fix(server): bound resumability version gates to supported versions, pin the unsupported-version rejection format#2280
Merged
Conversation
🦋 Changeset detectedLatest commit: 425f79f The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@modelcontextprotocol/client
@modelcontextprotocol/codemod
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
4f6b348 to
ce5bdbb
Compare
ce5bdbb to
6d78425
Compare
Merged
9 tasks
The Streamable HTTP server transport enabled priming events and closeSSEStream callbacks via an open-ended >= '2025-11-25' comparison, so an unknown future protocol version string in an initialize request body (which is not header-validated) silently enabled that behavior. The version must now also be one of the transport's supported protocol versions. Behavior for all currently supported versions is unchanged.
The go-sdk client substring-matches 'Unsupported protocol version' on non-2xx response bodies to detect protocol-version fallback (its structured parse path rejects the id:null error body), so the HTTP 400 status and that literal substring are load-bearing interop surface. Assert them from the response bytes; assert the full message shape against a string derived from SUPPORTED_PROTOCOL_VERSIONS so the tests survive additions to the supported-versions list.
Migration guide notes: unknown future protocol versions in an initialize body no longer enable resumability behavior, and the 404/-32001 'Session not found' response on session-ID mismatch is an SDK convention that may be re-derived for the 2026 protocol revision - clients should key off the HTTP status, not the code. Changeset for the server package included.
6d78425 to
425f79f
Compare
maxisbey
approved these changes
Jun 12, 2026
This was referenced Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bounds the two open-ended protocol-version comparisons gating SSE resumability behavior in the Streamable HTTP server transport, and pins the
-32000"Unsupported protocol version" rejection wire format.Motivation and Context
The priming-event gate and the
closeSSEStreamcallback gate both used open-ended lexicographic checks (protocolVersion >= '2025-11-25'). The version they compare can come from aninitializerequest body, which — unlike theMCP-Protocol-Versionheader — is not validated against the supported-versions list, so an unknown future version string (e.g. a draft revision a client speculatively claims) silently enabled behavior reserved for versions the transport actually supports. The checks now also require membership in the transport's supported protocol versions, mirroring the already-set-closed header path.The rejection shape is load-bearing interop surface: the go-sdk client substring-matches
Unsupported protocol versionon non-2xx response bodies to drive its protocol-version fallback (streamableClientConn.checkResponseinmcp/streamable.go; its structured JSON-RPC parse path rejects this server'sid: nullerror body, so the substring is the operative signal). This PR pins HTTP 400 + that substring from the response bytes, and asserts the full message shape against a string derived fromSUPPORTED_PROTOCOL_VERSIONSso the tests survive future additions to the supported-versions list.How Has This Been Tested?
'2099-01-01'and'2099-12-31'initialize bodies through both gates (no priming event, no early-close callbacks). Far-future sentinels deliberately avoid the next planned revision (2026-07-28) so the cases stay "unknown" when it gains support.Breaking Changes
None for any currently supported protocol version (byte-identical behavior, see matrix above). Clients claiming an unknown future protocol version in the initialize body are now treated like clients without empty-SSE-data support: no priming event, no early-close callbacks. Documented in
docs/migration.md, with a patch changeset.Types of changes
Checklist
Additional context
Also documents the existing 404/
-32001"Session not found" response in the migration guide: that code is an SDK convention (not spec-assigned), flagged for re-derivation as 2026-07-28 error handling is adopted — clients should key off the HTTP 404 status rather than the-32001code.Note: this server emits
-32000for the unsupported-version rejection while the go-sdk and the conformance mocks use-32004— a cross-SDK inconsistency worth aligning separately.