Repository navigation
Description
Describe the bug
When the initial initialize request carries an MCP-Protocol-Version HTTP header that disagrees with initialize.params.protocolVersion in the JSON-RPC body, the server accepts the request without error. The negotiated protocol version follows the JSON-RPC body rather than the MCP-Protocol-Version request header.
The current MCP 2025-11-25 specification does not explicitly require the server to check body/header consistency on initialize, so this is filed as an implementation observation rather than a strict spec-violation claim.
- Environment
- Reproduced with stable release
v1.29.0(e12cbd70) - Also reproduced with a
mainsnapshot from 2026-05-16:22595b96 - Transport: Streamable HTTP server (stateful and stateless profiles)
- Reproduced with stable release
To reproduce
- Start a TypeScript SDK Streamable HTTP server.
- Send an
initializerequest where the bodyprotocolVersionis2025-11-25but theMCP-Protocol-Versionheader is2025-03-26(or vice versa). - Observe that the server returns HTTP 200 with a normal
initializeresult. - Check the negotiated protocol version in the response.
Expected behavior
Option A: the server rejects the mismatch before negotiation, for example with HTTP 400 or a JSON-RPC Invalid Request error.
Option B: the spec clarifies which field is authoritative, and the SDK documents that behavior and covers it with a regression test.
Logs
Both mismatch directions were accepted:
body=2025-11-25 header=2025-03-26 -> HTTP 200, negotiated version follows body (2025-11-25)
body=2025-03-26 header=2025-11-25 -> HTTP 200, negotiated version follows body (2025-03-26)
After initialization, subsequent responses used the body-negotiated version in the MCP-Protocol-Version header, not the original mismatched header value.
With a Streamable HTTP server running, set ENDPOINT to the server endpoint and send an initial initialize request whose HTTP header and JSON-RPC body disagree:
ENDPOINT=http://127.0.0.1:8080/mcp
curl -i -sS --http1.1 -X POST "$ENDPOINT" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2025-03-26' \
--data '{"jsonrpc":"2.0","id":"init-conflict-1","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"version-conflict-repro","version":"0.1.0"}}}'Repeat with the values reversed: body 2025-03-26, header 2025-11-25.
Additional context
- Related: SEP-2575 introduces a related future-state requirement that, for HTTP requests, the
MCP-Protocol-Versionheader match_meta["io.modelcontextprotocol/protocolVersion"].
Activity
dparikh79 commentedon May 16, 2026
I would like to take this. Quick read of the code on
main:packages/server/src/server/streamableHttp.tsrunsvalidateProtocolVersion()only on the non-initialize path (line 696 in the request-handling block, and similarly in the GET and DELETE handlers). The init branch (line 666 onward) accepts the request based on body parsing alone and never compares the header againstparams.protocolVersion. The same shape exists onv1.x(src/server/webStandardStreamableHttp.ts,validateProtocolVersionat line 874).Proposed fix: when the request is an initialize and the
MCP-Protocol-Versionheader is present, reject with 400 if it does not equalinitialize.params.protocolVersion. Header absent stays a soft case (the existing "header optional on initialize" behavior). This matches Option A from the issue and is consistent with the broader pattern of header-vs-body alignment that SEP-2575 is heading toward, without front-running that SEP.I will add a test in
packages/server/test/server/streamableHttp.test.tsthat exercises both directions (body newer than header, header newer than body) plus the negative case where they match. Will also mirror the change tov1.xin a separate PR if a maintainer wants it backported.Will hold off pushing the PR until I see a thumbs up here. Disclosure: implementation assisted by Claude; I am the human contributor reviewing.
jshaofa-ui commentedon May 17, 2026
jshaofa-ui commentedon May 17, 2026
serejaris commentedon May 27, 2026
Duplicate check update: I compared open PR #2111 against this issue.
#2111 covers the reported Streamable HTTP initialize mismatch directly:
packages/server/src/server/streamableHttp.ts;packages/server/test/server/streamableHttp.test.ts;-32600;I do not see extra behavior that needs a separate PR from my side. The useful next step looks like maintainer review/merge of #2111, not another duplicate branch.