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
Validate Mcp-Param-* headers server-side on the 2026-07-28 HTTP path (SEP-2243)
Servers that process the request body MUST validate that Mcp-Param-*
headers match the corresponding x-mcp-header-annotated body arguments,
rejecting mismatches with HTTP 400 and -32020 (HeaderMismatch). The
client half shipped earlier; this adds the server half:
- mcp.shared.inbound grows a pure, exported validate_mcp_param_headers
built on the same walker and scalar rendering the client emit side
uses, so the two halves of the mirror contract cannot drift. Presence
rules follow the spec's scenario table; recognized headers supplied
more than once are rejected (first-wins consumers vs last-wins
validation would otherwise disagree); integer values compare
numerically behind a canonical-decimal gate, exactly and in both
directions; unrecognized headers stay ignored.
- decode_header_value now requires canonical base64 in the sentinel
(bad padding, stray characters, non-zero trailing bits, or invalid
UTF-8 are malformed), which the conformance suite mandates for
Mcp-Param-* and which now applies to Mcp-Name symmetrically.
- The modern HTTP entry validates tools/call pre-dispatch, resolving
the called tool's inputSchema through the server's own registered
tools/list handler via the normal serve_one path with the caller's
envelope - so a visibility-scoped catalog validates exactly what
this caller was advertised, with nothing to configure on MCPServer
or lowlevel servers. The listing is skipped (never failing the
call) when no tools/list handler is registered, the tool is not
advertised, the handler raises (logged), pagination exceeds a page
cap or cycles, or the call has no arguments and no Mcp-Param-*
headers.
- Remove http-custom-header-server-validation from both conformance
expected-failures baselines; the scenario passes 9/9 against the
everything-server, with http-header-validation and server-stateless
unchanged.
Copy file name to clipboardExpand all lines: docs/migration.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -427,6 +427,14 @@ On `ClientSession`, `call_tool` / `get_prompt` / `read_resource` still return th
427
427
428
428
For protocol 2026-07-28 over Streamable HTTP, a tool's input-schema property may carry an `x-mcp-header` annotation. When a tool the client has listed is called, each annotated argument is mirrored into an `Mcp-Param-<name>` request header (string verbatim, integer as decimal, boolean as `true`/`false`, base64-sentinel-wrapped when not header-safe; `null`/absent arguments are omitted). The argument is also left in the request body. `list_tools` caches a tool's annotations, so list a tool before calling it to enable mirroring; a tool the client never listed emits no `Mcp-Param-*` headers. Other transports ignore the annotation.
429
429
430
+
### Servers validate `Mcp-Param-*` headers against the request body ([SEP-2243](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2243))
431
+
432
+
The server half of the same contract: on the 2026-07-28 Streamable HTTP path, a `tools/call` whose tool declares `x-mcp-header` annotations is validated before dispatch — each annotated argument and its mirroring `Mcp-Param-*` header must be present together and agree (after base64-sentinel decoding; integers compare numerically), or absent together. A violation is rejected with HTTP 400 and JSON-RPC error `-32020` (`HeaderMismatch`), as the spec requires. A client that sends an annotated argument *without* its header — for example one that never listed the tool — is therefore rejected instead of silently served; the spec's recovery is to re-list and retry.
433
+
434
+
There is nothing to configure. The server resolves the called tool's schema through its own registered `tools/list` handler (for `MCPServer`, the built-in one), so the validated catalog is exactly what that caller would be shown. Two consequences worth knowing: the listing runs internally on validated calls, so middleware and an expensive or paginated `tools/list` handler see extra invocations; and validation is skipped — never failing the call — when no `tools/list` handler is registered, the tool isn't in the listing, the handler raises (logged as a warning), or the call has no arguments and no `Mcp-Param-*` headers. Headers with no matching annotation are ignored; a recognized header supplied more than once is rejected. The codec and validator are public in `mcp.shared.inbound` (`decode_header_value`, `validate_mcp_param_headers`) for low-level servers hosting their own HTTP entry.
435
+
436
+
Base64-sentinel decoding is strict everywhere it applies, including the `Mcp-Name` header: a `=?base64?...?=` value whose payload is not canonical base64 (wrong padding, stray characters, non-zero trailing bits) or not valid UTF-8 is rejected as malformed rather than leniently decoded.
437
+
430
438
### `Client` verbs may serve cached responses ([SEP-2549](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2549))
431
439
432
440
On protocol 2026-07-28, servers attach caching hints (`ttlMs`, `cacheScope`) to the cacheable results, and `Client` now honors them: `list_tools`, `list_prompts`, `list_resources`, `list_resource_templates`, and `read_resource` may serve a cached response instead of making a round trip, for as long as the server's `ttlMs` says the result is fresh. With the default configuration, servers that send no hints, including every pre-2026 server, see identical call-for-call behavior, because hint-less results are not cached (a `CacheConfig.default_ttl_ms` above zero caches them too). Pass `Client(..., cache=False)` to disable the cache and restore v1 behavior exactly; per-call control (`cache_mode`) and configuration (`CacheConfig`) are described in [Caching hints](advanced/caching.md).
0 commit comments