Repository navigation
MCP: accept missing MCP-Protocol-Version as the session's negotiated version - #1694
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the MCP transport protocol validation to accept requests with a missing MCP-Protocol-Version header on established sessions, treating them as using the session's negotiated version. This resolves issues where headerless requests on newer session versions were incorrectly rejected. Corresponding unit tests have been updated and added to verify this behavior. There are no review comments, and I have no additional feedback to provide.
|
Reviewed; no blockers found. |
|
Hey @kylebernhardy — retargeted this from |
…sion (#1611) Assuming 2025-03-26 for an absent header (the spec's backcompat rule for pre-header clients) made every headerless request on a 2025-06-18 session fail the mismatch check with a 400. The established session is the version authority: a missing header now validates as the session's own version, while a present header must still be supported and match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8252640 to
5671427
Compare
|
Understood — thanks for the workflow correction (main-first, |
Patch cherry-pick: mergedCherry-picked onto |
…x-1611 MCP: accept missing MCP-Protocol-Version as the session's negotiated version
Fixes #1611 (as repurposed after investigation — both originally-filed items were verified unreproducible/stale on 5.1.17; see the issue comment with runtime evidence).
Summary
Requests on an established session that omit
MCP-Protocol-Versionwere treated as2025-03-26(the spec's backcompat assumption) and then failed the negotiated-version check — so any client that negotiated2025-06-18but doesn't send the header on every request got400 MCP-Protocol-Version mismatch. The session record already knows the negotiated version, so a missing header now validates as that version. A header that IS present must still name a supported version and match the negotiated one (both still 400).One conditional in
validateProtocolHeader(covers both call sites: POST dispatch and GET SSE open);initializenever validated the header and is unchanged.Spec posture (flagging for review): the assume-2025-03-26 rule is a SHOULD aimed at clients predating the header; such clients negotiate 2025-03-26 anyway, so deferring to the session version is equivalent for them and stops penalizing modern clients that violate the MUST-send-header rule on non-critical requests. No downgrade risk — the authority is the server-side session record, not anything an attacker can strip in transit.
Testing
Flipped the unit test that asserted the 400, added a headerless GET SSE case; verified at runtime on a live instance (headerless
tools/liston a 2025-06-18 session → 200;2025-03-26header on the same session → 400; garbage version → 400). No docs companion: the docs don't document the header behavior.Generated by an LLM (Claude Fable 5); cross-reviewed by Codex (no findings) and Gemini (no findings; confirmed both call sites, the empty-string-header edge, and the no-downgrade posture).