You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The 2026 Streamable HTTP header validation rejects a valid Mcp-Name when its value has leading or trailing HTTP optional whitespace. Header field values are subject to HTTP whitespace normalization; a client or intermediary that sends Mcp-Name: tools/call is rejected with JSON-RPC error -32020, although the trimmed value names the registered method.
This also fails the official conformance case sep-2243 (header validation).
Reproduction
Send a valid 2026 request with:
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: tools/call
a valid tools/call JSON-RPC body
On mcp 2.3.0, the SDK returns -32020 rather than accepting the header value after HTTP whitespace handling.
Expected
Normalize permitted surrounding HTTP whitespace before comparing the header value, while continuing to reject values that differ after normalization.
Environment
Python SDK 2.3.0; reproduced by the MCP conformance suite's sep-2243 header-validation case.
Thanks for the focused reproduction. I’d normalize only permitted HTTP optional whitespace around Mcp-Name before comparing it with the registered method, then add regression coverage for leading and trailing whitespace while keeping mismatched values rejected. I used Codex to help review the issue and will review and own any change. Does that match the intended spec handling, and would it be okay for me to take this once assigned?
When headers.get(MCP_NAME_HEADER) carries permitted OWS (e.g. Mcp-Name: tools/call or Mcp-Name: my_tool ), decode_header_value returns the unstripped literal. In classify_inbound_request (line 467):
ifbody_valueisnotNoneanddecode_header_value(headers.get(MCP_NAME_HEADER)) !=body_value:
returnInboundLadderRejection(
code=HEADER_MISMATCH,
message=f"{MCP_NAME_HEADER} header does not match the request body's {name_key!r} parameter",
)
The comparison " tools/call " != "tools/call" fails, rejecting valid requests with HEADER_MISMATCH (-32020) and causing conformance scenario sep-2243 to fail.
Proposed Fix
In src/mcp/shared/inbound.py, strip permitted HTTP OWS (" \t") in decode_header_value before sentinel matching:
Full test suites passing: 240/240 tests pass (pytest tests/shared/test_inbound.py tests/server/test_streamable_http_modern.py). Ruff lint and formatting clean.
Yep, that matches what I meant. I'd keep it to HTTP OWS (SP / HTAB) at the header boundary, then still reject anything that doesn't match after normalization.
@aritejhg thanks for taking a look, and @duongynhi000005-oss appreciate the repro + tests. The existing patch looks like the right direction, so no need for folks to duplicate the same fix. Happy to review or help verify sep-2243 once a maintainer picks an owner.
Linking the existing implementation so it doesn’t get missed: #3764 already proposes trimming HTTP SP/HTAB before sentinel decoding and comparison. It was auto-closed by the assignment gate, not rejected on technical grounds. There is also the tested fork proposal linked above; I won’t create another implementation.
The behavior I want as the reporter is to remove surrounding wire-level OWS before decoding, while preserving whitespace inside a decoded Base64 value and continuing to reject actual header/body mismatches. That keeps a body name containing significant edge whitespace distinct from padding added around its encoded header.
AI disclosure: Codex reviewed the source and existing proposals and drafted this reply; I have not independently run either contributor’s tests.
Activity
aritejhg commentedon Oct 26, 2026
Thanks for the focused reproduction. I’d normalize only permitted HTTP optional whitespace around
Mcp-Namebefore comparing it with the registered method, then add regression coverage for leading and trailing whitespace while keeping mismatched values rejected. I used Codex to help review the issue and will review and own any change. Does that match the intended spec handling, and would it be okay for me to take this once assigned?duongynhi000005-oss commentedon Oct 27, 2026
Technical Root Cause & Proposal
Root Cause Analysis
Per RFC 9110 §5.6.3 (and RFC 7230 §3.2.4), HTTP header field values permit surrounding Optional Whitespace (
OWS = *( SP / HTAB )). HTTP intermediaries, reverse proxies, and client libraries routinely normalize or retain leading/trailing spaces and tabs around field values.In
src/mcp/shared/inbound.py:When
headers.get(MCP_NAME_HEADER)carries permitted OWS (e.g.Mcp-Name: tools/callorMcp-Name: my_tool),decode_header_valuereturns the unstripped literal. Inclassify_inbound_request(line 467):The comparison
" tools/call " != "tools/call"fails, rejecting valid requests withHEADER_MISMATCH(-32020) and causing conformance scenariosep-2243to fail.Proposed Fix
In
src/mcp/shared/inbound.py, strip permitted HTTP OWS (" \t") indecode_header_valuebefore sentinel matching:" \t"conforms strictly to RFC 9110 OWS definitions.=?base64?...?=).encode_header_value(values with edge whitespace are already base64-wrapped byencode_header_value).Mcp-NameandMcp-Param-*headers.Verification & Test Coverage
Added regression tests to
tests/shared/test_inbound.py:test_decode_header_value_normalizes_http_optional_whitespace: verifies spaces, tabs, and sentinel wrapping with OWS.test_header_rung_accepts_whitespace_padded_name_header: verifiesclassify_inbound_requestsuccessfully accepts whitespace-paddedMcp-Name.pytest tests/shared/test_inbound.py tests/server/test_streamable_http_modern.py). Ruff lint and formatting clean.Tested fix is ready on fork branch
duongynhi000005-oss:fix/3763-whitespace-padded-mcp-name. Per CONTRIBUTING.md, keeping code on the fork — happy to open the PR if maintainers assign the issue!DMomplaisir commentedon Oct 27, 2026
Yep, that matches what I meant. I'd keep it to HTTP OWS (SP / HTAB) at the header boundary, then still reject anything that doesn't match after normalization.
@aritejhg thanks for taking a look, and @duongynhi000005-oss appreciate the repro + tests. The existing patch looks like the right direction, so no need for folks to duplicate the same fix. Happy to review or help verify sep-2243 once a maintainer picks an owner.
DMomplaisir commentedon Oct 27, 2026
Linking the existing implementation so it doesn’t get missed: #3764 already proposes trimming HTTP SP/HTAB before sentinel decoding and comparison. It was auto-closed by the assignment gate, not rejected on technical grounds. There is also the tested fork proposal linked above; I won’t create another implementation.
The behavior I want as the reporter is to remove surrounding wire-level OWS before decoding, while preserving whitespace inside a decoded Base64 value and continuing to reject actual header/body mismatches. That keeps a body name containing significant edge whitespace distinct from padding added around its encoded header.
AI disclosure: Codex reviewed the source and existing proposals and drafted this reply; I have not independently run either contributor’s tests.