What's broken?
The spec is ambiguous or self-contradictory
Where in the spec or docs?
Version negotiation, Streamable HTTP protocol version header
What should happen?
The spec should define the expected behavior when an HTTP initialize request contains both:
MCP-Protocol-Version: 2025-03-26
and:
{
"jsonrpc": "2.0",
"id": "init-1",
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": {
"name": "example-client",
"version": "1.0.0"
}
}
}
The expected behavior should be explicit. At the moment, it is unclear whether this request is valid, invalid, or valid with one of the two version fields treated as authoritative.
What actually happens?
The current Streamable HTTP specification defines protocol version negotiation in the JSON-RPC initialize request body, and separately defines the MCP-Protocol-Version HTTP header. It does not appear to say what a server should do when both are present on the initial initialize request and they disagree.
This creates an ambiguity across protocol layers:
- MCP request-handling logic may negotiate based on
initialize.params.protocolVersion.
- HTTP middleware, gateways, observability tools, or security filters may route or validate based on
MCP-Protocol-Version.
- If the two values disagree and the spec does not define precedence or rejection behavior, different components can make decisions based on different protocol versions.
In cross-SDK testing, we sent initial initialize requests where initialize.params.protocolVersion and MCP-Protocol-Version disagreed in both directions:
- Body
2025-11-25, header 2025-03-26
- Body
2025-03-26, header 2025-11-25
Across the tested official SDK server configurations, none rejected the initial mismatch based on body/header inconsistency. All returned HTTP 200 and completed initialization.
Observed behavior for the initial initialize request:
| SDK |
Tested HTTP profile(s) |
Stable release |
main snapshot (pinned 2026-05-11) |
Observed result |
| TypeScript |
stateful, stateless |
v1.29.0 (e12cbd70) |
2c0c481c |
Accepted; negotiated version followed the JSON-RPC body |
| C# |
stateful, stateless |
v1.3.0 (2ce15f4c) |
3118fcd6 |
Accepted; negotiated version followed the JSON-RPC body |
| Go |
stateful |
v1.6.0 (f5f20154) |
9f5e89fe |
Accepted; negotiated version followed the JSON-RPC body |
| Go |
declared stateless profile |
v1.6.0 (f5f20154) |
9f5e89fe |
Accepted; issued a session ID in this test setup, so it was not counted as clean stateless evidence |
| Java |
stateful |
v1.1.2 (e9e1a2f3) |
87e2c7d4 |
Accepted; negotiated version followed the JSON-RPC body |
| Kotlin |
stateful |
0.12.0 (c339d8cb) |
8a814292 |
Accepted; negotiated version followed the JSON-RPC body |
| Python |
stateful, stateless |
v1.27.1 (77431ebe) |
161834d4 |
Accepted; negotiated version followed the JSON-RPC body |
| Ruby |
stateful |
v0.15.0 (ebc65696) |
9090cb6e |
Accepted; negotiated version followed the JSON-RPC body |
| PHP |
stateful |
v0.5.0 (fb2c8c2e) |
06917f6a |
Accepted; server returned its preferred version (2025-06-18) regardless of either input value |
| Rust |
stateful |
rmcp-v1.6.0 (014fb2e6) |
321ab14f |
Accepted; server returned its preferred version (2024-11-05) regardless of either input value |
As of May 11, 2026, the same pattern was observed in both stable release-version SDK pins and recent main-branch snapshots used for comparison.
Follow-up responses generally used the server's negotiated version in MCP-Protocol-Version, not the mismatching initial header value. This suggests that implementations are either ignoring the header during initialization or applying server-specific negotiation rules without checking consistency.
Anything else?
This is not intended as a report against any single SDK. The same ambiguity showed up across multiple official SDK server implementations, suggesting that the spec text is underspecified rather than a single SDK bug.
Related prior issues and work:
Related conformance work:
This issue is narrower than SEP-2575: it asks whether the current 2025-11-25 spec should clarify what happens when the initial initialize request carries two different protocol-version signals.
What's broken?
The spec is ambiguous or self-contradictory
Where in the spec or docs?
Version negotiation, Streamable HTTP protocol version header
What should happen?
The spec should define the expected behavior when an HTTP
initializerequest contains both:and:
{ "jsonrpc": "2.0", "id": "init-1", "method": "initialize", "params": { "protocolVersion": "2025-11-25", "capabilities": {}, "clientInfo": { "name": "example-client", "version": "1.0.0" } } }The expected behavior should be explicit. At the moment, it is unclear whether this request is valid, invalid, or valid with one of the two version fields treated as authoritative.
What actually happens?
The current Streamable HTTP specification defines protocol version negotiation in the JSON-RPC
initializerequest body, and separately defines theMCP-Protocol-VersionHTTP header. It does not appear to say what a server should do when both are present on the initialinitializerequest and they disagree.This creates an ambiguity across protocol layers:
initialize.params.protocolVersion.MCP-Protocol-Version.In cross-SDK testing, we sent initial
initializerequests whereinitialize.params.protocolVersionandMCP-Protocol-Versiondisagreed in both directions:2025-11-25, header2025-03-262025-03-26, header2025-11-25Across the tested official SDK server configurations, none rejected the initial mismatch based on body/header inconsistency. All returned HTTP
200and completed initialization.Observed behavior for the initial
initializerequest:mainsnapshot (pinned 2026-05-11)v1.29.0(e12cbd70)2c0c481cv1.3.0(2ce15f4c)3118fcd6v1.6.0(f5f20154)9f5e89fev1.6.0(f5f20154)9f5e89fev1.1.2(e9e1a2f3)87e2c7d40.12.0(c339d8cb)8a814292v1.27.1(77431ebe)161834d4v0.15.0(ebc65696)9090cb6ev0.5.0(fb2c8c2e)06917f6a2025-06-18) regardless of either input valuermcp-v1.6.0(014fb2e6)321ab14f2024-11-05) regardless of either input valueAs of May 11, 2026, the same pattern was observed in both stable release-version SDK pins and recent main-branch snapshots used for comparison.
Follow-up responses generally used the server's negotiated version in
MCP-Protocol-Version, not the mismatching initial header value. This suggests that implementations are either ignoring the header during initialization or applying server-specific negotiation rules without checking consistency.Anything else?
This is not intended as a report against any single SDK. The same ambiguity showed up across multiple official SDK server implementations, suggesting that the spec text is underspecified rather than a single SDK bug.
Related prior issues and work:
MCP-Protocol-Versionis missing._metaprotocol version.Related conformance work:
initialize.MCP-Protocol-Versionvalues, but not a supported header value that disagrees with the body.initialize.params.protocolVersionbody/header interaction.This issue is narrower than SEP-2575: it asks whether the current
2025-11-25spec should clarify what happens when the initialinitializerequest carries two different protocol-version signals.