Research · MCP 2026-07-28 · detection after the session
Stateless. Not Traceless.
The largest revision since the protocol launched does not add a feature — it removes a primitive. The session was load-bearing for something the spec authors were never obligated to care about: detection.
The correlation key is gone.
MCP is now stateless at the protocol layer. The initialize handshake is retired under SEP-2575 and the Mcp-Session-Id header under SEP-2567. A request carries its own protocol version, client identity and capabilities in _meta, and any request can land on any server instance behind an ordinary round-robin load balancer.
Operationally this is unambiguously good. Sticky routing is gone, shared session stores are gone, a server restart no longer detonates every in-flight conversation. The cost lands somewhere the release notes do not look.
The last row is the problem. Behavioural detection needs a unit of analysis. You cannot baseline normal for a single isolated request any more than a network IDS can baseline a single packet. Sequence is the signal: this agent called list_files, then read_file eleven times, then send_email. The individual calls are all legitimate. The shape is the attack.
Strip the session and you are left with a stream of self-describing requests that a load balancer has deliberately scattered across instances. The scatter is the point of the release. It is also why no single instance now sees enough of a sequence to have an opinion about it.
Where the anchor moved.
The anchor did not vanish; it relocated. Two candidates ship in the spec. The first is _meta, carrying client info on every request. The second is W3C Trace Context, formally documented under SEP-414, which reserves traceparent, tracestate and baggage so a trace can be stitched across SDK, gateway, server and whatever the server calls downstream.
Trace Context is the better of the two, and its standardisation is quietly the most useful security change in the release — a defensible span tree where you previously had a session ID and hope. But note the asymmetry against what you had before.
An attacker driving a compromised or hostile client controls its own correlation identifier. It can rotate traceparent per call and shatter its own sequence into singleton spans, each individually unremarkable. It can reuse a victim's trace ID and graft its calls onto someone else's legitimate span tree. Neither move requires a vulnerability — both are the protocol working exactly as specified.
The mitigation is not to trust the field. Derive a server-side correlation identity from properties the client does not unilaterally control — authenticated principal, resolved token subject, source characteristics, tool-call causality reconstructed from argument dataflow — and treat client-supplied traceparent as a hint that must agree with the derived identity, never as the identity itself. Disagreement between the two is itself a high-quality signal, and one that did not exist before this release.
That is a design change in MST's MCP audit module, not a config flag, and it is the main reason this release warrants a threat model rather than a changelog entry.
The maintainers already conceded the point.
If you want confirmation that removing the session broke something structural rather than merely inconvenient, it is in the Tasks extension. When Tasks graduated out of the experimental core, tasks/list was not migrated — it was removed, on the stated grounds that it cannot be scoped safely without sessions.
That is the authorization consequence of statelessness, admitted in the spec itself. A listing endpoint needs to know whose things to list. The session used to answer that. With the session gone, the maintainers concluded no safe answer remained and dropped the endpoint.
Read that carefully if you operate an MCP server with any other listing or enumeration surface — because the same reasoning applies to yours, and nobody removed yours for you.
State you handed to the attacker.
A stateless protocol still needs mid-call interaction. Multi Round-Trip Requests (SEP-2322) rebuild that flow. Rather than holding a stream open, the server returns a result of type input_required with a set of input requests; the client collects the answers and re-issues the original call with the responses attached, plus a verbatim echo of a field called requestState.
That field is how any instance picks the call back up. Everything the server needs to resume is in the payload the client sends back. In the specification's own worked example it is a base64 string — decode it and you get a small JSON object holding the step index and the file list the operation was working on.
Base64 is not a security boundary. It is an encoding. What we have is server-authored state, round-tripped through an untrusted client, and resumed by a server instance that may never have seen the original request. The spec does not mandate that this blob be authenticated.
Tampering.
Decode, mutate the step index or the operand list, re-encode, return. A confirmation gate that ran at step 1 does not re-run when the resumed state claims step 3. This is the agentic equivalent of a client-side price field.
Replay.
Nothing in the round-trip model inherently requires the state to be single-use. A captured requestState plus a captured approval response is a reusable approval — and carrying approvals for consequential actions is the entire reason the mechanism exists.
Cross-instance confusion.
Any instance resumes it. That is the feature. It also means an instance with a different configuration, a different policy version, or a stale deployment resumes it.
Deserialization.
If the server hydrates that blob into a language-level object rather than parsing it into a validated schema, the failure mode is not information disclosure.
The NSA's Artificial Intelligence Security Center flagged serialization risks and trust boundaries as core MCP concerns in its May 2026 information sheet, before the final spec landed. This mechanism is where those two concerns intersect in the protocol text itself.
For auditors this is a clean, testable finding with a deterministic check: flip one bit in the blob and see whether the server notices.
The header says one thing, the body says another.
SEP-2243 makes Mcp-Method and Mcp-Name mandatory on Streamable HTTP, so that gateways, rate limiters and WAFs can route, meter and authorize on headers instead of parsing JSON bodies. The spec anticipates the obvious problem and requires servers to reject requests where headers and body disagree.
That requirement binds the server. Every hop in front of it — reverse proxy, API gateway, WAF, rate limiter, cache, access log, metrics pipeline, the SIEM ingesting all of the above — now makes decisions on a header it does not verify against a body it does not read.
If you have worked HTTP request smuggling you already know the shape. Two parsers, one message, disagreeing about what it says. The classic version exploits content-length against transfer-encoding. This one has a cleaner primitive, because the spec explicitly encourages the front end to route on metadata and the back end to act on content.
A conformant server will reject a read-only method in the headers wrapping a privileged call in the body. The question worth auditing is what the seven components in front of that server did with it on the way past. Did the WAF apply its permissive read-only ruleset? Did the rate limiter charge it against a cheap bucket? Did the gateway's authorization policy grant it on the header claim? Does the access log now hold a permanent record of an operation that never happened — and does your detection pipeline consume that log?
Even against a fully conformant server, header-body disagreement is a log poisoning and detection-evasion primitive. Your telemetry describes a call the server rejected, and your telemetry is what an investigation reads afterward. Conformance is also doing heavy lifting in that sentence: four Tier 1 SDKs shipped on day one, the wider ecosystem of hand-rolled servers did not, and the mismatch check is exactly the kind of validation an implementer under deadline defers.
Audit position: assert agreement at the outermost hop that can see both, not only at the origin. Log both values on disagreement. Alert on the delta, because there is no benign reason for a well-behaved client to produce one.
Poison with a TTL.
Tool poisoning we covered in Hunting MCP Tool Poisoning: an agent treats tool descriptions as authoritative instructions, nothing binds the description you audited at install time to the one served at runtime, and the poisoned text is invisible in the UI while fully visible to the model.
SEP-2549 adds ttlMs and cacheScope to listing and read results. Clients learn how long a catalogue stays fresh and whether it is safe to share across users. It is modelled on HTTP cache-control, which means it inherits the entire cache-poisoning literature that came with it.
Before, a poisoned description reached the agents that fetched it and expired with the connection. Blast radius: one session, one client. After, it is deliberately retained for a server-declared duration and, at the wrong scope, deliberately shared between users.
The attacker no longer needs to win the race on every fetch. They need to win it once, and the caching layer distributes and persists the payload on their behalf for as long as the TTL says. A rug-pull — clean descriptions during review, poisoned ones after — now has a persistence mechanism built into the protocol. This is the same check-then-change shape treated as a class in Checked, Then Changed.
The controls follow directly. Never accept cacheScope at face value from a server you do not operate; a shared scope on a catalogue containing per-user or tenant-scoped tools is a finding on its own. Cap ttlMs client-side rather than honouring arbitrary server-declared lifetimes. Hash every catalogue on fetch and diff against the reviewed baseline, because a cached catalogue that silently changed content mid-TTL is the exact signature of a rug-pull. Purge on principal change.
One adjacent note from the same release: tool schemas are lifted to full JSON Schema 2020-12 under SEP-2106, bringing composition, conditionals and references. The spec instructs implementations not to auto-dereference external reference URIs and to bound schema depth and validation time. Both instructions exist because the alternatives are outbound fetch on an attacker-controlled URI and algorithmic denial of service. When a specification tells you not to do something, that is a map of what the ecosystem will do anyway.
What changes in MST.
Two checks carry an MST-local tag rather than an ASI number: the observability category present in the draft Agentic Top 10 did not survive to release, and taking a number that now means something else would misfile the finding.
That last row deserves its own sentence. The new deprecation policy guarantees a minimum twelve-month window before anything deprecated can be removed, and legacy registration remains functional alongside the new model for backward compatibility. This is good governance and correct protocol design. It also guarantees a year in which every server that supports the new model very likely still speaks the old one — and downgrade is the cheapest attack in any protocol transition.