Disambiguate HTTP backward-compat fallbacks: inspect 400/404 body before falling back#2727
Merged
Merged
Conversation
…ore falling back Multiple HTTP backward-compatibility paths in the draft spec are keyed on the same status codes: - 400 is returned by modern servers for UnsupportedProtocolVersionError, MissingRequiredClientCapabilityError, and Mcp-* header validation failures, AND is described as the trigger for falling back to the legacy initialize handshake. - 404 is returned by modern servers for an unknown RPC method (with a -32601 JSON-RPC body), AND is part of the heuristic for detecting the deprecated 2024-11-05 HTTP+SSE transport. - A missing MCP-Protocol-Version header is simultaneously a Server Validation MUST-reject failure and a SHOULD-assume-2025-03-26 fallback, with no statement of which rule wins. This change makes the response body the disambiguator: a modern server always returns a recognizable JSON-RPC error in the body, while a legacy server does not. Clients are told to inspect the body before deciding which fallback path to take, and the missing-header SHOULD rule is scoped to servers that opt in to supporting clients implementing protocol versions earlier than 2025-06-18. Also fixes `supportedVersions` -> `supported` in lifecycle.mdx and transports.mdx; the field on UnsupportedProtocolVersionError.error.data is named `supported`. `supportedVersions` is the field on DiscoverResult, a successful result, not an error.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
kurtisvg
approved these changes
May 15, 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.
Motivation and Context
A review of the draft spec found that several HTTP backward-compatibility paths are over-determined: the same status codes signal multiple unrelated conditions, with no defined way for a client to distinguish them.
400 Bad Requestis overloaded. Modern servers return400forUnsupportedProtocolVersionError,MissingRequiredClientCapabilityError, andMcp-*header-validation failures. The backward-compatibility section oflifecycle.mdx(andtransports.mdx§ Backward Compatibility) tells clients to fall back to the legacyinitializehandshake on any400. A client that does so will incorrectly drop into legacy mode against a modern server that simply doesn't support the requested version, or whose request was malformed.404 Not Foundis overloaded.transports.mdx§ Protocol Version Header introduces404+ JSON-RPC-32601for unknown methods, while the HTTP+SSE backward-compat heuristic uses404(alongside400/405) as a signal to try the deprecated2024-11-05GET-SSE transport.MCP-Protocol-Versionheader has two conflicting behaviors. § Server Validation lists the missing header as a MUST-reject failure; § Protocol Version Header says the server SHOULD assume2025-03-26. There is no statement of which rule applies.This PR makes the response body the disambiguator, since a modern server always returns a recognizable JSON-RPC error in the body and a legacy server does not. Specifically:
lifecycle.mdx: the HTTP fallback bullet now tells clients to inspect the400body. A recognized modern error means "modern server — retry with a supported version or correct the request"; an empty or unrecognized body means "legacy server — fall back toinitialize."transports.mdx: the same body-inspection guidance is applied to both backward-compat paths. The HTTP+SSE detection step now triggers only when the400/404/405body is not a recognized modern JSON-RPC error, so a404for unknown method does not falsely look like an old transport.transports.mdx: the missing-MCP-Protocol-VersionSHOULD rule is scoped to servers that opt in to supporting clients implementing protocol versions earlier than2025-06-18(which did not define the header). Servers that do not support such clients reject per Server Validation.Also fixes
supportedVersions→supportedin the two backward-compat sections; the field onUnsupportedProtocolVersionError.error.datais namedsupported. (supportedVersionsis the field onDiscoverResult, a successful result, not an error.)How Has This Been Tested?
npm run check:docs(no new errors).Breaking Changes
None. This is a documentation clarification; the wire format and status codes are unchanged. It does change what conformant clients should do on a
400/404, which is the point — the previous text would have caused incorrect fallbacks.Types of changes
Checklist
Additional context
Related: #2716 introduces a dedicated
-32004error code forUnsupportedProtocolVersionError, which makes the body-inspection rule even more reliable.