# Stateless MCP: What the 2026-07-28 specification changes for security

> Source: <https://equixly.com/blog/2026/08/05/stateless-mcp/>
> Published: 2026-08-05 08:00:00+00:00

# Stateless MCP: What the 2026-07-28 specification changes for security

##### Zoran Gorgiev, Alessio Dalla Piazza

## Table of contents

A protocol revision rarely makes front-page news. But the latest MCP update rightly earns our full attention.

On 28 July 2026, the Model Context Protocol published its [2026-07-28 specification](https://blog.modelcontextprotocol.io/posts/2026-07-28/). It is the largest revision since the protocol was launched.

The headline is that **MCP is now stateless**. In addition, the specification brings:

- A redesign of interactive requests
- Mandatory routing headers
- Cacheable capability listings
- A formal extensions framework
- Hardened authorization

Each of these solves a genuine operational problem. However, each also changes the attack surface.

## MCP 2026-07-28: Key changes at a glance

Change |
Developer impact |
Security note |
|---|---|---|
Stateless protocol |
No sessions, sticky routing, or shared session store | Protect explicit state handles |
`server/discover` |
Replaces capability discovery during initialization | Review exposed capabilities |
Multi-round-trip requests |
Enables approvals without persistent connections | Sign and expire `requestState` |
No stream resumability |
Interrupted calls must be retried | Prevent duplicate side effects |
Routing headers |
Gateways can route and authorize by tool | Reject header/body mismatches |
Parameter headers |
Selected arguments can reach edge infrastructure | Enforce strict header validation |
Cacheable listings |
Reduces requests and token usage | Limit stale or poisoned metadata |
Authorization updates |
Stronger OAuth issuer and client checks | Test identity and credential binding |
Deprecations |
Older features and HTTP+SSE require migration | Watch for downgrade paths |

## The MCP session is gone

Before this release, **MCP was a stateful protocol**. Every exchange between Claude Code, an IDE assistant, an agent framework, or any other MCP client and an MCP server opened with an `initialize`

handshake. Also, over HTTP, it typically carried an `Mcp-Session-Id`

header.

This session ID pinned a client session to whichever server instance answered first. Running a remote MCP server therefore meant:

- Sticky sessions
- Session affinity at the load balancer
- A shared store for session state

But often, all three. **That operational complexity was a large part of why a remote server was harder to run than it looked.**

**The new revision removes the handshake and the session header.** Each request now stands alone, carrying its protocol version and client capabilities in `_meta`

, along with client identity.

A client that wants server capabilities up front can call the new `server/discover`

RPC. Calling it is optional. However, implementing it is not; every 2026-07-28 server must implement it now.

But why does this matter?

A stateless MCP server is an ordinary HTTP workload. Any request can land on any server instance behind a plain round-robin load balancer. There is no persistent session, session affinity, and shared storage. That means serverless and edge deployment, horizontal scaling, and a **sharp drop in the cost of running a remote MCP server**.

Long-lived streams have not vanished entirely. Change notifications now travel over a `subscriptions/listen`

stream that clients opt into per notification type. But nothing in the request path depends on one.

State itself does not vanish, however. The recommended pattern is for a tool to mint an explicit handle and have the model pass it back as an argument on a subsequent request. That is cleaner than session state hidden in the transport layer. But it carries an implication worth noting: **a capability reference now travels through model context, visible to the model and to anything that can influence the model’s input.**

## MCP interactivity without a persistent connection

Over HTTP, server-initiated requests (elicitation, sampling, and roots) used to require a held-open stream that the server could push down.

**Multi Round-Trip Requests (MRTR) replace them.** When a tool needs something mid-call, such as a confirmation or a missing parameter, the server answers with `resultType: “input_required”`

and the questions it needs resolved. The client then reissues the original call with the answers attached in `inputResponses`

.

**That is big because approval flows now work on a stateless server that holds no connection at all.** A tool can check with a person before doing something irreversible.

Note the shift, though: **the approval arrives as data inside a subsequent request rather than over a live SSE connection.**

One implementation note: the `requestState`

a server attaches to an `input_required`

result round-trips through the client. That makes it attacker-controlled input, so you must integrity-protect it, bind it to the principal and the originating request, and give it an expiry before letting it influence authorization.

Stream resumability is also gone. `Last-Event-ID`

and SSE event IDs have been removed, so a broken response stream loses the in-flight request. That means the client must reissue it as a new request with a new ID.

The core protocol defines no idempotency key. Whether that retry duplicates a payment, a deployment, a message, or a deletion depends entirely on whether the tool underneath was written to notice.

## MCP tool routing moves into the headers

Streamable HTTP requests must now carry `MCP-Protocol-Version`

(which has to match the value in the body’s `_meta`

) and `Mcp-Method`

. Calls that name a target — meaning `tools/call`

, `resources/read`

, and `prompts/get`

— also carry `Mcp-Name`

.

The invoked method and the tool it targets are both visible in the HTTP headers. Thus, an MCP gateway, rate limiter, or WAF can route, meter, and authorize without parsing the JSON-RPC body.

This change matters tremendously because **per-tool policy becomes practical at the edge**. The specification anticipates the obvious risk: a server that processes the body must reject a header that disagrees with it, returning `400 Bad Request`

and JSON-RPC error `-32020, HeaderMismatch`

.

So the surface worth testing is not whether header and body can disagree, but **whether the implementation performs that comparison at all, and the downgrade path beneath it**.

An intermediary enforcing policy on mirrored headers should confirm that the declared protocol version is one that requires header/body validation and reject the request otherwise. An old or absent version header means a gateway trusting values that nobody checked.

Tool parameters can reach the headers too. A server may annotate a parameter in its tool schema with `x-mcp-header`

, and a conforming HTTP client mirrors that argument’s value into an `Mcp-Param-{Name}`

header.

The specification fences this tightly:

- Header names must be valid HTTP tokens
- Values must be simple types
- Non-ASCII characters must be base64-encoded
- Carriage returns and newlines are banned outright
- A client must refuse any tool definition that breaks these rules

That is the fencing you would expect regarding a feature that moves data from a request body into an HTTP header, since a stray newline in a header value splits it into a second header.

**Note where the trust sits.** The server’s schema decides which parameter becomes policy-visible metadata, the value comes from the call arguments, and the client emits the header. A gateway metering on `Mcp-Param-*`

is applying policy to a field the server it polices chose to expose.

## MCP capability listings become cacheable

Responses to `tools/list`

, `prompts/list`

, `resources/list`

, `resources/templates/list`

, and `resources/read`

now carry `ttlMs`

and `cacheScope`

.

Separately, servers should return tools in a deterministic order. A client can cache the catalog of available tools instead of refetching it, and upstream prompt caches stay stable across reconnects.

**The result is fewer round trips and lower token cost.**

Remember that a tool definition is not inert. A server advertises each tool with a description and a JSON Schema for its inputs, and both feed the model’s choice of which tool to call and how. Anything cacheable is therefore worth understanding in terms of how long a bad value survives and how widely `cacheScope`

shares it.

## MCP extensions, SDKs, and authorization

Extensions are now a governed framework instead of an informal convention, with Tasks joining MCP Apps, Enterprise Managed Authorization, and OAuth Client Credentials. Tasks leaves the experimental core and gains a proper life cycle for long-running work.

Authorization moves closer to production OAuth practice:

`iss`

validation per[RFC 9207](https://datatracker.ietf.org/doc/html/rfc9207)before a code is redeemed- Client credentials bound to the issuer that minted them
- Dynamic Client Registration deprecated in favor of Client ID Metadata Documents

Roots, Sampling, and Logging are deprecated, each with at least twelve months of runway, as is the legacy HTTP+SSE transport. The Tier 1 MCP SDKs (TypeScript, Python, Go, and C#) speak the new specification today.

## What the 2026-07-28 specification means for MCP security testing

The new specification brings changes highly relevant to security testing:

- Where state lives
- How a server asks a person for confirmation
- What a gateway can see without opening a message

Each of those is a new attack surface, and each is new enough that nobody has much experience getting it wrong yet. That alone is worth testing for.

What the new specification does not change, however, is the layer underneath. An [MCP server exposes](https://equixly.com/blog/2026/02/12/how-mcp-servers-challenge-traditional-api-security-models/) existing functionality, such as an API, a database, or a filesystem, through a new interface. And our assessment of popular MCP implementations found that little hardening is added at that boundary. [Testing MCP servers](https://equixly.com/blog/2025/03/29/mcp-server-new-security-nightmare/), **we found ordinary vulnerability classes, like command injection and path traversal, not protocol flaws**.

So a migration to the new specification leaves you with both: **everything behind the interface that was never hardened in the first place, and a rebuilt interface that has never been exercised adversarially**.

Equixly already tests for the first and now supports the second, too: MCP servers running 2026-07-28. Its [agentic AI system](https://equixly.com/blog/2025/09/28/ai-agents-vs-agentic-ai/):

- Connects to your MCP server the way any AI client would
- Enumerates the tools and resources it exposes
- Attacks them as an adversary would, chaining calls, probing parameter combinations, and following each tool through to the system beneath it

The transport has changed. What we look for has not.

*Migrating an MCP server to the new specification?
*

[Talk to us](https://equixly.com/contact-us/)about testing it before it ships.

## FAQs

### Is MCP still stateful?

No, the 2026-07-28 specification removes the initialize handshake and the Mcp-Session-Id header. So, every request carries its own protocol version and capabilities, along with client identity, and a request can be served by any instance.

### When do I need to migrate my MCP server?

Now, if you want to serve 2026-07-28 clients. The initialize handshake and Mcp-Session-Id are gone, not deprecated. Older clients keep working only if you run the old path alongside the new one. The twelve-month runway you may have heard about covers Roots, Sampling, and Logging, which stay in the spec until at least July 2027.

### Does a stateless MCP server make my deployment more secure?

No, statelessness changes where authorization happens and how you deploy the server. However, the vulnerabilities we find in MCP servers sit in the functionality they expose, which the specification does not touch.

[
]

#### Zoran Gorgiev

##### Technical Content Specialist

Zoran is a technical content specialist with SEO mastery and practical cybersecurity and web technologies knowledge. He has rich international experience in content and product marketing, helping both small companies and large corporations implement effective content strategies and attain their marketing objectives. He applies his philosophical background to his writing to create intellectually stimulating content. Zoran is an avid learner who believes in continuous learning and never-ending skill polishing.

[
]

#### Alessio Dalla Piazza

##### CTO & FOUNDER

Former Founder & CTO of CYS4, he embarked on active digital surveillance work in 2014, collaborating with global and local law enforcement to combat terrorism and organized crime. He designed and utilized advanced eavesdropping technologies, identifying Zero-days in products like Skype, VMware, Safari, Docker, and IBM WebSphere. In June 2016, he transitioned to a research role at an international firm, where he crafted tools for automated offensive security and vulnerability detection. He discovered multiple vulnerabilities that, if exploited, would grant complete control. His expertise served the banking, insurance, and industrial sectors through Red Team operations, Incident Management, and Advanced Training, enhancing client security.
