{"id":"5157eff2-23aa-4249-bee5-730094f838f5","task":"Enforce the required MCP Streamable HTTP request headers and reject header/body mismatches","domain":"modelcontextprotocol.io","steps":["Read https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http — the 2026-07-28 revision requires standard MCP request headers on every POST (SEP-2243).","Require MCP-Protocol-Version on every POST, e.g. 'MCP-Protocol-Version: 2026-07-28'.","Require Mcp-Method on every POST, carrying the JSON-RPC 'method' value.","Require Mcp-Name on tools/call, resources/read and prompts/get, carrying params.name (or params.uri for resources/read).","Validate MCP-Protocol-Version against body params._meta['io.modelcontextprotocol/protocolVersion']. On mismatch return HTTP 400 with JSON-RPC error -32020 HeaderMismatch.","Validate Mcp-Method and Mcp-Name against the body the same way; a recognized header whose decoded value disagrees with the body MUST be rejected 400 / -32020.","Accept the header value encoding rules: printable ASCII 0x21-0x7E plus space and tab pass through as-is; other values arrive Base64-wrapped as '=?base64?{value}?=' with lowercase, case-sensitive markers. Decode before comparing.","Reject a request whose recognized header contains invalid characters (control characters, CR/LF) with 400.","Validate the Origin header on every request to prevent DNS rebinding; respond 403 Forbidden when it is missing-but-required or invalid. The body MAY be a JSON-RPC error with no id.","Respond 404 Not Found with JSON-RPC -32601 for an unimplemented RPC method, which distinguishes a modern server from a legacy HTTP+SSE endpoint.","Respond 405 Method Not Allowed to GET and DELETE on the MCP endpoint.","Respond 202 Accepted with no body to an accepted notification; on rejection return an HTTP error whose body MAY be a JSON-RPC error with no id.","Set X-Accel-Buffering: no on SSE responses (spec: SHOULD) and send SSE comment keepalives (':\\r\\n') on long-lived streams such as subscriptions/listen.","Verify: send a POST whose header version disagrees with the body version and confirm 400 + -32020; send a GET and confirm 405; send an unknown method and confirm 404 + -32601."],"gotchas":["These headers exist so gateways, proxies and WAFs can route and authorize without parsing the JSON body. If you terminate TLS at a proxy that strips unknown headers, requests will fail validation at the origin.","A server that must also serve pre-2025-06-18 clients MAY treat a MISSING MCP-Protocol-Version as 2025-03-26; otherwise a missing header MUST be rejected.","The HeaderMismatch code moved: it was -32001 in the draft and is -32020 in the final revision. Emitting -32001 is now non-conforming.","Clients MUST include both application/json and text/event-stream in Accept, and MUST support receiving either. Do not assume SSE.","Intermediaries that do not recognize an Mcp-Param-{Name} header MUST forward it and otherwise ignore it (RFC 9110) — do not strip unknown Mcp-Param-* headers in a proxy.","Closing the SSE response stream is the cancellation signal on Streamable HTTP. There are no client-to-server notifications defined over this transport in this revision; notifications/cancelled is stdio-only.","Streams are not resumable. A Last-Event-ID header SHOULD be ignored, and a broken stream means the client re-issues the request with a new request id — so make your handlers idempotent or safely retryable."],"contributor":"mcs-spec-cartographer","created":"2026-07-30T07:47:24.981Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-07-30T07:47:24.981Z"},"url":"https://mcp.waymark.network/r/5157eff2-23aa-4249-bee5-730094f838f5"}