Repository navigation
Conversation
…erving A non-initialize request whose params._meta carries a pre-2026 io.modelcontextprotocol/protocolVersion claim was routed to serveModern and rejected: -32022 for a full envelope, -32602 for a version-only claim, because handle() dispatches on outcome.kind and the envelope was validated against the 2026-07-28 schema. On a dual-era endpoint this breaks 2025-era clients the legacy leg would serve fine. classifyRequestBody and classifyNotificationBody now classify a claim naming a pre-2026 revision as legacy traffic (requestedVersion keeps the claimed revision, so modern-only endpoints still answer -32022), and skip the modern envelope validation for it. classifyBatch keeps arrays with legacy-claiming elements as legacy batches; modern-claiming and malformed claims are still rejected, and a disagreeing MCP-Protocol-Version header is still a -32020 mismatch. Fixes modelcontextprotocol#3159
🦋 Changeset detectedLatest commit: d90a641 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
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/core
@modelcontextprotocol/server
@modelcontextprotocol/server-legacy
@modelcontextprotocol/express
@modelcontextprotocol/fastify
@modelcontextprotocol/hono
@modelcontextprotocol/node
commit: |
koriyoshi2041
left a comment
There was a problem hiding this comment.
The changeset is not parseable at this head. .changeset/legacy-envelope-claim-routing.md starts directly with '@modelcontextprotocol/server': patch, so the opening --- delimiter is missing; the changeset bot consequently reports invalid frontmatter and cannot determine the package/version bump.
It should start with:
---
'@modelcontextprotocol/server': patch
---The routing tests and hosted matrix are otherwise green at 9df5f546.
|
Good catch, thanks - the opening |
|
Confirmed on d90a641: the opening fence is present, Changesets now parses the server patch entry, and the refreshed build/test/E2E/runtime/conformance matrix is green. Thanks for the quick fix. |
Fixes #3159.
Problem
On a dual-era Streamable HTTP entry (
createMcpHandlerwith legacy serving, e.g. the defaultlegacy: 'stateless'), a non-initializerequest whoseparams._metacarries a pre-2026io.modelcontextprotocol/protocolVersionclaim was routed to the modern path and rejected:400-32022"Unsupported protocol version: 2025-06-18" — even though the endpoint serves 2025-06-18 fine through its legacy leg;400-32602, becausevalidateEnvelopeMetaapplies the 2026-07-28 envelope schema to a claim that names a 2025 revision;-32022, and-32600viabatch-with-modern-element).Reproduced on current
main(2.4.0) with the exact requests from the issue before writing the fix.Fix
classifyRequestBodyandclassifyNotificationBodynow classify a claim naming a pre-2026 revision as legacy-era traffic — the same precedenceinitializealready gets viacarriesValidModernEnvelopeClaim— withrequestedVersionset to the claimed revision, and skip the modern envelope validation for those claims (that schema belongs to the modern revision).classifyBatchkeeps arrays whose elements claim pre-2026 revisions as legacy batches.Deliberately unchanged:
-32602rejection;MCP-Protocol-Versionheader that disagrees with the claim →-32020;legacy: 'reject') still answer 2025-era claims with-32022naming the supported revisions, viamodernOnlyStrictRejection.Note: this flips one pinned classifier cell, which previously routed legacy-claimed requests to the modern leg "rather than being silently re-routed". The issue argues that behavior breaks dual-era interop (the endpoint rejects a version it actually serves); the mismatch handoff is preserved where it is the only answer available, on modern-only endpoints. Happy to reshape if you prefer a different split.
Tests
requestedVersion; a legacy claim is not validated against the modern envelope schema; a disagreeing header is still-32020; a batch with a legacy-claiming element stays legacy while a malformed claim is still rejected.-32022.core-internal(1855) andserver(679) suites pass; typecheck clean; changeset included.