completionCompleteRequestHandler() {
- return (exchange, params) -> {
- McpSchema.CompleteRequest request = parseCompletionParams(params);
-
- if (request.ref() == null) {
- return Mono.error(new McpError("ref must not be null"));
- }
-
- if (request.ref().type() == null) {
- return Mono.error(new McpError("type must not be null"));
- }
-
- String type = request.ref().type();
-
- // check if the referenced resource exists
- if (type.equals("ref/prompt") && request.ref() instanceof McpSchema.PromptReference promptReference) {
- McpServerFeatures.AsyncPromptSpecification prompt = this.prompts.get(promptReference.name());
- if (prompt == null) {
- return Mono.error(new McpError("Prompt not found: " + promptReference.name()));
- }
- }
-
- if (type.equals("ref/resource")
- && request.ref() instanceof McpSchema.ResourceReference resourceReference) {
- McpServerFeatures.AsyncResourceSpecification resource = this.resources.get(resourceReference.uri());
- if (resource == null) {
- return Mono.error(new McpError("Resource not found: " + resourceReference.uri()));
- }
- }
-
- McpServerFeatures.AsyncCompletionSpecification specification = this.completions.get(request.ref());
-
- if (specification == null) {
- return Mono.error(new McpError("AsyncCompletionSpecification not found: " + request.ref()));
- }
-
- return specification.completionHandler().apply(exchange, request);
- };
- }
-
- /**
- * Parses the raw JSON-RPC request parameters into a
- * {@link McpSchema.CompleteRequest} object.
- *
- * This method manually extracts the `ref` and `argument` fields from the input
- * map, determines the correct reference type (either prompt or resource), and
- * constructs a fully-typed {@code CompleteRequest} instance.
- * @param object the raw request parameters, expected to be a Map containing "ref"
- * and "argument" entries.
- * @return a {@link McpSchema.CompleteRequest} representing the structured
- * completion request.
- * @throws IllegalArgumentException if the "ref" type is not recognized.
- */
- @SuppressWarnings("unchecked")
- private McpSchema.CompleteRequest parseCompletionParams(Object object) {
- Map params = (Map) object;
- Map refMap = (Map) params.get("ref");
- Map argMap = (Map) params.get("argument");
-
- String refType = (String) refMap.get("type");
-
- McpSchema.CompleteReference ref = switch (refType) {
- case "ref/prompt" -> new McpSchema.PromptReference(refType, (String) refMap.get("name"));
- case "ref/resource" -> new McpSchema.ResourceReference(refType, (String) refMap.get("uri"));
- default -> throw new IllegalArgumentException("Invalid ref type: " + refType);
- };
-
- String argName = (String) argMap.get("name");
- String argValue = (String) argMap.get("value");
- McpSchema.CompleteRequest.CompleteArgument argument = new McpSchema.CompleteRequest.CompleteArgument(
- argName, argValue);
-
- return new McpSchema.CompleteRequest(ref, argument);
- }
-
- // ---------------------------------------
- // Sampling
- // ---------------------------------------
+ return specification.completionHandler().apply(exchange, request);
+ };
+ }
- @Override
- void setProtocolVersions(List protocolVersions) {
- this.protocolVersions = protocolVersions;
- }
+ /**
+ * Parses the raw JSON-RPC request parameters into a {@link McpSchema.CompleteRequest}
+ * object.
+ *
+ * This method manually extracts the `ref` and `argument` fields from the input map,
+ * determines the correct reference type (either prompt or resource), and constructs a
+ * fully-typed {@code CompleteRequest} instance.
+ * @param object the raw request parameters, expected to be a Map containing "ref" and
+ * "argument" entries.
+ * @return a {@link McpSchema.CompleteRequest} representing the structured completion
+ * request.
+ * @throws IllegalArgumentException if the "ref" type is not recognized.
+ */
+ @SuppressWarnings("unchecked")
+ private McpSchema.CompleteRequest parseCompletionParams(Object object) {
+ Map params = (Map) object;
+ Map refMap = (Map) params.get("ref");
+ Map argMap = (Map) params.get("argument");
+
+ String refType = (String) refMap.get("type");
+
+ McpSchema.CompleteReference ref = switch (refType) {
+ case "ref/prompt" -> new McpSchema.PromptReference(refType, (String) refMap.get("name"));
+ case "ref/resource" -> new McpSchema.ResourceReference(refType, (String) refMap.get("uri"));
+ default -> throw new IllegalArgumentException("Invalid ref type: " + refType);
+ };
+
+ String argName = (String) argMap.get("name");
+ String argValue = (String) argMap.get("value");
+ McpSchema.CompleteRequest.CompleteArgument argument = new McpSchema.CompleteRequest.CompleteArgument(argName,
+ argValue);
+
+ return new McpSchema.CompleteRequest(ref, argument);
+ }
+ /**
+ * This method is package-private and used for test only. Should not be called by user
+ * code.
+ * @param protocolVersions the Client supported protocol versions.
+ */
+ void setProtocolVersions(List protocolVersions) {
+ this.protocolVersions = protocolVersions;
}
}
diff --git a/mcp/src/main/java/io/modelcontextprotocol/server/McpServer.java b/mcp/src/main/java/io/modelcontextprotocol/server/McpServer.java
index 84089703..d6ec2cc3 100644
--- a/mcp/src/main/java/io/modelcontextprotocol/server/McpServer.java
+++ b/mcp/src/main/java/io/modelcontextprotocol/server/McpServer.java
@@ -19,6 +19,8 @@
import io.modelcontextprotocol.spec.McpSchema.ResourceTemplate;
import io.modelcontextprotocol.spec.McpServerTransportProvider;
import io.modelcontextprotocol.util.Assert;
+import io.modelcontextprotocol.util.DeafaultMcpUriTemplateManagerFactory;
+import io.modelcontextprotocol.util.McpUriTemplateManagerFactory;
import reactor.core.publisher.Mono;
/**
@@ -156,6 +158,8 @@ class AsyncSpecification {
private final McpServerTransportProvider transportProvider;
+ private McpUriTemplateManagerFactory uriTemplateManagerFactory = new DeafaultMcpUriTemplateManagerFactory();
+
private ObjectMapper objectMapper;
private McpSchema.Implementation serverInfo = DEFAULT_SERVER_INFO;
@@ -204,6 +208,19 @@ private AsyncSpecification(McpServerTransportProvider transportProvider) {
this.transportProvider = transportProvider;
}
+ /**
+ * Sets the URI template manager factory to use for creating URI templates. This
+ * allows for custom URI template parsing and variable extraction.
+ * @param uriTemplateManagerFactory The factory to use. Must not be null.
+ * @return This builder instance for method chaining
+ * @throws IllegalArgumentException if uriTemplateManagerFactory is null
+ */
+ public AsyncSpecification uriTemplateManagerFactory(McpUriTemplateManagerFactory uriTemplateManagerFactory) {
+ Assert.notNull(uriTemplateManagerFactory, "URI template manager factory must not be null");
+ this.uriTemplateManagerFactory = uriTemplateManagerFactory;
+ return this;
+ }
+
/**
* Sets the duration to wait for server responses before timing out requests. This
* timeout applies to all requests made through the client, including tool calls,
@@ -517,6 +534,36 @@ public AsyncSpecification prompts(McpServerFeatures.AsyncPromptSpecification...
return this;
}
+ /**
+ * Registers multiple completions with their handlers using a List. This method is
+ * useful when completions need to be added in bulk from a collection.
+ * @param completions List of completion specifications. Must not be null.
+ * @return This builder instance for method chaining
+ * @throws IllegalArgumentException if completions is null
+ */
+ public AsyncSpecification completions(List completions) {
+ Assert.notNull(completions, "Completions list must not be null");
+ for (McpServerFeatures.AsyncCompletionSpecification completion : completions) {
+ this.completions.put(completion.referenceKey(), completion);
+ }
+ return this;
+ }
+
+ /**
+ * Registers multiple completions with their handlers using varargs. This method
+ * is useful when completions are defined inline and added directly.
+ * @param completions Array of completion specifications. Must not be null.
+ * @return This builder instance for method chaining
+ * @throws IllegalArgumentException if completions is null
+ */
+ public AsyncSpecification completions(McpServerFeatures.AsyncCompletionSpecification... completions) {
+ Assert.notNull(completions, "Completions list must not be null");
+ for (McpServerFeatures.AsyncCompletionSpecification completion : completions) {
+ this.completions.put(completion.referenceKey(), completion);
+ }
+ return this;
+ }
+
/**
* Registers a consumer that will be notified when the list of roots changes. This
* is useful for updating resource availability dynamically, such as when new
@@ -587,7 +634,8 @@ public McpAsyncServer build() {
this.resources, this.resourceTemplates, this.prompts, this.completions, this.rootsChangeHandlers,
this.instructions);
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
- return new McpAsyncServer(this.transportProvider, mapper, features, this.requestTimeout);
+ return new McpAsyncServer(this.transportProvider, mapper, features, this.requestTimeout,
+ this.uriTemplateManagerFactory);
}
}
@@ -600,6 +648,8 @@ class SyncSpecification {
private static final McpSchema.Implementation DEFAULT_SERVER_INFO = new McpSchema.Implementation("mcp-server",
"1.0.0");
+ private McpUriTemplateManagerFactory uriTemplateManagerFactory = new DeafaultMcpUriTemplateManagerFactory();
+
private final McpServerTransportProvider transportProvider;
private ObjectMapper objectMapper;
@@ -650,6 +700,19 @@ private SyncSpecification(McpServerTransportProvider transportProvider) {
this.transportProvider = transportProvider;
}
+ /**
+ * Sets the URI template manager factory to use for creating URI templates. This
+ * allows for custom URI template parsing and variable extraction.
+ * @param uriTemplateManagerFactory The factory to use. Must not be null.
+ * @return This builder instance for method chaining
+ * @throws IllegalArgumentException if uriTemplateManagerFactory is null
+ */
+ public SyncSpecification uriTemplateManagerFactory(McpUriTemplateManagerFactory uriTemplateManagerFactory) {
+ Assert.notNull(uriTemplateManagerFactory, "URI template manager factory must not be null");
+ this.uriTemplateManagerFactory = uriTemplateManagerFactory;
+ return this;
+ }
+
/**
* Sets the duration to wait for server responses before timing out requests. This
* timeout applies to all requests made through the client, including tool calls,
@@ -1064,7 +1127,8 @@ public McpSyncServer build() {
this.rootsChangeHandlers, this.instructions);
McpServerFeatures.Async asyncFeatures = McpServerFeatures.Async.fromSync(syncFeatures);
var mapper = this.objectMapper != null ? this.objectMapper : new ObjectMapper();
- var asyncServer = new McpAsyncServer(this.transportProvider, mapper, asyncFeatures, this.requestTimeout);
+ var asyncServer = new McpAsyncServer(this.transportProvider, mapper, asyncFeatures, this.requestTimeout,
+ this.uriTemplateManagerFactory);
return new McpSyncServer(asyncServer);
}
diff --git a/mcp/src/main/java/io/modelcontextprotocol/util/DeafaultMcpUriTemplateManagerFactory.java b/mcp/src/main/java/io/modelcontextprotocol/util/DeafaultMcpUriTemplateManagerFactory.java
new file mode 100644
index 00000000..3870b76f
--- /dev/null
+++ b/mcp/src/main/java/io/modelcontextprotocol/util/DeafaultMcpUriTemplateManagerFactory.java
@@ -0,0 +1,23 @@
+/*
+* Copyright 2025 - 2025 the original author or authors.
+*/
+package io.modelcontextprotocol.util;
+
+/**
+ * @author Christian Tzolov
+ */
+public class DeafaultMcpUriTemplateManagerFactory implements McpUriTemplateManagerFactory {
+
+ /**
+ * Creates a new instance of {@link McpUriTemplateManager} with the specified URI
+ * template.
+ * @param uriTemplate The URI template to be used for variable extraction
+ * @return A new instance of {@link McpUriTemplateManager}
+ * @throws IllegalArgumentException if the URI template is null or empty
+ */
+ @Override
+ public McpUriTemplateManager create(String uriTemplate) {
+ return new DefaultMcpUriTemplateManager(uriTemplate);
+ }
+
+}
diff --git a/mcp/src/main/java/io/modelcontextprotocol/util/DefaultMcpUriTemplateManager.java b/mcp/src/main/java/io/modelcontextprotocol/util/DefaultMcpUriTemplateManager.java
new file mode 100644
index 00000000..b2e9a528
--- /dev/null
+++ b/mcp/src/main/java/io/modelcontextprotocol/util/DefaultMcpUriTemplateManager.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2025-2025 the original author or authors.
+ */
+
+package io.modelcontextprotocol.util;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Default implementation of the UriTemplateUtils interface.
+ *
+ * This class provides methods for extracting variables from URI templates and matching
+ * them against actual URIs.
+ *
+ * @author Christian Tzolov
+ */
+public class DefaultMcpUriTemplateManager implements McpUriTemplateManager {
+
+ /**
+ * Pattern to match URI variables in the format {variableName}.
+ */
+ private static final Pattern URI_VARIABLE_PATTERN = Pattern.compile("\\{([^/]+?)\\}");
+
+ private final String uriTemplate;
+
+ /**
+ * Constructor for DefaultMcpUriTemplateManager.
+ * @param uriTemplate The URI template to be used for variable extraction
+ */
+ public DefaultMcpUriTemplateManager(String uriTemplate) {
+ if (uriTemplate == null || uriTemplate.isEmpty()) {
+ throw new IllegalArgumentException("URI template must not be null or empty");
+ }
+ this.uriTemplate = uriTemplate;
+ }
+
+ /**
+ * Extract URI variable names from a URI template.
+ * @param uriTemplate The URI template containing variables in the format
+ * {variableName}
+ * @return A list of variable names extracted from the template
+ * @throws IllegalArgumentException if duplicate variable names are found
+ */
+ @Override
+ public List getVariableNames() {
+ if (uriTemplate == null || uriTemplate.isEmpty()) {
+ return List.of();
+ }
+
+ List variables = new ArrayList<>();
+ Matcher matcher = URI_VARIABLE_PATTERN.matcher(this.uriTemplate);
+
+ while (matcher.find()) {
+ String variableName = matcher.group(1);
+ if (variables.contains(variableName)) {
+ throw new IllegalArgumentException("Duplicate URI variable name in template: " + variableName);
+ }
+ variables.add(variableName);
+ }
+
+ return variables;
+ }
+
+ /**
+ * Extract URI variable values from the actual request URI.
+ *
+ * This method converts the URI template into a regex pattern, then uses that pattern
+ * to extract variable values from the request URI.
+ * @param requestUri The actual URI from the request
+ * @return A map of variable names to their values
+ * @throws IllegalArgumentException if the URI template is invalid or the request URI
+ * doesn't match the template pattern
+ */
+ @Override
+ public Map extractVariableValues(String requestUri) {
+ Map variableValues = new HashMap<>();
+ List uriVariables = this.getVariableNames();
+
+ if (requestUri == null || uriVariables.isEmpty()) {
+ return variableValues;
+ }
+
+ try {
+ // Create a regex pattern by replacing each {variableName} with a capturing
+ // group
+ StringBuilder patternBuilder = new StringBuilder("^");
+
+ // Find all variable placeholders and their positions
+ Matcher variableMatcher = URI_VARIABLE_PATTERN.matcher(uriTemplate);
+ int lastEnd = 0;
+
+ while (variableMatcher.find()) {
+ // Add the text between the last variable and this one, escaped for regex
+ String textBefore = uriTemplate.substring(lastEnd, variableMatcher.start());
+ patternBuilder.append(Pattern.quote(textBefore));
+
+ // Add a capturing group for the variable
+ patternBuilder.append("([^/]+)");
+
+ lastEnd = variableMatcher.end();
+ }
+
+ // Add any remaining text after the last variable
+ if (lastEnd < uriTemplate.length()) {
+ patternBuilder.append(Pattern.quote(uriTemplate.substring(lastEnd)));
+ }
+
+ patternBuilder.append("$");
+
+ // Compile the pattern and match against the request URI
+ Pattern pattern = Pattern.compile(patternBuilder.toString());
+ Matcher matcher = pattern.matcher(requestUri);
+
+ if (matcher.find() && matcher.groupCount() == uriVariables.size()) {
+ for (int i = 0; i < uriVariables.size(); i++) {
+ String value = matcher.group(i + 1);
+ if (value == null || value.isEmpty()) {
+ throw new IllegalArgumentException(
+ "Empty value for URI variable '" + uriVariables.get(i) + "' in URI: " + requestUri);
+ }
+ variableValues.put(uriVariables.get(i), value);
+ }
+ }
+ }
+ catch (Exception e) {
+ throw new IllegalArgumentException("Error parsing URI template: " + uriTemplate + " for URI: " + requestUri,
+ e);
+ }
+
+ return variableValues;
+ }
+
+ /**
+ * Check if a URI matches the uriTemplate with variables.
+ * @param uri The URI to check
+ * @return true if the URI matches the pattern, false otherwise
+ */
+ @Override
+ public boolean matches(String uri) {
+ // If the uriTemplate doesn't contain variables, do a direct comparison
+ if (!this.isUriTemplate(this.uriTemplate)) {
+ return uri.equals(this.uriTemplate);
+ }
+
+ // Convert the pattern to a regex
+ String regex = this.uriTemplate.replaceAll("\\{[^/]+?\\}", "([^/]+?)");
+ regex = regex.replace("/", "\\/");
+
+ // Check if the URI matches the regex
+ return Pattern.compile(regex).matcher(uri).matches();
+ }
+
+ @Override
+ public boolean isUriTemplate(String uri) {
+ return URI_VARIABLE_PATTERN.matcher(uri).find();
+ }
+
+}
diff --git a/mcp/src/main/java/io/modelcontextprotocol/util/McpUriTemplateManager.java b/mcp/src/main/java/io/modelcontextprotocol/util/McpUriTemplateManager.java
new file mode 100644
index 00000000..19569e49
--- /dev/null
+++ b/mcp/src/main/java/io/modelcontextprotocol/util/McpUriTemplateManager.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2025-2025 the original author or authors.
+ */
+
+package io.modelcontextprotocol.util;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Interface for working with URI templates.
+ *
+ * This interface provides methods for extracting variables from URI templates and
+ * matching them against actual URIs.
+ *
+ * @author Christian Tzolov
+ */
+public interface McpUriTemplateManager {
+
+ /**
+ * Extract URI variable names from this URI template.
+ * @return A list of variable names extracted from the template
+ * @throws IllegalArgumentException if duplicate variable names are found
+ */
+ List getVariableNames();
+
+ /**
+ * Extract URI variable values from the actual request URI.
+ *
+ * This method converts the URI template into a regex pattern, then uses that pattern
+ * to extract variable values from the request URI.
+ * @param uri The actual URI from the request
+ * @return A map of variable names to their values
+ * @throws IllegalArgumentException if the URI template is invalid or the request URI
+ * doesn't match the template pattern
+ */
+ Map extractVariableValues(String uri);
+
+ /**
+ * Indicate whether the given URI matches this template.
+ * @param uri the URI to match to
+ * @return {@code true} if it matches; {@code false} otherwise
+ */
+ boolean matches(String uri);
+
+ /**
+ * Check if the given URI is a URI template.
+ * @return Returns true if the URI contains variables in the format {variableName}
+ */
+ public boolean isUriTemplate(String uri);
+
+}
diff --git a/mcp/src/main/java/io/modelcontextprotocol/util/McpUriTemplateManagerFactory.java b/mcp/src/main/java/io/modelcontextprotocol/util/McpUriTemplateManagerFactory.java
new file mode 100644
index 00000000..9644f9a6
--- /dev/null
+++ b/mcp/src/main/java/io/modelcontextprotocol/util/McpUriTemplateManagerFactory.java
@@ -0,0 +1,22 @@
+/*
+* Copyright 2025 - 2025 the original author or authors.
+*/
+package io.modelcontextprotocol.util;
+
+/**
+ * Factory interface for creating instances of {@link McpUriTemplateManager}.
+ *
+ * @author Christian Tzolov
+ */
+public interface McpUriTemplateManagerFactory {
+
+ /**
+ * Creates a new instance of {@link McpUriTemplateManager} with the specified URI
+ * template.
+ * @param uriTemplate The URI template to be used for variable extraction
+ * @return A new instance of {@link McpUriTemplateManager}
+ * @throws IllegalArgumentException if the URI template is null or empty
+ */
+ McpUriTemplateManager create(String uriTemplate);
+
+}
diff --git a/mcp/src/test/java/io/modelcontextprotocol/McpUriTemplateManagerTests.java b/mcp/src/test/java/io/modelcontextprotocol/McpUriTemplateManagerTests.java
new file mode 100644
index 00000000..6f041daa
--- /dev/null
+++ b/mcp/src/test/java/io/modelcontextprotocol/McpUriTemplateManagerTests.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2025-2025 the original author or authors.
+ */
+
+package io.modelcontextprotocol;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import java.util.Map;
+
+import io.modelcontextprotocol.util.DeafaultMcpUriTemplateManagerFactory;
+import io.modelcontextprotocol.util.McpUriTemplateManager;
+import io.modelcontextprotocol.util.McpUriTemplateManagerFactory;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for {@link McpUriTemplateManager} and its implementations.
+ *
+ * @author Christian Tzolov
+ */
+public class McpUriTemplateManagerTests {
+
+ private McpUriTemplateManagerFactory uriTemplateFactory;
+
+ @BeforeEach
+ void setUp() {
+ this.uriTemplateFactory = new DeafaultMcpUriTemplateManagerFactory();
+ }
+
+ @Test
+ void shouldExtractVariableNamesFromTemplate() {
+ List variables = this.uriTemplateFactory.create("/api/users/{userId}/posts/{postId}")
+ .getVariableNames();
+ assertEquals(2, variables.size());
+ assertEquals("userId", variables.get(0));
+ assertEquals("postId", variables.get(1));
+ }
+
+ @Test
+ void shouldReturnEmptyListWhenTemplateHasNoVariables() {
+ List variables = this.uriTemplateFactory.create("/api/users/all").getVariableNames();
+ assertEquals(0, variables.size());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenExtractingVariablesFromNullTemplate() {
+ assertThrows(IllegalArgumentException.class, () -> this.uriTemplateFactory.create(null).getVariableNames());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenExtractingVariablesFromEmptyTemplate() {
+ assertThrows(IllegalArgumentException.class, () -> this.uriTemplateFactory.create("").getVariableNames());
+ }
+
+ @Test
+ void shouldThrowExceptionWhenTemplateContainsDuplicateVariables() {
+ assertThrows(IllegalArgumentException.class,
+ () -> this.uriTemplateFactory.create("/api/users/{userId}/posts/{userId}").getVariableNames());
+ }
+
+ @Test
+ void shouldExtractVariableValuesFromRequestUri() {
+ Map values = this.uriTemplateFactory.create("/api/users/{userId}/posts/{postId}")
+ .extractVariableValues("/api/users/123/posts/456");
+ assertEquals(2, values.size());
+ assertEquals("123", values.get("userId"));
+ assertEquals("456", values.get("postId"));
+ }
+
+ @Test
+ void shouldReturnEmptyMapWhenTemplateHasNoVariables() {
+ Map values = this.uriTemplateFactory.create("/api/users/all")
+ .extractVariableValues("/api/users/all");
+ assertEquals(0, values.size());
+ }
+
+ @Test
+ void shouldReturnEmptyMapWhenRequestUriIsNull() {
+ Map values = this.uriTemplateFactory.create("/api/users/{userId}/posts/{postId}")
+ .extractVariableValues(null);
+ assertEquals(0, values.size());
+ }
+
+ @Test
+ void shouldMatchUriAgainstTemplatePattern() {
+ var uriTemplateManager = this.uriTemplateFactory.create("/api/users/{userId}/posts/{postId}");
+
+ assertTrue(uriTemplateManager.matches("/api/users/123/posts/456"));
+ assertFalse(uriTemplateManager.matches("/api/users/123/comments/456"));
+ }
+
+}
diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpAsyncClientTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpAsyncClientTests.java
index c3908013..8c0069d6 100644
--- a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpAsyncClientTests.java
+++ b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpAsyncClientTests.java
@@ -25,12 +25,12 @@ protected McpClientTransport createMcpTransport() {
ServerParameters stdioParams;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
stdioParams = ServerParameters.builder("cmd.exe")
- .args("/c", "npx.cmd", "-y", "@modelcontextprotocol/server-everything", "dir")
+ .args("/c", "npx.cmd", "-y", "@modelcontextprotocol/server-everything", "stdio")
.build();
}
else {
stdioParams = ServerParameters.builder("npx")
- .args("-y", "@modelcontextprotocol/server-everything", "dir")
+ .args("-y", "@modelcontextprotocol/server-everything", "stdio")
.build();
}
return new StdioClientTransport(stdioParams);
diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java
index 8e75c4a3..706aa9b2 100644
--- a/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java
+++ b/mcp/src/test/java/io/modelcontextprotocol/client/StdioMcpSyncClientTests.java
@@ -33,12 +33,12 @@ protected McpClientTransport createMcpTransport() {
ServerParameters stdioParams;
if (System.getProperty("os.name").toLowerCase().contains("win")) {
stdioParams = ServerParameters.builder("cmd.exe")
- .args("/c", "npx.cmd", "-y", "@modelcontextprotocol/server-everything", "dir")
+ .args("/c", "npx.cmd", "-y", "@modelcontextprotocol/server-everything", "stdio")
.build();
}
else {
stdioParams = ServerParameters.builder("npx")
- .args("-y", "@modelcontextprotocol/server-everything", "dir")
+ .args("-y", "@modelcontextprotocol/server-everything", "stdio")
.build();
}
return new StdioClientTransport(stdioParams);
diff --git a/pom.xml b/pom.xml
index 9be256cc..c2327ee8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
io.modelcontextprotocol.sdk
mcp-parent
- 0.10.0-SNAPSHOT
+ 0.11.0-SNAPSHOT
pom
https://github.com/modelcontextprotocol/java-sdk
@@ -57,6 +57,7 @@
17
17
17
+
3.26.3
5.10.2
@@ -163,13 +164,23 @@
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+
+ properties
+
+
+
+
org.apache.maven.plugins
maven-surefire-plugin
${maven-surefire-plugin.version}
- ${surefireArgLine}
-
+ ${surefireArgLine} -javaagent:${org.mockito:mockito-core:jar}
false
false