Gated

The 2026-07-28 MCP Spec: A Server Readiness Checklist

10 min readGustavo
mcpsecurityspectransport

The next Model Context Protocol specification, 2026-07-28, is the largest revision since the protocol launched. The release candidate locked on May 21, 2026, and the final spec publishes on July 28. It contains breaking changes to transport, authorization, and how tool schemas are handled.

A server that is correct against 2025-11-25 today is not broken. Nothing here is a present-tense vulnerability. But several of these changes are security properties, not just compatibility ones — request routing integrity, cross-user cache scope, and schema-driven fetch behavior all move under this revision. This checklist walks the changes a server operator needs to handle before July 28, and calls out the security implication wherever there is one.

Everything below describes the release candidate. Treat specifics as subject to change until the July 28 final, and validate against the official spec before shipping.


Transport: the stateless core

This is the headline change. MCP becomes stateless at the protocol layer, and most of the migration work lives here.

The handshake and session are gone

The initialize/initialized handshake is removed (SEP-2575). Protocol version, client info, and client capabilities no longer get exchanged once at connection time — they travel in _meta on every request. The same SEP adds server/discover as the new discovery anchor: servers must implement it, and clients fetch server capabilities from it when they need them up front. Once the handshake is gone, a server that can't answer server/discover can't be negotiated with.

The Mcp-Session-Id header and the protocol-level session it carried are also removed (SEP-2567). Any request can now land on any server instance. The sticky routing and shared session stores that horizontal deployments relied on are no longer required at the protocol layer.

If a server needs state across calls, mint an explicit handle from a tool — a basket_id, a browser_id — and have the model pass it back as an ordinary argument. The state becomes a visible tool input rather than something hidden in transport metadata.

Required routing headers

The Streamable HTTP transport now requires Mcp-Method and Mcp-Name headers (SEP-2243), so load balancers, gateways, and rate-limiters can route on the operation without reading the body. Requests also carry MCP-Protocol-Version.

Servers must reject requests where the headers and the body disagree. This is a request-integrity check, not just a convenience: a mismatch between the routing header and the actual method in the body is exactly the kind of ambiguity that smuggling and confused-routing attacks exploit. Enforce the agreement; don't route on the header and execute the body.

Checklist

  • Accept self-contained requests that carry protocol version, client info, and capabilities in _meta
  • Implement server/discover for capability negotiation
  • Stop depending on Mcp-Session-Id and stop requiring sticky sessions
  • Require Mcp-Method and Mcp-Name, and reject header/body mismatches
  • Move any cross-call state to explicit, model-visible handles

Server-to-client requests

A stateless protocol still needs a way for a server to ask the client for something mid-call. Two changes rebuild that flow without a persistent connection.

Elicitation only during active processing

Server-initiated requests may now only be issued while the server is actively processing a client request (SEP-2260). Earlier versions recommended this; it is now required.

The security value is concrete. A user is never prompted out of nowhere, and every elicitation traces back to an action they or their agent started. An unsolicited server-initiated prompt is now a spec violation, which makes a whole class of social-engineering-via-prompt behavior detectable rather than ambiguous.

Multi round-trip results

Instead of holding a Server-Sent Events stream open, the server returns an InputRequiredResult carrying an opaque requestState (SEP-2322). The client gathers answers and re-issues the original call with inputResponses and the echoed requestState, and any instance can pick the retry up.

Treat requestState as untrusted on the way back in. It leaves the server, sits client-side, and returns. Integrity-protect it — sign or encrypt it — so a modified requestState can't replay or escalate a half-finished operation. Don't deserialize it into trusted server state without verification.

Checklist

  • Issue server-initiated requests only while handling a client call
  • Return InputRequiredResult rather than holding an SSE stream open
  • Integrity-protect requestState and verify it on retry

Caching and tracing

Three smaller changes make the resulting traffic easier to operate — and two of them carry data across boundaries that deserve attention.

Cache scope is a tenancy boundary

List and resource-read results now carry ttlMs and cacheScope, modeled on HTTP Cache-Control (SEP-2549). Clients learn exactly how long a tools/list response stays fresh and whether it is safe to share across users.

cacheScope is where this becomes a security decision. If a server exposes a per-user or per-tenant tool surface but marks the result shareable, a client may serve one user's tool list to another. Set cacheScope to match the actual sensitivity of what the response reveals, and default to the narrower scope when unsure.

Trace context propagation

W3C Trace Context propagation in _meta is now documented, fixing the traceparent, tracestate, and baggage key names (SEP-414). A trace can follow a call through the client SDK, the server, and whatever the server calls downstream, and show up as one span tree in an OpenTelemetry-compatible backend.

baggage is the field to watch. It propagates arbitrary key-value data downstream by design, which is useful and also a path for sensitive values to cross into systems that shouldn't see them. Decide deliberately what goes into baggage, and strip or scrub it at trust boundaries rather than forwarding everything.

Checklist

  • Emit accurate ttlMs on list and resource-read results
  • Set cacheScope to match per-user or per-tenant sensitivity
  • Use the fixed trace key names, and control what baggage carries across boundaries

Authorization hardening

Six SEPs align the authorization spec more closely with how OAuth 2.0 and OpenID Connect are deployed. These matter most to operators who run their own authorization server or broker auth in front of a server.

Authorization servers should supply the iss parameter on authorization responses per RFC 9207 (SEP-2468). Clients are now expected to validate it, and in a future version they will reject responses that omit it. This is a low-cost mitigation for a mix-up attack that is more likely in MCP's single-client, many-server pattern — so begin supplying iss now if you don't already.

The remaining changes are smaller but worth handling together: support the OpenID Connect application_type during Dynamic Client Registration so desktop and CLI clients aren't defaulted to "web" and rejected (SEP-837); bind registered credentials to the issuing authorization server's issuer and re-register when a resource migrates (SEP-2352); document how to request refresh tokens from OIDC-style servers (SEP-2207); and follow the clarified scope-accumulation and .well-known discovery rules (SEP-2350, SEP-2351).

Checklist

  • Supply iss on authorization responses
  • Honor application_type in Dynamic Client Registration
  • Bind credentials to the issuer and re-register on resource migration
  • Follow the documented refresh-token, scope-accumulation, and discovery rules

Tool schemas

Tool inputSchema and outputSchema are lifted to full JSON Schema 2020-12 (SEP-2106). Input schemas keep the type: "object" root but now allow composition (oneOf, anyOf, allOf), conditionals, and references ($ref, $defs). Output schemas are unrestricted, and structuredContent can be any JSON value rather than only an object.

Two constraints in this change are security constraints, and the spec states them as requirements. Implementations must not auto-dereference external $ref URIs — a schema that points $ref at an external URL is an SSRF and unbounded-fetch vector if you follow it. And implementations should bound schema depth and validation time, because a deeply nested or recursive schema is a denial-of-service input. If your server validates against client-supplied or third-party schemas, enforce both.

Separately, the error code for a missing resource changes from the MCP-custom -32002 to the JSON-RPC standard -32602 Invalid Params (SEP-2164). If any code matches on the literal -32002, update it.

Checklist

  • Accept JSON Schema 2020-12 input and output schemas
  • Never auto-dereference external $ref URIs
  • Bound schema depth and validation time
  • Return -32602 for missing resources, and update any matching on -32002

Deprecations

Roots, Sampling, and Logging are deprecated under the new feature lifecycle policy (SEP-2577). These are annotation-only deprecations: they keep working in this release and in every spec version published within a year, and removal requires a separate SEP. There is no forced cutover on July 28 — but plan the replacements now.

The documented replacements are tool parameters, resource URIs, or server configuration in place of Roots; direct integration with an LLM provider API in place of Sampling; and stderr (for stdio transports) or OpenTelemetry in place of Logging.

Checklist

  • Inventory any use of Roots, Sampling, or Logging
  • Plan migration to the documented replacements before the lifecycle clock runs out

Extensions

Extensions are now first-class (SEP-2133). They are identified by reverse-DNS IDs, negotiated through an extensions map on client and server capabilities, and versioned independently of the specification.

Two official extensions ship with this release. Tasks graduates from an experimental core feature to an extension with a redesigned, stateless lifecycle: a server answers tools/call with a task handle, and the client drives it with tasks/get, tasks/update, and tasks/cancel. tasks/list is removed (SEP-2663) because it can't be scoped safely without sessions. Anyone who built against the 2025-11-25 experimental Tasks API needs to migrate.

MCP Apps (SEP-1865) lets servers ship interactive HTML interfaces that hosts render in a sandboxed iframe. Tools declare their UI templates ahead of time so hosts can prefetch, cache, and security-review them before anything runs, and every UI-initiated action goes through the same audit and consent path as a direct tool call.

Checklist

  • Negotiate extensions through the extensions capability map
  • Migrate any experimental Tasks usage to the extension lifecycle
  • If shipping a UI, declare MCP Apps templates ahead of time for host review

What to do now

The ten-week window between the May 21 lock and the July 28 final exists for exactly this: validate the changes against real workloads before they become normative. Start a migration branch if you operate a remote MCP server, run your own authorization, or build against the experimental Tasks API. The transport rework is the largest piece; the auth and schema constraints are the ones with security teeth.

Most of these are checkable from outside the server — the routing-header enforcement, the cache scope on list responses, the $ref handling, the iss parameter. Gated inspects deployed MCP servers against these and the rest of its check library, mapping each to the conformance and security families with a reproduction for every finding — including private and internal servers reached from inside your network. If a security team wants the posture of a server in writing before July 28, that's the kind of thing it produces.

— Gustavo, Gated