Skip to content

Clarify behavior when initialize.params.protocolVersion conflicts with MCP-Protocol-Version #2721

@cclabadmin

Description

@cclabadmin

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions