fix: add backward compatibility for MCP servers returning older protocol versions

- Add ProtocolVersions interface with version constants
- Change protocolVersion() to protocolVersions() returning List<String>
- 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 <christian.tzolov@broadcom.com>
This commit is contained in:
Christian Tzolov 2025-08-04 12:07:31 +01:00 • committed by Christian Tzolov
commit 5e035ea255
14 changed files with 107 additions and 54 deletions

View file

@ -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);
});

View file

@ -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);
}

View file

@ -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<String> protocolVersions() {
return List.of(ProtocolVersions.MCP_2024_11_05);
}
/**

View file

@ -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<String> protocolVersions() {
return List.of(ProtocolVersions.MCP_2024_11_05, ProtocolVersions.MCP_2025_03_26);
}
public static Builder builder(String baseUri) {

View file

@ -145,7 +145,7 @@ public class McpAsyncServer {
Map<String, McpRequestHandler<?>> requestHandlers = prepareRequestHandlers();
Map<String, McpNotificationHandler> 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<String, McpRequestHandler<?>> requestHandlers = prepareRequestHandlers();
Map<String, McpNotificationHandler> notificationHandlers = prepareNotificationHandlers(features);
this.protocolVersions = List.of(mcpTransportProvider.protocolVersion());
this.protocolVersions = mcpTransportProvider.protocolVersions();
mcpTransportProvider.setSessionFactory(new DefaultMcpStreamableServerSessionFactory(requestTimeout,
this::asyncInitializeRequestHandler, requestHandlers, notificationHandlers));

View file

@ -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);

View file

@ -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<String> protocolVersions() {
return List.of(ProtocolVersions.MCP_2024_11_05);
}
/**

View file

@ -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<String> protocolVersions() {
return List.of(ProtocolVersions.MCP_2024_11_05, ProtocolVersions.MCP_2025_03_26);
}
@Override

View file

@ -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<String> protocolVersions() {
return List.of(ProtocolVersions.MCP_2024_11_05);
}
@Override

View file

@ -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";

View file

@ -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<String> protocolVersions() {
return List.of(ProtocolVersions.MCP_2024_11_05);
}
}

View file

@ -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<Void> closeGracefully();
default String protocolVersion() {
return "2025-03-26";
default List<String> protocolVersions() {
return List.of(ProtocolVersions.MCP_2025_03_26);
}
}

View file

@ -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> T unmarshalFrom(Object data, TypeReference<T> typeRef);
default String protocolVersion() {
return "2024-11-05";
default List<String> protocolVersions() {
return List.of(ProtocolVersions.MCP_2024_11_05);
}
}

View file

@ -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";
}