Skip to content
All articles
MCPAI IntegrationClaudeArchitecture

MCP's 2026-07-28 Spec: What Stateless Means for Your Server

The biggest Model Context Protocol update since launch removes sessions and the initialize handshake. What changed, what is deprecated, and a migration checklist.

Usama Munawar4 min read

What changed

The 2026-07-28 revision of the Model Context Protocol is the largest since the protocol launched. The headline: MCP is now stateless. There is no session handshake and no session id, so an MCP server behaves much more like an ordinary HTTP API and scales like one.

It replaces the 2025-11-25 revision. The four Tier-1 SDKs (TypeScript, Python, Go and C#) already support it. If you run an MCP server, or connect agents to one, this is what changes.

The big changes, in plain terms

1. No sessions

Protocol-level sessions and the Mcp-Session-Id header are gone from the Streamable HTTP transport. The list endpoints (tools/list, resources/list, prompts/list) no longer vary per connection. If your server needs state across calls, it now hands out explicit, server-minted handles that the client passes back as ordinary tool arguments. State becomes something you design on purpose, not something hidden in the connection.

2. No initialize handshake

The initialize and notifications/initialized exchange is removed. Every request carries its protocol version and client capabilities in _meta:

  • io.modelcontextprotocol/protocolVersion
  • io.modelcontextprotocol/clientCapabilities

Clients should also send clientInfo, and servers should identify themselves in each result's _meta. A version mismatch returns UnsupportedProtocolVersionError.

Servers must implement a new server/discover call that advertises supported protocol versions, capabilities and identity. Clients can call it first to pick a version.

3. Multi Round-Trip Requests

Servers used to send their own requests mid-call (roots/list, sampling/createMessage, elicitation/create). That needed a live bidirectional connection, which is exactly what stateless servers do not have. The replacement is Multi Round-Trip Requests: the server returns an InputRequiredResult (resultType: "input_required") describing what it needs, and the client retries the original request with inputResponses. Every result now carries a required resultType field, "complete" for ordinary results.

4. Subscriptions and streams

resources/subscribe and the HTTP GET endpoint are replaced by a single subscriptions/listen stream, where clients opt in to specific change notifications. SSE stream resumability (Last-Event-ID) is removed: if a response stream breaks, the client re-issues the request with a new request id.

5. Caching and routing

  • Results from the list and read calls must now include ttlMs (a freshness hint) and cacheScope (public or private), so clients can cache instead of polling.
  • Servers should return tools in a deterministic order, which also helps LLM prompt caching.
  • Streamable HTTP POST requests must carry Mcp-Method and Mcp-Name headers, so gateways and load balancers can route without parsing bodies.

6. Auth and schema

  • Authorization servers should include the iss parameter (RFC 9207), and clients must validate it before redeeming a code.
  • Client credentials are bound to the issuer that created them.
  • Dynamic Client Registration (RFC 7591) is deprecated in favour of Client ID Metadata Documents.
  • Tool inputSchema and outputSchema now accept any JSON Schema 2020-12 keywords.

7. Extensions and deprecations

Tasks (long-running work) moved out of the core into an official extension, io.modelcontextprotocol/tasks. Roots, Sampling and Logging are deprecated, along with the old HTTP+SSE transport. Deprecated features stay for at least twelve months under the new lifecycle policy. Suggested replacements: pass paths through tool parameters instead of Roots, call your LLM provider directly instead of Sampling, and log to stderr or OpenTelemetry instead of the Logging feature.

Old and new at a glance

Before (2025-11-25)Now (2026-07-28)
Session id header, per-connection stateNo sessions; explicit handles in tool arguments
initialize handshakeVersion and capabilities in _meta on every request
Server-initiated requestsMulti Round-Trip Requests (input_required)
resources/subscribe, GET streamsubscriptions/listen
Experimental tasks in coreTasks extension
Sampling, Roots, LoggingDeprecated

Migration checklist for server authors

  1. Upgrade your SDK to a release that supports 2026-07-28, and keep answering older clients while they catch up.
  2. Remove session assumptions. Anything stored per connection (a cursor, a cart, an open file) needs an explicit handle that you issue and the client returns.
  3. Implement server/discover.
  4. Replace server-initiated requests with the multi round-trip pattern.
  5. Add ttlMs and cacheScope to list and read results, and make tool order deterministic.
  6. Re-check authorization: issuer validation, the issuer-bound client credentials, and a Client ID Metadata Document if you register clients.
  7. Stop using Sampling, Roots and Logging in new code.
  8. Test with a real client, then with an old one.

What this means in practice

Stateless servers are easier to run: any instance can answer any request, so you can put them behind a normal load balancer, scale them horizontally and deploy without draining sessions. The cost is that state is now your job. For a Laravel server, laravel/mcp already speaks this revision; I walk through building one in Laravel MCP server. For agents that also use phone lines, see AI voice agents on Asterisk.

Need an MCP server built or migrated?

See AI integration, or email devusamaworks@gmail.com or WhatsApp +92 303 8004684 for a free 30-minute call.

A question about this article?Ask me on WhatsApp

Keep reading

Open for new work

Have a system that needs to scale?

Bring your architecture problem, automation bottleneck, or product idea. We will work out the right engineering path before you spend more time or money.

Free, 30 minutes, no pitch. You leave with a next step either way.