createmcps.com

Spec explainer

What changed in MCP spec 2026-07-28

Last verified: 10 August 2026 · spec 2026-07-28 · ruleset 1.4.2

2026-07-28 is the largest revision since MCP launched. It removed protocol-level sessions and the initialize handshake, made Mcp-Method and Mcp-Name required headers, added ttlMs and cacheScope to cacheable results, replaced server-initiated requests with a retry pattern, and retired several methods.

The six changes that matter most

  • Stateless core. No sessions, no Mcp-Session-Id, no initialize.
  • Required headers. MCP-Protocol-Version, Mcp-Method, Mcp-Name — and they must match the body.
  • Caching metadata. ttlMs and cacheScope required on five result types.
  • resultType on every result. "complete", or "input_required" for MRTR.
  • MRTR replaces server-initiated requests. The server asks for input by returning it, not by sending its own request.
  • Methods retired. ping, logging/setLevel, resources/subscribe, the GET stream.
This page is the reference — what changed. For how to move a working server across, with before/after code for each change, use the migration guide.

Every change, by area

The rule counts below are live from our catalogue — 79 rules across these eleven areas, each traced where possible to the spec sentence it comes from.

AreaWhat changedRules
Stateless coreSTLProtocol-level sessions, the Mcp-Session-Id header, and the initialize / notifications/initialized handshake were removed. Context now travels per-request in _meta.8
Required headersHDRMCP-Protocol-Version on every POST, Mcp-Method on every request, Mcp-Name on tools/call, resources/read and prompts/get. Header values must match the body.10
Caching metadataCACttlMs and cacheScope became required on five result types via a new CacheableResult interface.5
Result shape and MRTRRESEvery result carries a resultType. Server-initiated requests were replaced by Multi Round-Trip Requests: the server returns input_required and the client retries the original call.7
Error codesERRThe server-error range was partitioned. -32020 HeaderMismatch, -32021 MissingRequiredClientCapability and -32022 UnsupportedProtocolVersion were added; -32002 and -32042 were retired.8
DiscoveryDSCserver/discover became mandatory, advertising supported protocol versions, capabilities and identity without a handshake. Extensions use reverse-DNS identifiers.5
Authorization hardeningAUTRFC 9728 Protected Resource Metadata became mandatory; RFC 9207 iss support is advertised through authorization server metadata; Client ID Metadata Documents supersede Dynamic Client Registration.11
Schema constraintsSCHThe x-mcp-header extension lets tools promote primitive parameters into HTTP headers, with strict constraints on naming, uniqueness, type and reachability.7
Security requirementsSECOrigin validation against DNS rebinding, HTTPS for OAuth URLs, icon URI restrictions, and a ban on dereferencing $ref values that resolve to network URIs.7
Deprecated and removedDEPping, logging/setLevel, the HTTP GET stream, and resources/subscribe were removed. Roots, Sampling and Logging entered a formal 12-month deprecation window.7
RegistryREGserver.json validation, verifiable namespace ownership, semver-recommended versions, and a requirement that a declared remote endpoint is reachable at its stated URL.4

What was removed outright

Make MCP stateless: remove the initialize/notifications/initialized handshake.
MCP-STL-003 MUST · spec 2026-07-28
Remove ping, logging/setLevel, and notifications/roots/list_changed.
MCP-DEP-001 MAY · spec 2026-07-28
Replace the HTTP GET endpoint and resources/subscribe/resources/unsubscribe with subscriptions/listen: a single long-lived POST-response stream for opted-in server-to-client change notifications.
MCP-DEP-003 MAY · spec 2026-07-28

Removed is not the same as deprecated, and the revision does both. Roots, Sampling and Logging were deprecated — still functional, under a formal window:

Deprecate the Roots, Sampling, and Logging features. These features remain fully functional during the deprecation window but new implementations should not add support for them.
MCP-DEP-005 MAY · spec 2026-07-28
New implementations SHOULD NOT adopt it; existing implementations SHOULD migrate to Streamable HTTP.
MCP-DEP-004 SHOULD_NOT · spec 2026-07-28

The 12-month minimum deprecation window is itself new. Before this revision MCP had no stated lifecycle policy, so “deprecated” carried no promise about when something would stop working.

New and retired error codes

The partitioned server-error range
-32000 … -32019   legacy  — do not allocate new codes here
-32020 … -32099   reserved by the specification

  NEW in 2026-07-28
  -32020  HeaderMismatch
  -32021  MissingRequiredClientCapability
  -32022  UnsupportedProtocolVersion

  RETIRED — MUST NOT be emitted
  -32002  resource not found     → use -32602 (Invalid params)
  -32042  URL elicitation        → 2025-11-25 only
-32002 — resource not found (2025-11-25 and earlier; replaced by -32602). Implementations of this protocol version MUST NOT emit these codes.
MCP-ERR-003 MUST_NOT · spec 2026-07-28
Implementations MUST NOT emit any code from this sub-range that is not defined by this specification and MUST use defined codes only with their specified meanings.
MCP-ERR-005 MUST_NOT · spec 2026-07-28

MCP-ERR-005 is the one that catches homegrown codes. Picking an unused number in the -32020-32099 range for your own error was reasonable before this revision and is a conformance failure after it — that range now belongs to the specification.

Is it a breaking change?

Yes, in both directions, and the spec addresses that directly rather than leaving it to implementers:

A server that wishes to support both legacy clients and modern clients MAY implement both behaviors.
MCP-DEP-006 MAY · spec 2026-07-28
A server that supports only modern versions SHOULD name the protocol versions it supports in any error it returns to an initialize request.
MCP-DEP-007 SHOULD · spec 2026-07-28

A dual-era server chooses its behaviour from how the request arrives: modern per-request _meta means stateless handling, an initialize request means legacy session semantics for that connection. If you only support modern versions, naming them in the error you return to initialize matters more than it looks — legacy clients have no fall-forward mechanism, so that message may be the only diagnostic a user ever sees.

What to fix first

Ordered by what unblocks the most downstream work, not by how the spec is organised:

  • Statelessness. Every other change assumes it. A server that still requires initialize fails a modern client's very first request, so nothing else you fix is observable until this is done.
  • Required headers. Cheap, mechanical, and the second most common cause of a modern client failing.
  • resultType and caching metadata. Purely additive — a few lines per handler, and clients treat an absent resultType from an older server as "complete".
  • Error codes. Renumber -32002 to -32602, stop emitting -32042, and vacate the reserved range.
  • Retired methods and authorization. Delete what is gone, then harden auth.
Our recommendation, not a spec quote: this order is ours, not the spec's — the specification does not rank its own changes. It comes from which failures mask others: a server failing MCP-STL-003 cannot be meaningfully tested for anything else, because the validator never gets a successful request to inspect.

See which of these changes your server has made

Rather than reading the list and guessing, point the validator at a live server. It reports every rule above as pass, warn or fail, with the exact spec sentence behind each one.

Validate a server →

Frequently asked

What changed in MCP spec 2026-07-28?

The largest revision since MCP launched. Protocol-level sessions and the initialize handshake were removed in favour of a fully stateless core; Mcp-Method and Mcp-Name became required headers on Streamable HTTP; list and read results must carry ttlMs and cacheScope; server-initiated requests were replaced by the Multi Round-Trip Request pattern; several methods including ping, logging/setLevel and resources/subscribe were removed; and the error code range was partitioned with three new codes added.

Is 2026-07-28 a breaking change?

Yes, in both directions. A 2025-11-25 client expects an initialize handshake that a modern server no longer offers, and a modern client sends per-request _meta and required headers that a legacy server does not understand. The spec's answer is the dual-era server: a request carrying modern _meta is served statelessly, while an initialize request selects legacy session semantics for that connection.

When was MCP 2026-07-28 released?

2026-07-28 is the revision identifier itself — MCP revisions are named by date. It is the current revision as of this page's last verification, and the value servers send in the MCP-Protocol-Version header and in io.modelcontextprotocol/protocolVersion.

What was removed in 2026-07-28?

The initialize handshake and notifications/initialized, the Mcp-Session-Id header, the standalone HTTP GET stream endpoint, ping, logging/setLevel, notifications/roots/list_changed, and resources/subscribe and resources/unsubscribe. Error codes -32002 and -32042 were retired. Roots, Sampling and Logging were deprecated rather than removed, under a 12-month window.

Do I have to migrate immediately?

Not immediately, but the deprecated HTTP+SSE transport carries a minimum 12-month deprecation window before removal, and modern clients will fail against a legacy-only server today. The pragmatic order is to fix statelessness first, since every other change depends on it, then headers, then caching metadata.