The short answer
MCP revision 2026-07-28 makes the protocol stateless. The initialize handshake is gone, protocol-level sessions and the Mcp-Session-Id header are gone, and every request now carries its protocol version and client capabilities in _meta.11 Servers must implement a new server/discover method.1 On Streamable HTTP, each POST also mirrors the method and tool name into headers, and a server must reject the request with 400 if a header disagrees with the body.2
For anyone who sits between an agent and its tools, that last rule matters most. A proxy that routes or applies policy on the header, while the server runs what the body says, is exactly the split the spec is trying to close.2
The previous revision was 2025-11-25.1 This post walks through the changes that affect security, logging and gateways. It skips the schema details.
Deedglass
A tool call meets your rules before it runs
Asks to run
DELETE FROM visits;
Deletes every row in visits
Deedglass checks your rules
- Reading dataAllowed
- Deleting a whole table (DROP, TRUNCATE)Never
- Changing or deleting rows without saying which (WHERE)This one
- Other changesWait for a person
The changes in one table
Each row comes from the revision’s own changelog or its Streamable HTTP page.
| Area | Before (up to 2025-11-25) | In 2026-07-28 |
|---|---|---|
| Handshake | initialize, then notifications/initialized |
None; version and capabilities in each request’s _meta1 |
| Sessions | Optional Mcp-Session-Id, ended with DELETE |
Removed; servers keep state in handles passed as tool arguments1 |
| Discovery | From the initialize result |
server/discover, which every server must implement1 |
| Server-to-client asks | Server sent its own requests (sampling, elicitation, roots) | Result with resultType: "input_required"; client retries with the answers1 |
| Result shape | No result type | Every result carries resultType1 |
| Change notifications | GET stream, resources/subscribe |
subscriptions/listen on a long-lived POST response1 |
| Broken streams | Resumable with Last-Event-ID |
Not resumable; re-issue with a new request ID1 |
| List caching | listChanged only |
tools/list results carry ttlMs and cacheScope1 |
| HTTP headers | MCP-Protocol-Version |
Plus Mcp-Method, and Mcp-Name for calls and reads2 |
| Tasks | Experimental, in core | An official extension1 |
Some things are on their way out rather than gone. Roots, Sampling and Logging are deprecated, and so is OAuth Dynamic Client Registration, in favour of Client ID Metadata Documents. Deprecated features keep a deprecation window of at least twelve months.1
Metadata on every request
Without a handshake, nothing is negotiated once and remembered. Each request says which protocol version it speaks and what the client can do.1 If the server doesn’t support that version, it answers 400 with an UnsupportedProtocolVersionError that lists the versions it does support. An unknown method gets 404 with JSON-RPC -32601. A notification it accepts gets 202 with no body.2
This is good news for anyone keeping records. A log line for one request now holds everything needed to interpret it: the version, the client’s identity if it sent one, and the call itself. Under the old model, the meaning of a tools/call could depend on a handshake that happened minutes earlier on the same session, which a log of single requests didn’t capture.
It also changes how state works. Servers that need state across calls now mint their own handles and pass them as ordinary tool arguments.1 That means the state is visible in the arguments, where a policy engine can see it, rather than hidden in a session id.
Multi Round-Trip Requests change one more thing. When a server needs the user’s input, or a model completion, it no longer sends its own request back to the client. It returns a result with resultType: "input_required", and the client retries the original request with the answers attached.1 For an approval flow, that means the same tool call can arrive twice: once without the extra input, once with it. Anything counting calls should count the final one.
Headers that must match the body
Streamable HTTP now mirrors parts of the JSON-RPC body into headers so load balancers and gateways can route without parsing JSON. Every POST carries MCP-Protocol-Version, which must equal the version in _meta, plus Mcp-Method. Calls to tools/call, resources/read and prompts/get also carry Mcp-Name.2 A name that isn’t plain ASCII travels Base64-encoded between =?base64? and ?=.2
A server that processes the body must reject a missing or mismatched header with 400 and JSON-RPC error -32020, HeaderMismatch.2 The spec gives the reason plainly: different components can rely on different sources of truth, such as a load balancer routing on the header while the server executes the body.2
Here is what the attack looks like when nobody checks:
Code A request one program sends to another over the web.
POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: list_tables
{"jsonrpc":"2.0","id":7,"method":"tools/call",
"params":{"name":"drop_table","arguments":{"table":"orders"}, "_meta":{...}}}
A gateway with a rule “allow list_tables” that reads only the header lets this through. The server runs drop_table. Under 2026-07-28 a conforming server refuses it, but only if it processes the body and checks. A gateway that makes decisions should parse the body itself, or at least confirm the two agree before it allows anything.
The spec adds a second warning for intermediaries. One that enforces policy on mirrored headers should check that MCP-Protocol-Version names a version that requires header and body validation. If the version is older or the header is missing, it should reject the request rather than trust headers nobody validated.2
Servers can also ask clients to mirror chosen tool parameters into Mcp-Param- headers, using x-mcp-header in the tool’s input schema.1 The same rule applies: a header is a copy, and the body is what runs.
What breaks for older clients
A server that only speaks 2026-07-28 will see old-style traffic for a while. The spec says it should answer GET and DELETE on the endpoint with 405, and ignore Mcp-Session-Id and Last-Event-ID.2 Clients that support both eras try a modern request first and look inside any 400 before falling back to initialize, because modern servers also use 400 for version and header errors.2
Two changes can surprise code that worked before:
- Lost streams stay lost. With resumability gone, a dropped response stream loses the in-flight request, and the client must send it again with a new request ID.1 For a tool that writes, that retry is a second write unless the tool is idempotent. Our post on agents that retried and wrote twice covers the fix.
- Session-scoped rules lose their anchor. Any gateway rule keyed on
Mcp-Session-Id, such as “this session already got approval”, needs a new key. The agent’s own identity, from authorization, is the obvious one.
The authorization changes are smaller. Authorization servers should include iss in their responses, and clients must check a present iss against the issuer they recorded before redeeming a code.1
A checklist for gateways and logs
If you run a proxy, a gateway or a logging layer in front of MCP servers, these are the checks the new revision calls for.
- Decide on the body, not the headers. Parse
params.nameandparams.arguments. Use the headers for routing only after confirming they match.2 - Reject old or missing versions where you rely on headers.2
- Decode Base64 header values before comparing.2
- Log the
_metaversion and client info with each call. Each request now carries them.1 - Count the final round of a multi round-trip request, not every attempt.1
- Make writes safe to retry. Streams no longer resume.1
- Re-key anything that used session ids.1
- Keep validating
Originand answer 403 when it is present and invalid; bind local servers to localhost.2
The basics in MCP server security still apply on top of these. What an MCP gateway does, and how the options compare, is on the comparison page.
What this post doesn’t cover
- The full schema. JSON Schema 2020-12 for tool schemas, error-code renumbering and the tasks extension’s methods are in the changelog.1
- Which clients and servers have shipped it. Adoption moves weekly; check your SDK’s release notes rather than a blog post.
- Whether a given gateway implements the header check. Test it: send a mismatched
Mcp-Nameand see whether you get 400 and-32020.
If you want to know which MCP servers your own machine is configured to run, npx deedglass scan reads the config files locally; the scan reads files on your machine and sends nothing to us.3 For tool calls themselves, a tool-call policy decides on the arguments in the body, which is where 2026-07-28 says the truth is. To try the checks without installing anything, open the playground; to grade what an agent can reach on your own machine, run npx deedglass scan (the grade, explained).
Written with AI assistance and checked against our claims register.