From 5e035ea2555f561ce5e840d5fa07f6aa8f834715 Mon Sep 17 00:00:00 2001 From: Christian Tzolov Date: Mon, 4 Aug 2025 12:07:31 +0100 Subject: [PATCH] fix: add backward compatibility for MCP servers returning older protocol versions - Add ProtocolVersions interface with version constants - Change protocolVersion() to protocolVersions() returning List - Streamable HTTP clients now support both 2024-11-05 and 2025-03-26 - Fixes compatibility with MCP servers that return 2024-11-05 instead of 2025-03-26 Resolves #436 Related to #438 Signed-off-by: Christian Tzolov --- .../WebClientStreamableHttpTransport.java | 7 +++--- .../transport/WebFluxSseClientTransport.java | 8 ++++--- .../WebFluxSseServerTransportProvider.java | 6 +++-- ...FluxStreamableServerTransportProvider.java | 5 ++-- .../WebMvcSseServerTransportProvider.java | 6 +++-- ...bMvcStreamableServerTransportProvider.java | 5 ++-- .../client/LifecycleInitializer.java | 3 ++- .../client/McpAsyncClient.java | 6 ++--- .../HttpClientSseClientTransport.java | 8 ++++--- .../HttpClientStreamableHttpTransport.java | 7 +++--- .../server/McpAsyncServer.java | 4 ++-- .../server/McpStatelessAsyncServer.java | 2 +- ...HttpServletSseServerTransportProvider.java | 6 +++-- ...vletStreamableServerTransportProvider.java | 5 ++-- .../StdioServerTransportProvider.java | 6 +++-- .../modelcontextprotocol/spec/McpSchema.java | 2 +- .../spec/McpServerTransportProviderBase.java | 5 ++-- .../spec/McpStatelessServerTransport.java | 6 +++-- .../spec/McpTransport.java | 6 +++-- .../spec/ProtocolVersions.java | 23 +++++++++++++++++++ .../MockMcpClientTransport.java | 4 ++-- .../McpAsyncClientResponseHandlerTests.java | 2 +- .../client/McpAsyncClientTests.java | 6 +++-- .../client/McpClientProtocolVersionTests.java | 8 ++++--- .../server/McpServerProtocolVersionTests.java | 7 ++++-- .../spec/McpSchemaTests.java | 8 +++---- 26 files changed, 107 insertions(+), 54 deletions(-) create mode 100644 mcp/src/main/java/io/modelcontextprotocol/spec/ProtocolVersions.java diff --git a/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/client/transport/WebClientStreamableHttpTransport.java b/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/client/transport/WebClientStreamableHttpTransport.java index b7b5446..4758fd2 100644 --- a/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/client/transport/WebClientStreamableHttpTransport.java +++ b/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/client/transport/WebClientStreamableHttpTransport.java @@ -34,6 +34,7 @@ import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpTransportSession; import io.modelcontextprotocol.spec.McpTransportSessionNotFoundException; import io.modelcontextprotocol.spec.McpTransportStream; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.util.Assert; import io.modelcontextprotocol.util.Utils; import reactor.core.Disposable; @@ -71,7 +72,7 @@ public class WebClientStreamableHttpTransport implements McpClientTransport { private static final Logger logger = LoggerFactory.getLogger(WebClientStreamableHttpTransport.class); - private static final String MCP_PROTOCOL_VERSION = "2025-03-26"; + private static final String MCP_PROTOCOL_VERSION = ProtocolVersions.MCP_2025_03_26; private static final String DEFAULT_ENDPOINT = "/mcp"; @@ -111,8 +112,8 @@ public class WebClientStreamableHttpTransport implements McpClientTransport { } @Override - public String protocolVersion() { - return MCP_PROTOCOL_VERSION; + public List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05, ProtocolVersions.MCP_2025_03_26); } /** diff --git a/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/client/transport/WebFluxSseClientTransport.java b/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/client/transport/WebFluxSseClientTransport.java index f122c8f..75caebe 100644 --- a/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/client/transport/WebFluxSseClientTransport.java +++ b/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/client/transport/WebFluxSseClientTransport.java @@ -5,6 +5,7 @@ package io.modelcontextprotocol.client.transport; import java.io.IOException; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.Function; @@ -16,6 +17,7 @@ import io.modelcontextprotocol.spec.McpClientTransport; import io.modelcontextprotocol.spec.McpError; import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpSchema.JSONRPCMessage; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.util.Assert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,7 +67,7 @@ public class WebFluxSseClientTransport implements McpClientTransport { private static final Logger logger = LoggerFactory.getLogger(WebFluxSseClientTransport.class); - private static final String MCP_PROTOCOL_VERSION = "2024-11-05"; + private static final String MCP_PROTOCOL_VERSION = ProtocolVersions.MCP_2024_11_05; /** * Event type for JSON-RPC messages received through the SSE connection. The server @@ -172,8 +174,8 @@ public class WebFluxSseClientTransport implements McpClientTransport { } @Override - public String protocolVersion() { - return MCP_PROTOCOL_VERSION; + public List protocolVersions() { + return List.of(MCP_PROTOCOL_VERSION); } /** diff --git a/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxSseServerTransportProvider.java b/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxSseServerTransportProvider.java index c2c2c2e..aaf7bab 100644 --- a/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxSseServerTransportProvider.java +++ b/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxSseServerTransportProvider.java @@ -6,6 +6,7 @@ package io.modelcontextprotocol.server.transport; import java.io.IOException; import java.time.Duration; +import java.util.List; import java.util.concurrent.ConcurrentHashMap; import com.fasterxml.jackson.core.type.TypeReference; @@ -15,6 +16,7 @@ import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpServerSession; import io.modelcontextprotocol.spec.McpServerTransport; import io.modelcontextprotocol.spec.McpServerTransportProvider; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.util.Assert; import io.modelcontextprotocol.util.KeepAliveScheduler; @@ -219,8 +221,8 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv } @Override - public String protocolVersion() { - return "2024-11-05"; + public List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05); } @Override diff --git a/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxStreamableServerTransportProvider.java b/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxStreamableServerTransportProvider.java index b9111d6..f3f6c2c 100644 --- a/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxStreamableServerTransportProvider.java +++ b/mcp-spring/mcp-spring-webflux/src/main/java/io/modelcontextprotocol/server/transport/WebFluxStreamableServerTransportProvider.java @@ -14,6 +14,7 @@ import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpStreamableServerSession; import io.modelcontextprotocol.spec.McpStreamableServerTransport; import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.server.McpTransportContext; import io.modelcontextprotocol.util.Assert; import io.modelcontextprotocol.util.KeepAliveScheduler; @@ -96,8 +97,8 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe } @Override - public String protocolVersion() { - return "2025-03-26"; + public List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05, ProtocolVersions.MCP_2025_03_26); } @Override diff --git a/mcp-spring/mcp-spring-webmvc/src/main/java/io/modelcontextprotocol/server/transport/WebMvcSseServerTransportProvider.java b/mcp-spring/mcp-spring-webmvc/src/main/java/io/modelcontextprotocol/server/transport/WebMvcSseServerTransportProvider.java index a389800..ff452ca 100644 --- a/mcp-spring/mcp-spring-webmvc/src/main/java/io/modelcontextprotocol/server/transport/WebMvcSseServerTransportProvider.java +++ b/mcp-spring/mcp-spring-webmvc/src/main/java/io/modelcontextprotocol/server/transport/WebMvcSseServerTransportProvider.java @@ -6,6 +6,7 @@ package io.modelcontextprotocol.server.transport; import java.io.IOException; import java.time.Duration; +import java.util.List; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; @@ -16,6 +17,7 @@ import io.modelcontextprotocol.spec.McpError; import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpServerTransport; import io.modelcontextprotocol.spec.McpServerTransportProvider; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.spec.McpServerSession; import io.modelcontextprotocol.util.Assert; import io.modelcontextprotocol.util.KeepAliveScheduler; @@ -210,8 +212,8 @@ public class WebMvcSseServerTransportProvider implements McpServerTransportProvi } @Override - public String protocolVersion() { - return "2024-11-05"; + public List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05); } @Override diff --git a/mcp-spring/mcp-spring-webmvc/src/main/java/io/modelcontextprotocol/server/transport/WebMvcStreamableServerTransportProvider.java b/mcp-spring/mcp-spring-webmvc/src/main/java/io/modelcontextprotocol/server/transport/WebMvcStreamableServerTransportProvider.java index 4a2117c..fa51a01 100644 --- a/mcp-spring/mcp-spring-webmvc/src/main/java/io/modelcontextprotocol/server/transport/WebMvcStreamableServerTransportProvider.java +++ b/mcp-spring/mcp-spring-webmvc/src/main/java/io/modelcontextprotocol/server/transport/WebMvcStreamableServerTransportProvider.java @@ -32,6 +32,7 @@ import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpStreamableServerSession; import io.modelcontextprotocol.spec.McpStreamableServerTransport; import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.util.Assert; import io.modelcontextprotocol.util.KeepAliveScheduler; import reactor.core.publisher.Flux; @@ -142,8 +143,8 @@ public class WebMvcStreamableServerTransportProvider implements McpStreamableSer } @Override - public String protocolVersion() { - return "2025-03-26"; + public List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05, ProtocolVersions.MCP_2025_03_26); } @Override diff --git a/mcp/src/main/java/io/modelcontextprotocol/client/LifecycleInitializer.java b/mcp/src/main/java/io/modelcontextprotocol/client/LifecycleInitializer.java index 4eb94da..2e0b517 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/client/LifecycleInitializer.java +++ b/mcp/src/main/java/io/modelcontextprotocol/client/LifecycleInitializer.java @@ -290,7 +290,8 @@ class LifecycleInitializer { .timeout(this.initializationTimeout) .onErrorResume(ex -> { logger.warn("Failed to initialize", ex); - return Mono.error(new McpError("Client failed to initialize " + actionName)); + return Mono.error( + new McpError("Client failed to initialize " + actionName + " due to: " + ex.getMessage())); }) .flatMap(operation); }); diff --git a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java index 27d9d2e..0f2ee19 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java +++ b/mcp/src/main/java/io/modelcontextprotocol/client/McpAsyncClient.java @@ -272,9 +272,9 @@ public class McpAsyncClient { notificationHandlers.put(McpSchema.METHOD_NOTIFICATION_PROGRESS, asyncProgressNotificationHandler(progressConsumersFinal)); - this.initializer = new LifecycleInitializer(clientCapabilities, clientInfo, - List.of(transport.protocolVersion()), initializationTimeout, ctx -> new McpClientSession(requestTimeout, - transport, requestHandlers, notificationHandlers, con -> con.contextWrite(ctx))); + this.initializer = new LifecycleInitializer(clientCapabilities, clientInfo, transport.protocolVersions(), + initializationTimeout, ctx -> new McpClientSession(requestTimeout, transport, requestHandlers, + notificationHandlers, con -> con.contextWrite(ctx))); this.transport.setExceptionHandler(this.initializer::handleException); } diff --git a/mcp/src/main/java/io/modelcontextprotocol/client/transport/HttpClientSseClientTransport.java b/mcp/src/main/java/io/modelcontextprotocol/client/transport/HttpClientSseClientTransport.java index 62c34fb..473f71f 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/client/transport/HttpClientSseClientTransport.java +++ b/mcp/src/main/java/io/modelcontextprotocol/client/transport/HttpClientSseClientTransport.java @@ -10,6 +10,7 @@ import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -25,6 +26,7 @@ import io.modelcontextprotocol.client.transport.ResponseSubscribers.ResponseEven import io.modelcontextprotocol.spec.McpClientTransport; import io.modelcontextprotocol.spec.McpError; import io.modelcontextprotocol.spec.McpSchema; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.spec.McpSchema.JSONRPCMessage; import io.modelcontextprotocol.util.Assert; import io.modelcontextprotocol.util.Utils; @@ -62,7 +64,7 @@ import reactor.core.publisher.Sinks; */ public class HttpClientSseClientTransport implements McpClientTransport { - private static final String MCP_PROTOCOL_VERSION = "2024-11-05"; + private static final String MCP_PROTOCOL_VERSION = ProtocolVersions.MCP_2024_11_05; private static final String MCP_PROTOCOL_VERSION_HEADER_NAME = "MCP-Protocol-Version"; @@ -217,8 +219,8 @@ public class HttpClientSseClientTransport implements McpClientTransport { } @Override - public String protocolVersion() { - return MCP_PROTOCOL_VERSION; + public List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05); } /** diff --git a/mcp/src/main/java/io/modelcontextprotocol/client/transport/HttpClientStreamableHttpTransport.java b/mcp/src/main/java/io/modelcontextprotocol/client/transport/HttpClientStreamableHttpTransport.java index dadb09a..3cfa735 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/client/transport/HttpClientStreamableHttpTransport.java +++ b/mcp/src/main/java/io/modelcontextprotocol/client/transport/HttpClientStreamableHttpTransport.java @@ -35,6 +35,7 @@ import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpTransportSession; import io.modelcontextprotocol.spec.McpTransportSessionNotFoundException; import io.modelcontextprotocol.spec.McpTransportStream; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.util.Assert; import io.modelcontextprotocol.util.Utils; import reactor.core.Disposable; @@ -73,7 +74,7 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport { private static final Logger logger = LoggerFactory.getLogger(HttpClientStreamableHttpTransport.class); - private static final String MCP_PROTOCOL_VERSION = "2025-03-26"; + private static final String MCP_PROTOCOL_VERSION = ProtocolVersions.MCP_2025_03_26; private static final String DEFAULT_ENDPOINT = "/mcp"; @@ -135,8 +136,8 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport { } @Override - public String protocolVersion() { - return MCP_PROTOCOL_VERSION; + public List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05, ProtocolVersions.MCP_2025_03_26); } public static Builder builder(String baseUri) { diff --git a/mcp/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java b/mcp/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java index 9605fb3..5b5e838 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java +++ b/mcp/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java @@ -145,7 +145,7 @@ public class McpAsyncServer { Map> requestHandlers = prepareRequestHandlers(); Map notificationHandlers = prepareNotificationHandlers(features); - this.protocolVersions = List.of(mcpTransportProvider.protocolVersion()); + this.protocolVersions = mcpTransportProvider.protocolVersions(); mcpTransportProvider.setSessionFactory(transport -> new McpServerSession(UUID.randomUUID().toString(), requestTimeout, transport, this::asyncInitializeRequestHandler, requestHandlers, notificationHandlers)); @@ -170,7 +170,7 @@ public class McpAsyncServer { Map> requestHandlers = prepareRequestHandlers(); Map notificationHandlers = prepareNotificationHandlers(features); - this.protocolVersions = List.of(mcpTransportProvider.protocolVersion()); + this.protocolVersions = mcpTransportProvider.protocolVersions(); mcpTransportProvider.setSessionFactory(new DefaultMcpStreamableServerSessionFactory(requestTimeout, this::asyncInitializeRequestHandler, requestHandlers, notificationHandlers)); diff --git a/mcp/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java b/mcp/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java index 565c53f..41e0e95 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java +++ b/mcp/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java @@ -118,7 +118,7 @@ public class McpStatelessAsyncServer { requestHandlers.put(McpSchema.METHOD_COMPLETION_COMPLETE, completionCompleteRequestHandler()); } - this.protocolVersions = List.of(mcpTransport.protocolVersion()); + this.protocolVersions = new ArrayList<>(mcpTransport.protocolVersions()); McpStatelessServerHandler handler = new DefaultMcpStatelessServerHandler(requestHandlers, Map.of()); mcpTransport.setMcpHandler(handler); diff --git a/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletSseServerTransportProvider.java b/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletSseServerTransportProvider.java index 40d2932..ceeea31 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletSseServerTransportProvider.java +++ b/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletSseServerTransportProvider.java @@ -8,6 +8,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.time.Duration; +import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -20,6 +21,7 @@ import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpServerSession; import io.modelcontextprotocol.spec.McpServerTransport; import io.modelcontextprotocol.spec.McpServerTransportProvider; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.util.Assert; import io.modelcontextprotocol.util.KeepAliveScheduler; import jakarta.servlet.AsyncContext; @@ -180,8 +182,8 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement } @Override - public String protocolVersion() { - return "2024-11-05"; + public List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05); } /** diff --git a/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletStreamableServerTransportProvider.java b/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletStreamableServerTransportProvider.java index 6805bf1..8b95ec6 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletStreamableServerTransportProvider.java +++ b/mcp/src/main/java/io/modelcontextprotocol/server/transport/HttpServletStreamableServerTransportProvider.java @@ -28,6 +28,7 @@ import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpStreamableServerSession; import io.modelcontextprotocol.spec.McpStreamableServerTransport; import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.util.Assert; import io.modelcontextprotocol.util.KeepAliveScheduler; import jakarta.servlet.AsyncContext; @@ -155,8 +156,8 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet } @Override - public String protocolVersion() { - return "2025-03-26"; + public List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05, ProtocolVersions.MCP_2025_03_26); } @Override diff --git a/mcp/src/main/java/io/modelcontextprotocol/server/transport/StdioServerTransportProvider.java b/mcp/src/main/java/io/modelcontextprotocol/server/transport/StdioServerTransportProvider.java index d2943b3..af602f6 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/server/transport/StdioServerTransportProvider.java +++ b/mcp/src/main/java/io/modelcontextprotocol/server/transport/StdioServerTransportProvider.java @@ -10,6 +10,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.charset.StandardCharsets; +import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; @@ -22,6 +23,7 @@ import io.modelcontextprotocol.spec.McpSchema.JSONRPCMessage; import io.modelcontextprotocol.spec.McpServerSession; import io.modelcontextprotocol.spec.McpServerTransport; import io.modelcontextprotocol.spec.McpServerTransportProvider; +import io.modelcontextprotocol.spec.ProtocolVersions; import io.modelcontextprotocol.util.Assert; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,8 +91,8 @@ public class StdioServerTransportProvider implements McpServerTransportProvider } @Override - public String protocolVersion() { - return "2024-11-05"; + public List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05); } @Override diff --git a/mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java b/mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java index fb4baab..af0f55a 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java +++ b/mcp/src/main/java/io/modelcontextprotocol/spec/McpSchema.java @@ -45,7 +45,7 @@ public final class McpSchema { } @Deprecated - public static final String LATEST_PROTOCOL_VERSION = "2025-03-26"; + public static final String LATEST_PROTOCOL_VERSION = ProtocolVersions.MCP_2025_03_26; public static final String JSONRPC_VERSION = "2.0"; diff --git a/mcp/src/main/java/io/modelcontextprotocol/spec/McpServerTransportProviderBase.java b/mcp/src/main/java/io/modelcontextprotocol/spec/McpServerTransportProviderBase.java index d1b252a..acb1eca 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/spec/McpServerTransportProviderBase.java +++ b/mcp/src/main/java/io/modelcontextprotocol/spec/McpServerTransportProviderBase.java @@ -4,6 +4,7 @@ package io.modelcontextprotocol.spec; +import java.util.List; import java.util.Map; import reactor.core.publisher.Mono; @@ -63,8 +64,8 @@ public interface McpServerTransportProviderBase { * Returns the protocol version supported by this transport provider. * @return the protocol version as a string */ - default String protocolVersion() { - return "2024-11-05"; + default List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05); } } diff --git a/mcp/src/main/java/io/modelcontextprotocol/spec/McpStatelessServerTransport.java b/mcp/src/main/java/io/modelcontextprotocol/spec/McpStatelessServerTransport.java index 14ed544..c1234b1 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/spec/McpStatelessServerTransport.java +++ b/mcp/src/main/java/io/modelcontextprotocol/spec/McpStatelessServerTransport.java @@ -4,6 +4,8 @@ package io.modelcontextprotocol.spec; +import java.util.List; + import io.modelcontextprotocol.server.McpStatelessServerHandler; import reactor.core.publisher.Mono; @@ -26,8 +28,8 @@ public interface McpStatelessServerTransport { */ Mono closeGracefully(); - default String protocolVersion() { - return "2025-03-26"; + default List protocolVersions() { + return List.of(ProtocolVersions.MCP_2025_03_26); } } diff --git a/mcp/src/main/java/io/modelcontextprotocol/spec/McpTransport.java b/mcp/src/main/java/io/modelcontextprotocol/spec/McpTransport.java index 49c4850..1922548 100644 --- a/mcp/src/main/java/io/modelcontextprotocol/spec/McpTransport.java +++ b/mcp/src/main/java/io/modelcontextprotocol/spec/McpTransport.java @@ -4,6 +4,8 @@ package io.modelcontextprotocol.spec; +import java.util.List; + import com.fasterxml.jackson.core.type.TypeReference; import io.modelcontextprotocol.spec.McpSchema.JSONRPCMessage; import reactor.core.publisher.Mono; @@ -77,8 +79,8 @@ public interface McpTransport { */ T unmarshalFrom(Object data, TypeReference typeRef); - default String protocolVersion() { - return "2024-11-05"; + default List protocolVersions() { + return List.of(ProtocolVersions.MCP_2024_11_05); } } diff --git a/mcp/src/main/java/io/modelcontextprotocol/spec/ProtocolVersions.java b/mcp/src/main/java/io/modelcontextprotocol/spec/ProtocolVersions.java new file mode 100644 index 0000000..d8cb913 --- /dev/null +++ b/mcp/src/main/java/io/modelcontextprotocol/spec/ProtocolVersions.java @@ -0,0 +1,23 @@ +package io.modelcontextprotocol.spec; + +public interface ProtocolVersions { + + /** + * MCP protocol version for 2024-11-05. + * https://modelcontextprotocol.io/specification/2024-11-05 + */ + String MCP_2024_11_05 = "2024-11-05"; + + /** + * MCP protocol version for 2025-03-26. + * https://modelcontextprotocol.io/specification/2025-03-26 + */ + String MCP_2025_03_26 = "2025-03-26"; + + /** + * MCP protocol version for 2025-06-18. + * https://modelcontextprotocol.io/specification/2025-06-18 + */ + String MCP_2025_06_18 = "2025-06-18"; + +} diff --git a/mcp/src/test/java/io/modelcontextprotocol/MockMcpClientTransport.java b/mcp/src/test/java/io/modelcontextprotocol/MockMcpClientTransport.java index b531d57..b1113a6 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/MockMcpClientTransport.java +++ b/mcp/src/test/java/io/modelcontextprotocol/MockMcpClientTransport.java @@ -45,8 +45,8 @@ public class MockMcpClientTransport implements McpClientTransport { } @Override - public String protocolVersion() { - return protocolVersion; + public List protocolVersions() { + return List.of(protocolVersion); } public void simulateIncomingMessage(McpSchema.JSONRPCMessage message) { diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java index 11bd2e4..b2fd7fb 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientResponseHandlerTests.java @@ -79,7 +79,7 @@ class McpAsyncClientResponseHandlerTests { // Verify initialization result assertThat(result).isNotNull(); - assertThat(result.protocolVersion()).isEqualTo(transport.protocolVersion()); + assertThat(result.protocolVersion()).isEqualTo(transport.protocolVersions().get(0)); assertThat(result.capabilities()).isEqualTo(serverCapabilities); assertThat(result.serverInfo()).isEqualTo(serverInfo); assertThat(result.instructions()).isEqualTo("Test instructions"); diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientTests.java index 2c0331f..ae33898 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/client/McpAsyncClientTests.java @@ -8,6 +8,8 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import io.modelcontextprotocol.spec.McpClientTransport; import io.modelcontextprotocol.spec.McpSchema; +import io.modelcontextprotocol.spec.ProtocolVersions; + import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; @@ -24,8 +26,8 @@ class McpAsyncClientTests { public static final McpSchema.ServerCapabilities MOCK_SERVER_CAPABILITIES = McpSchema.ServerCapabilities.builder() .build(); - public static final McpSchema.InitializeResult MOCK_INIT_RESULT = new McpSchema.InitializeResult("2024-11-05", - MOCK_SERVER_CAPABILITIES, MOCK_SERVER_INFO, "Test instructions"); + public static final McpSchema.InitializeResult MOCK_INIT_RESULT = new McpSchema.InitializeResult( + ProtocolVersions.MCP_2024_11_05, MOCK_SERVER_CAPABILITIES, MOCK_SERVER_INFO, "Test instructions"); private static final String CONTEXT_KEY = "context.key"; diff --git a/mcp/src/test/java/io/modelcontextprotocol/client/McpClientProtocolVersionTests.java b/mcp/src/test/java/io/modelcontextprotocol/client/McpClientProtocolVersionTests.java index 2d41fc5..3621698 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/client/McpClientProtocolVersionTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/client/McpClientProtocolVersionTests.java @@ -37,18 +37,20 @@ class McpClientProtocolVersionTests { try { Mono initializeResultMono = client.initialize(); + String protocolVersion = transport.protocolVersions().get(transport.protocolVersions().size() - 1); + StepVerifier.create(initializeResultMono).then(() -> { McpSchema.JSONRPCRequest request = transport.getLastSentMessageAsRequest(); assertThat(request.params()).isInstanceOf(McpSchema.InitializeRequest.class); McpSchema.InitializeRequest initRequest = (McpSchema.InitializeRequest) request.params(); - assertThat(initRequest.protocolVersion()).isEqualTo(transport.protocolVersion()); + assertThat(initRequest.protocolVersion()).isEqualTo(transport.protocolVersions().get(0)); transport.simulateIncomingMessage(new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), - new McpSchema.InitializeResult(transport.protocolVersion(), null, + new McpSchema.InitializeResult(protocolVersion, null, new McpSchema.Implementation("test-server", "1.0.0"), null), null)); }).assertNext(result -> { - assertThat(result.protocolVersion()).isEqualTo(transport.protocolVersion()); + assertThat(result.protocolVersion()).isEqualTo(protocolVersion); }).verifyComplete(); } diff --git a/mcp/src/test/java/io/modelcontextprotocol/server/McpServerProtocolVersionTests.java b/mcp/src/test/java/io/modelcontextprotocol/server/McpServerProtocolVersionTests.java index 95086ee..cdd2bac 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/server/McpServerProtocolVersionTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/server/McpServerProtocolVersionTests.java @@ -45,7 +45,9 @@ class McpServerProtocolVersionTests { assertThat(jsonResponse.id()).isEqualTo(requestId); assertThat(jsonResponse.result()).isInstanceOf(McpSchema.InitializeResult.class); McpSchema.InitializeResult result = (McpSchema.InitializeResult) jsonResponse.result(); - assertThat(result.protocolVersion()).isEqualTo(transportProvider.protocolVersion()); + + var protocolVersion = transportProvider.protocolVersions().get(transportProvider.protocolVersions().size() - 1); + assertThat(result.protocolVersion()).isEqualTo(protocolVersion); server.closeGracefully().subscribe(); } @@ -93,7 +95,8 @@ class McpServerProtocolVersionTests { assertThat(jsonResponse.id()).isEqualTo(requestId); assertThat(jsonResponse.result()).isInstanceOf(McpSchema.InitializeResult.class); McpSchema.InitializeResult result = (McpSchema.InitializeResult) jsonResponse.result(); - assertThat(result.protocolVersion()).isEqualTo(transportProvider.protocolVersion()); + var protocolVersion = transportProvider.protocolVersions().get(transportProvider.protocolVersions().size() - 1); + assertThat(result.protocolVersion()).isEqualTo(protocolVersion); server.closeGracefully().subscribe(); } diff --git a/mcp/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java b/mcp/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java index 6122227..a5b2137 100644 --- a/mcp/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java +++ b/mcp/src/test/java/io/modelcontextprotocol/spec/McpSchemaTests.java @@ -320,8 +320,8 @@ public class McpSchemaTests { McpSchema.Implementation clientInfo = new McpSchema.Implementation("test-client", "1.0.0"); Map meta = Map.of("metaKey", "metaValue"); - McpSchema.InitializeRequest request = new McpSchema.InitializeRequest("2024-11-05", capabilities, clientInfo, - meta); + McpSchema.InitializeRequest request = new McpSchema.InitializeRequest(ProtocolVersions.MCP_2024_11_05, + capabilities, clientInfo, meta); String value = mapper.writeValueAsString(request); assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER) @@ -343,8 +343,8 @@ public class McpSchemaTests { McpSchema.Implementation serverInfo = new McpSchema.Implementation("test-server", "1.0.0"); - McpSchema.InitializeResult result = new McpSchema.InitializeResult("2024-11-05", capabilities, serverInfo, - "Server initialized successfully"); + McpSchema.InitializeResult result = new McpSchema.InitializeResult(ProtocolVersions.MCP_2024_11_05, + capabilities, serverInfo, "Server initialized successfully"); String value = mapper.writeValueAsString(result); assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)