-
Notifications
You must be signed in to change notification settings - Fork 1.1k
fix(mcp): protocol version negotiation #24717
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Implements spec-compliant version negotiation: silent fallback (i.e. 200 OK with server-supported protocol version) during initialization and strict MCP-Protocol-Version header validation for subsequent requests (i.e. 400 Bad Request for invalid protocol versions). - Removes custom McpException in favor of McpError in SDK.
kroepke
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall 👍 but I've left some minor comments for clarity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove the unused/default fields here, they'd end up in the changelog otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. Thanks!
| @Singleton | ||
| public class McpService { | ||
| private static final Logger LOG = LoggerFactory.getLogger(McpService.class); | ||
| protected static final List<String> supportedVersions = List.of(ProtocolVersions.MCP_2025_06_18); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use getFirst below, and I believe the intention is that the list is sorted in descending order, returning the latest version we support.
If we really need a List here, we should note that requirement in a comment or simply support a single version. I guess just adding a comment is fine.
We typically capitalize constant fields, and annotat/comment it if the relaxed visibility is for testing (iirc @VisibleForTesting annotation)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I just added LATEST_SUPPORTED_MCP_VERSION to avoid the sorting issue altogether. The list is there so we can add versions as we support them (we should probably support at least "2025-03-26" too since it's supposed to be the fallback version but that's prob for another time).
I don't think we need the annotation here, as the added visibility is for the rest resource. It could still be reduced tho, so i went ahead and modified that as well.
Thank you!
| final McpSchema.InitializeResult result = new McpSchema.InitializeResult( | ||
| initializeRequest.protocolVersion(), | ||
| // Version negotiation: https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle#version-negotiation | ||
| supportedVersions.contains(initializeRequest.protocolVersion()) ? initializeRequest.protocolVersion() : supportedVersions.getFirst(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
supportedVersions.getFirst() relies on statically ordered supportedVersions above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
kroepke
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thx!
* fix(mcp): protocol version negotiation - Implements spec-compliant version negotiation: silent fallback (i.e. 200 OK with server-supported protocol version) during initialization and strict MCP-Protocol-Version header validation for subsequent requests (i.e. 400 Bad Request for invalid protocol versions). - Removes custom McpException in favor of McpError in SDK. (cherry picked from commit 45d97f0)
This PR:
200 OKresponse with server-supported protocol version) and strictMCP-Protocol-Versionheader validation for subsequent requests (i.e.400 Bad Requestresponses for invalid/unsupported protocol versions).McpExceptionin favor ofMcpErrorin SDK.This ensures proper error handling according to the Model Context Protocol specification and fixes compatibility issues with MCP clients like MCP Inspector and fastmcp.
Description
Spec Compliance
Per 2025-06-18:
File changes
McpException.java
Replaced with standard McpError from MCP SDK
McpRestResource.java
Protocol Version Handling:
MCP-Protocol-Versionheader on all requests (when present).400 Bad Requestfor invalid/unsupported header values per spec."2025-03-26"when header is missing per spec backwards compatibility requirement.TODOfor future session management to retrieve negotiated version from session state.Error Handling:
McpErrorspecifically and return400 Bad Requestwith proper JSON-RPC error structure.McpService.java
Version Negotiation:
supportedVersionsto protected static final for proper access from REST resource.FALLBACK_MCP_VERSIONconstant ("2025-03-26") per spec requirement.Error Handling:
McpExceptionto throwsMcpError.McpError.builder().METHOD_NOT_FOUND,RESOURCE_NOT_FOUND,INVALID_PARAMS.API Changes:
handle()method acceptingprotocolVersionparameter for future multi-version support.TODOindicating where version-specific handlers could be implemented.McpServiceTest.java
testInitializeWithUnsupportedVersion()to expect successful fallback instead of exception.McpExceptiontoMcpError.Motivation and Context
Fixes #24701
The previous implementation had two main issues:
400 Bad Requesterror. Per the MCP specification, servers must silently fall back to a supported version and return200 OK, allowing the client to decide whether to continue.McpExceptionclass instead of the standardMcpErrortypes provided by the MCP SDK, leading to inconsistent error codes and messages.How Has This Been Tested?
Screenshots (if appropriate):
Types of changes
Checklist: