Skip to content

Disambiguate HTTP backward-compat fallbacks: inspect 400/404 body before falling back#2727

Merged
pja-ant merged 1 commit into
mainfrom
pja/draft-http-fallback-disambiguation
May 15, 2026
Merged

Disambiguate HTTP backward-compat fallbacks: inspect 400/404 body before falling back#2727
pja-ant merged 1 commit into
mainfrom
pja/draft-http-fallback-disambiguation

Conversation

@pja-ant

@pja-ant pja-ant commented May 15, 2026

Copy link
Copy Markdown
Contributor

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 Request is overloaded. Modern servers return 400 for UnsupportedProtocolVersionError, MissingRequiredClientCapabilityError, and Mcp-* header-validation failures. The backward-compatibility section of lifecycle.mdx (and transports.mdx § Backward Compatibility) tells clients to fall back to the legacy initialize handshake on any 400. 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 Found is overloaded. transports.mdx § Protocol Version Header introduces 404 + JSON-RPC -32601 for unknown methods, while the HTTP+SSE backward-compat heuristic uses 404 (alongside 400/405) as a signal to try the deprecated 2024-11-05 GET-SSE transport.
  • A missing MCP-Protocol-Version header has two conflicting behaviors. § Server Validation lists the missing header as a MUST-reject failure; § Protocol Version Header says the server SHOULD assume 2025-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 the 400 body. 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 to initialize."
  • transports.mdx: the same body-inspection guidance is applied to both backward-compat paths. The HTTP+SSE detection step now triggers only when the 400/404/405 body is not a recognized modern JSON-RPC error, so a 404 for unknown method does not falsely look like an old transport.
  • transports.mdx: the missing-MCP-Protocol-Version SHOULD rule is scoped to servers that opt in to supporting clients implementing protocol versions earlier than 2025-06-18 (which did not define the header). Servers that do not support such clients reject per Server Validation.

Also fixes supportedVersionssupported in the two backward-compat sections; the field on UnsupportedProtocolVersionError.error.data is named supported. (supportedVersions is the field on DiscoverResult, 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

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Related: #2716 introduces a dedicated -32004 error code for UnsupportedProtocolVersionError, which makes the body-inspection rule even more reliable.

…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.
@mintlify

mintlify Bot commented May 15, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
mcp-staging 🟢 Ready View Preview May 15, 2026, 3:06 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@pja-ant pja-ant marked this pull request as ready for review May 15, 2026 15:22
@pja-ant pja-ant requested a review from a team as a code owner May 15, 2026 15:22
@pja-ant pja-ant requested a review from kurtisvg May 15, 2026 15:23
@pja-ant pja-ant merged commit 2807279 into main May 15, 2026
10 checks passed
@pja-ant pja-ant deleted the pja/draft-http-fallback-disambiguation branch May 15, 2026 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants