2026-07-28The Model Context Protocol,
explained the way agents actually use it.
A practical, practitioner-grade reference for the 2026-07-28 specification: what MCP is, how the new stateless core works, how to build a server well, and how to keep it secure - with animated diagrams of every flow.
What's new in 2026-07-28
The largest breaking change since MCP launched. MCP is now a stateless request/response protocol. If you last read about MCP before August 2026, read this section first - several things you learned are no longer true.
initialize handshake, the Mcp-Session-Id header, server-initiated requests, and SSE stream resumability are all gone. Any request can now land on any instance behind a plain round-robin load balancer.
No sessions, no handshake
Protocol-level sessions and initialize/notifications/initialized are removed. Every request carries its protocol version, client identity and capabilities in _meta.
server/discover
One mandatory RPC advertising supported versions, capabilities and identity. Clients may call it up front, or just fire a request and handle UnsupportedProtocolVersion.
Multi Round-Trip Requests
Servers no longer call clients. They return resultType: "input_required"; the client answers and retries the original request. Elicitation now survives a stateless core.
Header-based routing
Mcp-Method and Mcp-Name are required on Streamable HTTP POSTs, so gateways, rate limiters and WAFs can route and meter without parsing JSON.
Cacheable list results
ttlMs and cacheScope are required on list and read results. Clients cache instead of re-listing every turn.
Deprecations
Roots, Sampling, Logging and OAuth Dynamic Client Registration are deprecated - still functional, removable no sooner than 2027-07-28.
SEP-2577 · SEP-2596Also in this release
- Extensions framework (SEP-2133) - reverse-DNS identified, independently versioned, always opt-in. Tasks, MCP Apps, Skills over MCP and the auth extensions all live here.
- Tasks left the core (SEP-2663) - now
io.modelcontextprotocol/tasks, with polling viatasks/getand a newtasks/updatefor mid-flight input. subscriptions/listenreplaces the HTTP GET endpoint andresources/subscribe, with per-type client opt-in.- Authorization hardening - RFC 9207
issvalidation, issuer-bound client credentials,application_typein DCR, and Client ID Metadata Documents as the preferred registration path. - Full JSON Schema 2020-12 in
inputSchemaandoutputSchema, includingoneOf,anyOf,allOfand$ref. - A formal deprecation policy - Active → Deprecated → Removed, with a twelve-month minimum window.
- No SSE resumability -
Last-Event-IDand event IDs are gone. A broken stream means the client re-issues the request, so make side-effecting tools idempotent.
What is MCP?
An open JSON-RPC 2.0 standard that gives any LLM a single, uniform way to call tools, read data, and use reusable prompts from any compliant external system. The "USB-C for AI" - one connector, every device.
A short history
- Nov 2024 - Anthropic publishes the spec (
2024-11-05) and open-sources the SDKs. - 2025 - OpenAI, Google DeepMind, Microsoft, AWS and most major IDEs adopt MCP. Revisions
2025-03-26(Streamable HTTP, OAuth) and2025-06-18(elicitation, structured output) land. - Nov 2025 -
2025-11-25ships: experimental tasks, URL-mode elicitation, further authorization work. - Dec 2025 - Anthropic donates MCP to the Agentic AI Foundation under the Linux Foundation, reinforcing vendor-neutral governance.
- Mar 2026 - The 2026 roadmap names transport scalability, agent communication, governance and enterprise readiness as priorities. The extensions framework arrives.
- Jun 2026 - Enterprise-Managed Authorization reaches stable, adopted by Anthropic, Microsoft and Okta.
- 28 Jul 2026 -
2026-07-28ships the stateless core, MRTR, header routing, cacheable lists, auth hardening and extensions. All four Tier 1 SDKs (TypeScript, Python, Go, C#) speak it on day one; Rust follows in beta. - Aug 2026 - A new roadmap sets five priority areas for the next cycle.
At the 2026-07-28 release the maintainers reported close to half a billion downloads a month across the Tier 1 SDKs, with the TypeScript and Python SDKs each crossing 1 billion total downloads.
Protocol revisions at a glance
The spec calls 2025-11-25 and earlier legacy (they establish a session with an initialize handshake) and 2026-07-28 and later modern (version, identity and capabilities travel as per-request metadata). An implementation supporting both is dual-era.
The building blocks
MCP organizes capabilities into a small set of named primitives. Three live on the server, three used to live on the client (two are now deprecated), and a handful are protocol-level. Know them cold.
Server-side primitives what your server exposes
Tools
Functions the model can invoke - query a DB, send an email, create a GitHub issue. Each has a name, description and JSON Schema. Since 2026-07-28, schemas may use any JSON Schema 2020-12 keywords.
Resources
Read-only data identified by URI - file contents, DB rows, API responses. Pulled into context by the host or user.
application-controlledPrompts
Reusable, parameterized templates the server exposes - slash commands, workflows. The user picks them from a menu.
user-controlledClient-side primitives what the server can ask the host to do
2026-07-28 a server cannot call the client out of band. It returns an interim result saying "I need this input", and the client answers and retries. That's Multi Round-Trip Requests.
Elicitation active
Server asks the user a structured follow-up question mid-flow - "Which environment do you want to deploy to?" The only client feature the modern spec still lists as active.
elicitation/createSampling deprecated
Server asks the host's LLM to run a completion. Still functional through the deprecation window; new servers should integrate directly with an LLM provider API instead.
removable from 2027-07-28Roots deprecated
Client tells the server "you may operate within these URIs". Migration path: pass directories or files via tool parameters, resource URIs, or server configuration.
removable from 2027-07-28Protocol-level primitives
- Per-request metadata (
_meta) - replaces the handshake. Every request carriesio.modelcontextprotocol/protocolVersionandclientCapabilities(both required); clients should addclientInfo, and servers should returnserverInfoin each result. server/discover- mandatory RPC advertising supported versions, capabilities, identity and instructions. Optional for clients to call.subscriptions/listen- one long-lived stream for opted-in change notifications:toolsListChanged,promptsListChanged,resourcesListChanged,resourceSubscriptions. Servers must not push types the client didn't request.- Caching hints -
ttlMsandcacheScope(public/private) are required on list and read results. MRTR retries must never be cached. - Result types - every result carries
resultType:"complete"or"input_required". A missing field from a legacy server means"complete". - Capability negotiation - per request, plus an
extensionsmap on both client and server capabilities for opt-in features. - Tracing - W3C Trace Context keys (
traceparent,tracestate,baggage) are documented_metaconventions, so a tool call joins your distributed trace. - Logging deprecated - level is now set per request via
io.modelcontextprotocol/logLevel;logging/setLevelis removed. Usestderron stdio, or OpenTelemetry.
How MCP works, end-to-end
Built on JSON-RPC 2.0. Every message is a request, response, or notification - and since 2026-07-28, every request is self-describing. Two standardized transports: stdio for local, Streamable HTTP for remote.
There is no session, and no handshake
This is the defining change of 2026-07-28. No initialize exchange, no Mcp-Session-Id header, no per-connection list results, no SSE resumability, no ping. The practical consequence: any request can land on any instance behind a plain round-robin load balancer - no sticky routing, no shared session store, no drained sessions on redeploy. A server that genuinely needs cross-call state mints an explicit handle and hands it back as an ordinary tool argument.
Multi Round-Trip Requests (MRTR)
Server-initiated requests needed an open, sticky stream, so they couldn't survive a stateless core. MRTR inverts them. When a server needs an elicitation, a sampling completion or a roots list, it does not call the client - it returns an interim result:
Server returns
resultType: "input_required" plus an inputRequests map (keys are server-assigned ids; values are elicitation/create, sampling/createMessage or roots/list request objects) and an opaque requestState.
Client retries
The same request, a new request id, now carrying inputResponses keyed by the same ids plus the echoed requestState. Because the state travels with the retry, the second call can land on a different instance.
Header-based routing
Streamable HTTP POSTs must now carry standard headers so gateways, rate limiters and WAFs can route and meter without parsing the body. A mismatch between a header and the body is a HeaderMismatch error (-32020).
methodparams.name or params.uritools/call, resources/read, prompts/getTools may additionally promote individual parameters into HTTP headers with an x-mcp-header annotation in the input schema - useful for routing on a tenant or region without cracking the payload open.
Error codes
The two transports, side by side
stdio
Host spawns the server as a subprocess. Talks over stdin/stdout. Best for local, single-user integrations - IDE plugins, desktop apps. Trust the host process.
Streamable HTTP
Server runs as a remote service. Client POSTs JSON-RPC; the server may stream request-scoped notifications over SSE on that response. This is how multi-tenant production servers run - and since 2026-07-28 it's just an ordinary HTTP workload.
2025-03-26, is now formally Deprecated under the lifecycle policy and eligible for removal three months after SEP-2596 reaches Final. Migrate to Streamable HTTP.
What to consider when building a server
A "hello world" MCP server is 50 lines. A production-grade one is a product. Here's the checklist that separates toys from tools agents love.
- Define the agent story first. Write the user-and-agent workflows you want to support, then design the minimum tools to satisfy them in one or two calls - not seven.
- Pick the right transport. stdio for local; Streamable HTTP for remote multi-tenant.
- Design for statelessness - it's now the protocol's default. Not a deployment preference any more. Every handler must be independently servable by any instance; mint explicit handles for anything spanning calls.
- Budget your tool surface. 5-8 tools per server is the sweet spot. Past ~12, agent performance degrades.
- Write tool descriptions for the LLM. Action-first, disambiguating, under ~200 tokens. They go straight into the context window.
- Design payloads for context economy. Return only what the agent needs for the next decision. Offer a
verboseflag if power users need more. - Set caching hints honestly. A generous
ttlMson a stable catalog saves a round trip every turn. The same on a per-user tool list is a correctness bug - andcacheScope: "public"on anything user-specific is a data-leak bug. When in doubt:private, short TTL. - Errors are guidance, not just failures. "Permission denied" is bad. "Reauthenticate with repo:write scope" is useful. Use the allocated code ranges; never invent codes in
-32020..-32099. - Version gracefully. Tool names and schemas are a public API. Add fields as optional; never repurpose existing ones. Return a deterministic tool order so client and prompt caches stay warm.
- Plan your dual-era story. You'll serve legacy and modern callers together for a while. Let
server/discoverandUnsupportedProtocolVersionErrordo the negotiating. - Observability from day one. Structured logs, per-tool latency, audit trail of who called what. Propagate
traceparentfrom_meta.
Why MCP and not just APIs?
MCP and REST solve different problems for different consumers. The fastest way to misuse MCP is to think of it as "an API with extra steps." It isn't.
server/discover + tools/list at runtime2026-07-28)Cache-ControlttlMs + cacheScope on list and read resultsNote how much of that table converged on REST in 2026-07-28. That's the point: a remote MCP server is now, operationally, just another HTTP workload. What still distinguishes MCP is who the consumer is and how the contract is described.
When to reach for each
Use MCP when...
An agent dynamically chooses what to do · three+ tools combine in one chat · you want the same integration to work across Claude, ChatGPT, Cursor, your in-house agent · destructive actions need user-consent flow.
Keep REST when...
A scheduled job calls a known endpoint with known params · mobile app needs deterministic CRUD with strict latency · the caller is human-written code, not a model.
How agents interact with MCP
From the agent's point of view, MCP tools look identical to natively defined functions - but richer, with semantic descriptions and live discovery.
The five phases of agent ↔ MCP
- Connection - host spawns or connects each configured server. There's no handshake to run; it may call
server/discoverto pin a version and read capabilities. - Discovery - client calls
tools/list; descriptions land in the agent's system prompt. Because results carryttlMs, a well-behaved host caches them rather than re-listing every turn. - Decision - LLM, given the catalog, decides whether to answer or call a tool. MCP's richer descriptions improve tool-selection accuracy materially.
- Invocation - chosen call goes out as
tools/callwith_metaand the routing headers; server executes; result feeds back as a tool message. - Mid-flight input & notifications - long tools stream
notifications/progresson their own response. If the server needs input it returnsinput_requiredand the client retries (MRTR). Genuinely long work returns a task handle the client polls. Catalog changes arrive on an opt-insubscriptions/listenstream.
subscriptions/listen stream. Nothing on the server needs tearing down.
Security designs for your MCP server
Public MCP deployments have already shown familiar security failures: leaked credentials, broad tokens, weak audit trails, and prompt-injection exposure. Treat the bar as high from day one.
The five recurring attack classes
Prompt injection
Malicious instructions hidden in data the agent reads - an issue title, an email body - that hijack the agent into calling tools it shouldn't.
indirect injectionTool poisoning / rug pulls
Hosted server ships benign tools, then mutates them with hidden directives later. Defend with pinning and signature verification.
MCPTox vectorOver-privileged tokens
User grants a broad scope once; every agent action runs with the union. Least-privilege per tool is essential.
scope sprawlCredential sprawl
Every dev spins up their own server with their own keys, stored insecurely in source or env files. Leaked keys turn a small server into a large incident.
secret hygieneAudit blind spots
No record of which agent called which tool, on whose behalf, with what arguments. Compliance fails when you can't answer.
governance gapCross-server token replay
Token issued for server A reused at server B. Mitigated by RFC 8707 Resource Indicators binding tokens to a server URI.
RFC 8707What changed in 2026-07-28 authorization hardening
- Validate the
issparameter (RFC 9207) - authorization servers should returniss, and clients must validate it against the recorded issuer before redeeming the authorization code. This closes an authorization-server mix-up hole. SEP-2468 - Prefer CIMD over DCR - OAuth Dynamic Client Registration is deprecated in favor of Client ID Metadata Documents, where the
client_idis an HTTPS URL serving a JSON document withclient_id,client_nameandredirect_uris. The answer to the very common MCP case where client and server have no prior relationship. - Issuer-bound credentials - clients must key persisted credentials by issuer, must not reuse them with a different authorization server, and must re-register when the authorization server changes. SEP-2352
application_typein DCR - clients must declare it, so authorization servers stop rejectinglocalhostredirects for desktop and CLI apps. SEP-837- Enterprise-Managed Authorization - an official extension, stable since June 2026. The client gets an ID-JAG from the IdP during SSO and exchanges it for an access token at the MCP server's authorization server, so an organization provisions MCP access centrally and users skip the per-server OAuth dance entirely.
requestState blob - is now a token travelling through the model's context. Assume it will be logged, summarized and possibly replayed. Sign or encrypt it, bind it to the authenticated principal, re-check that binding on use, give it an expiry, and put nothing sensitive in it in plaintext.
The compact security rule
"Every request" is now literal. With no session there is no connection-scoped "already authorized at connection time" - each request must be independently authenticated and authorized.
Security baseline for HTTP deployments
- OAuth 2.1 with PKCE - use the standard authorization flow for protected HTTP MCP servers.
- Resource Indicators (RFC 8707) - every access token must bind to the specific MCP server URI. Server rejects mismatched audience claims.
- Validate
iss(RFC 9207) before redeeming an authorization code. - Short-lived access tokens - 15-60 minutes - paired with refresh tokens.
- TLS for HTTP deployments - including internal systems unless local development is explicitly isolated.
- Human-in-the-loop for destructive actions - refunds, deletes, money movement need explicit user confirmation.
- Allow-list outbound calls - block egress to user-supplied URLs unless that is literally the tool's job.
- Never auto-dereference external
$refURIs in tool schemas, and bound the resources spent resolving composition keywords. - Validate promoted headers -
x-mcp-headervalues originate in model-generated tool arguments. Reject header/body mismatches rather than trusting whichever copy is convenient.
Designing MCP when you already have rich APIs
The most common starting point - and the most commonly bungled. The trap: one MCP tool per REST endpoint. It works. It's frustrating. Simple goals take five calls.
Patterns that work
Workflow tools, not CRUD tools
Instead of list_issues + get_issue + update_issue + list_comments + add_comment, expose triage_issue that does the obvious orchestrated thing.
Service-prefixed names
Pattern: {service}_{verb}_{noun} - slack_send_message, linear_create_issue, stripe_refund_charge. Avoids collisions across loaded servers.
Domain-sharded servers
A 400-endpoint API != one MCP server with 400 tools. It's 10-20 small servers, each scoped to a coherent domain. Hosts load only what they need.
Generated scaffold, hand-tuned surface
Stainless, FastMCP, Azure APIM auto-generate stubs from OpenAPI. Treat as starting point. Hand-curate names, collapse endpoints, prune fields.
Server-side ranking + pagination
500 results is fine for REST. For MCP it's broken. Default to 5-20, rank by relevance server-side, let the model ask for more.
Anti-patterns to avoid
Every endpoint "for completeness" · raw API JSON unchanged · HTTP status codes as errors · agent forced to know internal IDs.
A migration path
- Stand up a thin generated server from your OpenAPI spec to validate plumbing.
- Instrument it. Log which tools the agent actually uses for real workflows.
- Identify the top 3-5 workflows by frequency.
- Replace each cluster of fine-grained tools with one workflow tool.
- Retire unused fine-grained tools, or move behind a "power user" flag.
- Re-evaluate quarterly - usage shifts as agents and users learn what's possible.
State management - life after protocol-level sessions
The stateful-vs-stateless debate that dominated MCP architecture through 2025 and early 2026 has been settled by the spec: stateless won. The protocol no longer has sessions. State didn't disappear - it became explicit.
2026-07-28. Under 2025-11-25 and earlier, a session ran from initialize to shutdown and was pinned by an Mcp-Session-Id header. That was the single biggest obstacle to running MCP servers like ordinary web services. SEP-2567 and SEP-2575 removed the session and the handshake together.
What was removed, and what replaced it
initialize / notifications/initialized_metaserver/discover (optional, cacheable)Mcp-Session-Id headerresources/subscribe + HTTP GET streamsubscriptions/listenLast-Event-ID)Where state actually lives now
Cursors & opaque tokens
Pagination, a partially built query, a draft. The server mints an identifier, returns it, and the agent passes it to the next call. Backed by Redis or your database, readable by any instance.
requestState
Scoped to one logical request that needed user input. The server encodes what it needs; the client echoes it back verbatim on the retry. Sign it.
Task handles
For work that outlives a single HTTP exchange. Durable by definition - the client can crash, restart, and resume polling tasks/get with the same taskId.
The practical recipe
- Handlers are pure functions of
(request, shared storage). No process-local session maps. - Authenticate and authorize on every request. There is no connection-scoped "already checked".
- Mint explicit handles for anything spanning calls; sign them, scope them to a principal, expire them.
- Put shared state in a fast store (Redis, DynamoDB, Postgres) keyed by the handle, not by a connection.
- Hold heavy shared resources - warmed indexes, connection pools, model caches - at process or sidecar level, read-only, never keyed to a caller.
- Reap stale handles and tasks on a timer, the way you'd expire any other token.
- Use
ttlMsso clients stop re-listing; usesubscriptions/listenonly for clients that genuinely need push.
Per-agent isolation is still your job
The risk moved, it didn't vanish watch this
Everything that used to be dangerous about a shared session is now dangerous about a shared handle: cross-tenant leakage if a handle isn't bound to its principal · auth confusion about whose scopes apply · concurrent-modification bugs in whatever the handle points at.
Share the resource, not the identity the rule
A warmed index in a process-level cache is fine. A handle any caller can present is not. Bind every handle to its authenticated principal and re-check that binding on use.
2025-11-25 and earlier callers while serving modern requests statelessly. Don't let a legacy session's cached state leak into the modern path, and remember that sticky routing a legacy client needs is a property of that one path - not of your whole deployment. Route on the era, not on the service.
Architectural best practices
Consolidated from the 2026-07-28 specification, the August 2026 roadmap, and what production teams have learned the hard way.
Scope & structure
Schema & contracts
Transport & deployment
Security
Reliability
Idempotency matters more now, not less: there's no stream resumability, so a dropped response means the client will re-issue the request.
Observability
Developer experience
- README opens with three concrete agent prompts that should "just work."
- Read your
tools/listout loud - if it doesn't make sense, the agent won't either. - Local dev mode - stdio + fake auth, runs against the real server logic.
- Contract tests verifying JSON Schema of every tool's response, on every commit.
- A conformance run against the official suite (SEP-2484) - Standards Track SEPs can no longer reach Final without matching test scenarios, and the same discipline is worth borrowing.
- Quarterly review of which tools agents actually call. Remove what isn't used.
- Extensions as feature flags - they're always opt-in and disabled by default, so a beta capability can reach a subset of clients before becoming default.
- Your own deprecation policy - the spec's Active → Deprecated → Removed lifecycle with a twelve-month minimum window is a reasonable template.
The extension ecosystem
2026-07-28 formalized extensions (SEP-2133) as the way to add capability without destabilizing the core. Understanding this is now part of understanding MCP, because several things that used to be core features live here.
How extensions work
- Reverse-DNS identifiers -
{vendor-prefix}/{extension-name}. Official ones useio.modelcontextprotocol/; third parties use a domain they own. - Negotiated through the
extensionsmap on client and server capabilities. - Versioned independently of the core spec.
- Always disabled by default, requiring explicit developer opt-in. SDKs choose which to implement - check the SDK docs.
- Official extensions live in
ext-repositories in the MCP GitHub org; incubating ones inexperimental-ext-repos tied to a Working Group.
Tasks io.modelcontextprotocol/tasks
Experimental tasks left the core and were reshaped around statelessness. A supported request returns a CreateTaskResult (resultType: "task") with a taskId, status, TTL and suggested polling interval - durably created before the response is sent. The client polls tasks/get; statuses are working, input_required, completed, failed, cancelled. Mid-flight input is answered with tasks/update. tasks/result and tasks/list are gone.
MCP Apps ext-apps
Servers ship interactive HTML - charts, forms, dashboards - that the host renders inline in a sandboxed iframe. A tool declares a UI resource via _meta.ui.resourceUri; the host preloads and renders it in place of a text result. The app can call tools, delegate actions to the host and reuse the user's connected integrations - and because actions flow through the same JSON-RPC path, the audit trail stays consistent.
Authorization ext-auth
OAuth Client Credentials for machine-to-machine callers with no human in the loop. Enterprise-Managed Authorization (stable since June 2026) for ID-JAG token exchange during SSO, so an organization provisions MCP access centrally through its IdP.
zero-touch OAuthSkills over MCP ext-skills
Discover Agent Skills - workflow instructions and their supporting files - through MCP resources, so a server can hand an agent structured know-how rather than only callable functions.
ext-skillsThe road ahead August 2026 roadmap
Five priority areas guide the next release cycle. SEPs inside them get expedited review.
- Agentic messaging primitives - server-initiated events (webhooks and channels) so clients stop polling for results; a composition review across the Agents, Transports and Triggers & Events Working Groups; maturing Tasks toward core inclusion.
- HTTP-native transport unification - stretching the "an MCP server is just an HTTP workload" model to every deployment mode, including local servers speaking Streamable HTTP over stdio.
- Agent identity & enterprise security - moving past "a person approves in a browser" to workloads with their own identity: DPoP (RFC 9449), Workload Identity Federation, the ID-JAG grant, and standard token exchange, with continued engagement in the IETF OAuth and WIMSE working groups.
- Improved primitives - one clear contract for tool result handling, plus progressive discovery so a server can offer a small entry point and reveal more of its catalog as the conversation narrows.
- Improved SDK developer experience - ergonomics, conformance testing and documentation, which matter more now that many developers build MCP servers by pointing an agent at the libraries.
Separately, the Server Card Working Group is defining .well-known metadata conventions so a server can be discovered and reasoned about without connecting to it.
Migrating 2025-11-25 → 2026-07-28
A practical checklist. Budget real time for this - it's a breaking change, though the SDKs absorb much of it.
Server checklist
- Delete the handshake. Remove
initialize/notifications/initialized. Read protocol version and client capabilities from_metaon every request. - Implement
server/discover. It's mandatory. ReturnsupportedVersions,capabilities,instructions,serverInfo, plusttlMs/cacheScope. - Remove all per-connection state. Delete session maps keyed by
Mcp-Session-Id. Mint explicit signed handles instead. - Stop making server-initiated requests. Rewrite every
elicitation/create,sampling/createMessageandroots/listcall site to returninput_requiredwithinputRequestsandrequestState, and to resume frominputResponseson the retry. - Add
resultTypeto every result."complete"unless it's an MRTR interim result. - Add
ttlMsandcacheScopetoserver/discover, the three list methods,resources/templates/listandresources/read. Never on interim results. - Return tools in a deterministic order.
- Replace
resources/subscribeand the HTTP GET endpoint withsubscriptions/listen, honoring per-type opt-in and sending the acknowledgment first. - Drop
ping,logging/setLevelandnotifications/roots/list_changed. Readio.modelcontextprotocol/logLevelfrom_meta, and emitnotifications/messageonly for requests that set it. - Drop SSE resumability. Remove
Last-Event-IDhandling and event IDs. Make side-effecting tools idempotent - clients will re-issue lost requests. - Validate the routing headers and return
HeaderMismatch(-32020) on a mismatch. - Renumber error codes.
-32001→-32020,-32003→-32021,-32004→-32022; resource-not-found-32002→-32602. - Move long-running work to the Tasks extension rather than blocking.
- Re-check auth on every request. There's no connection-scoped authorization any more.
Client checklist
- Send
_metaon every request -protocolVersionandclientCapabilitiesare required; sendclientInfotoo. - Handle
UnsupportedProtocolVersionError(-32022) by picking a version from thesupportedlist and retrying. - Implement the MRTR retry loop - on
input_required, fulfil each entry ininputRequests, then re-issue the original request with a new request id, same params, plusinputResponsesand the echoedrequestState. - Treat a missing
resultTypeas"complete"so legacy servers keep working. - Honor
ttlMsandcacheScope- never serve a cached response across a different method or params, and never cache an MRTR retry result. - Send the routing headers, mirroring body values exactly, with the Base64 sentinel encoding where needed.
- Mirror
x-mcp-headerannotations from tool schemas into HTTP headers on HTTP transports. - Re-issue, don't resume, when a response stream breaks.
- Migrate registration to CIMD where supported; set
application_typeif you still fall back to DCR; key persisted credentials by issuer. - Validate
issbefore redeeming an authorization code.
Things you can stop doing
Provisioning sticky sessions at the load balancer · running a shared session store just to survive a redeploy · holding an SSE stream open to receive elicitations · polling tools/list on every turn.
Things not to rush
Roots, Sampling, Logging, DCR and the includeContext values "thisServer" / "allServers" are deprecated, not removed. Earliest removal is the first revision released on or after 2027-07-28. Don't add new dependencies; do plan the migration; don't panic-rewrite working code this quarter.