MCP 2026-07-28 Explained: The Stateless Core, server/discover, and Who's Already Compliant
MCP 2026-07-28 replaces initialize and Mcp-Session-Id with a stateless server/discover core — Hugging Face and Cloudflare comply, DeepWiki still runs legacy.
The Model Context Protocol shipped its largest specification change since launch on 2026-07-28, superseding the previous revision from 2025-11-25. The headline change: MCP is no longer a stateful, session-based protocol. The initialize handshake and the Mcp-Session-Id header — the mechanism every MCP server has used since the protocol's earliest versions — are gone from the core spec, replaced by a fully stateless model built around a new mandatory RPC, server/discover.
This isn't a cosmetic revision. It changes how a client identifies itself, how servers advertise capabilities, how server-initiated interactions like sampling and elicitation work, and which authentication mechanisms are considered current. Here's what actually changed, what's deprecated, and — since a spec change on paper isn't the same as adoption in production — which real MCP servers already speak the new revision.
The Core Change: No More Sessions
Every prior MCP revision worked the same way: a client opened a connection, sent initialize with its protocol version and capabilities, the server replied with serverInfo and its own capabilities, the client sent notifications/initialized, and every subsequent request on that connection was implicitly scoped to that negotiated session — often tracked via an Mcp-Session-Id header.
The 2026-07-28 revision removes all of that. There is no handshake. Every single request now carries its own protocol version and capabilities via a _meta object:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": { "location": "Seattle, WA" },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" },
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}
A server that needs cross-call state — a long-running task, a multi-step form — no longer relies on a session to hold it. It mints an explicit handle and passes it back as an ordinary tool argument on the next call. The spec is explicit about the implication: an open connection, including a stdio process, is not a conversation. A client can interleave unrelated requests on the same transport, and a server must never treat connection identity as a proxy for session continuity.
The practical upside, spelled out directly in the spec: any request can land on any server instance behind a plain round-robin load balancer, with no shared session store required.
server/discover Replaces the Handshake
Since there's no initialize to learn a server's supported versions and capabilities, servers now must implement a new RPC: server/discover. It's stateless, takes no meaningful parameters beyond the standard _meta, and returns exactly what a client used to learn from initialize:
{
"jsonrpc": "2.0",
"id": "discover-1",
"result": {
"resultType": "complete",
"supportedVersions": ["2026-07-28"],
"capabilities": { "tools": {}, "resources": {} },
"_meta": {
"io.modelcontextprotocol/serverInfo": { "name": "ExampleServer", "version": "1.0.0" }
},
"instructions": "This server provides weather and resource utilities."
}
}
Calling it first is optional for a client — any request can be sent inline, and a mismatched protocol version comes back as an UnsupportedProtocolVersionError listing what the server actually supports, at which point the client retries with a mutually agreeable version. But server/discover is the only reliable way to identify a server's era before committing to a request shape, which is exactly why it matters for anything doing external detection, monitoring, or compatibility probing.
Multi Round-Trip Requests Replace Server-Initiated Calls
The other structural change is how a server asks a client for more information mid-request — previously done via server-initiated roots/list, sampling/createMessage, or elicitation/create calls sent over an open stream. Streams are no longer guaranteed to stay open, so that pattern is gone too.
In its place: Multi Round-Trip Requests (MRTR). A server that needs input responds with resultType: "input_required" instead of a final result, listing the sub-requests it needs answered in inputRequests. The client gathers the answers and retries the original request — same method, new JSON-RPC id — with the answers in inputResponses. An opaque requestState string carries whatever context the server needs to resume, and the spec requires servers to integrity-protect it (HMAC or AEAD) since it round-trips through a client that must be treated as untrusted.
This only applies to three client-initiated calls: tools/call, resources/read, and prompts/get. Nothing else in the core protocol is allowed to return input_required.
What's Deprecated
The spec introduces a formal feature-lifecycle policy alongside this release — a minimum 12-month deprecation window before anything can actually be removed:
| Feature | Deprecated in | Migration | Earliest removal |
|---|---|---|---|
| Roots | 2026-07-28 | Pass paths via tool parameters, resource URIs, or config | 2027-07-28 |
| Sampling | 2026-07-28 | Integrate directly with an LLM provider API | 2027-07-28 |
| Logging | 2026-07-28 | Log to stderr (stdio) or use OpenTelemetry | 2027-07-28 |
| Dynamic Client Registration (RFC 7591) | 2026-07-28 | Client ID Metadata Documents | 2027-07-28 |
| HTTP+SSE transport (2024-11-05) | 2025-03-26 | Streamable HTTP | Sooner — 3 months after its own deprecation SEP finalizes |
Everything in that table still works today. The point of the table is planning, not urgency — a server built last month on 2025-11-25 isn't broken, it's just no longer the current revision.
The Dynamic Client Registration → Client ID Metadata Documents (CIMD) shift is worth a second look if your server sits behind OAuth. CIMD lets a client use an HTTPS URL as its client_id — the authorization server fetches that URL, reads client_name and redirect_uris from it, and validates the request without any registration round-trip. An authorization server advertises support with "client_id_metadata_document_supported": true in its metadata; if that's absent and only registration_endpoint (DCR) is present, you're on the mechanism the spec is actively moving away from.
Error Codes and Auth Hardening
A few smaller but real changes:
- The resource-not-found error code moved from
-32002to-32602to align with plain JSON-RPC semantics. Three new codes are allocated in the spec-reserved range:-32020(HeaderMismatch),-32021(MissingRequiredClientCapability),-32022(UnsupportedProtocolVersion). - Authorization responses should now include the
issparameter (RFC 9207), and clients must validate it against the recorded issuer before redeeming an authorization code — a defense against mix-up attacks between authorization servers. tools/listand other list endpoints now carryttlMsandcacheScopefields (the newCacheableResultinterface), letting clients cache results and reduce polling instead of re-fetching the same tool list on every connection.tools/listshould now return tools in a deterministic order — a small change, but a real one for anything relying on LLM prompt-cache hit rates against a stable tool list.
Who's Already Compliant
Spec revisions are one thing; production adoption is another. We ran the same probe against several public MCP servers to see who has actually shipped server/discover:
- Hugging Face (
huggingface.co/mcp) — responds toserver/discoverand reports2026-07-28as its negotiated version. Fully modern. - Cloudflare Docs (
docs.mcp.cloudflare.com/mcp) — same result. Fully modern, days after the spec shipped. - DeepWiki (
mcp.deepwiki.com/mcp) — no response toserver/discover; falls back to the legacyinitializehandshake, negotiating2025-06-18. Still fully functional, just not yet migrated. - GitHub Copilot (
api.githubcopilot.com/mcp) — returns a401with aWWW-Authenticatechallenge before any protocol negotiation happens at all. Its stateless-core status isn't observable from the outside without completing the OAuth flow first — a useful reminder that auth-gated servers are harder to audit for spec compliance than open ones.
Two adopters within days of the spec shipping is a fast start for a breaking change of this size, but it also means most of the MCP ecosystem is still on 2025-06-18 or 2025-11-25 right now — both fine, both fully supported, neither urgent to change today.
Checklist for Server Operators
- Implement
server/discover— it's a MUST for the current revision, and it's the only clean way for anything doing external compatibility checks to identify your server without guessing. - Drop any reliance on
Mcp-Session-Idor connection-scoped state; move it into explicit handles passed as tool arguments. - If your server does sampling, elicitation, or reads roots — migrate to the MRTR pattern (
input_requiredresults) rather than server-initiated requests over an open stream. - Add
ttlMs/cacheScopeto yourtools/list,resources/list, andprompts/listresponses. - If you're behind OAuth, check whether your authorization server advertises
client_id_metadata_document_supported— if it only offersregistration_endpoint, you're on the deprecated path.
You can check where any MCP server actually stands — modern or legacy, which protocol version it negotiates, whether it still advertises deprecated capabilities like logging, and whether its authorization server has moved to Client ID Metadata Documents — with the MCP Inspector in one scan.
Follow Trango Compute on LinkedIn
We post updates on new tools, context engineering patterns, and LLM cost research.