Home / Articles

MCP Grows Up: What Production Teams Must Plan For in the New Spec

How the 2026-07-28 Model Context Protocol revision changes scaling, Tasks, authorization and caching, and how to migrate an existing server in safe stages.

Publisher: REACTAPP.TOP15 min read3462 words

This article is published in English.

Sources: **MCP Grows Up: Six Changes Production Teams Need to Plan For**

A revision that is bigger than a version bump

According to the project's release announcement, the Model Context Protocol published its largest revision since launch on July 28, 2026. The spec drops protocol sessions, formalises extensions, adds durable asynchronous work, tightens authorization and gives implementers a real deprecation policy. The release candidate had been frozen since May 21, which gave SDK maintainers, client developers and server operators roughly ten weeks to test the redesign.

Taken together, the finished document delivers a stateless core, Multi Round-Trip Requests, routing by header, discovery and list results that can be cached, an extensions framework, Tasks, MCP Apps, tougher authorization, and a dependable process for phasing features out.

"Stateless MCP" makes a nice headline, but the change list is longer than that. Several breaking details hide below it. Results gain a resultType field. The HTTP GET stream is removed. subscriptions/listen takes over from older subscription styles. SSE streams lose resumption through Last-Event-ID. List and resource results are obliged to include cache hints. Tool schemas may use the whole of JSON Schema 2020-12. Finally, a missing resource now yields the standard JSON-RPC -32602 where it used to yield -32002.

Treating this as "bump the dependency and redeploy" would be a mistake. It is an architecture migration.

1. A stateless protocol doesn't make the application stateless

Earlier revisions established context with an initialize/initialized handshake. For remote HTTP servers, the server could also hand out an Mcp-Session-Id that the client echoed on later requests. That tied a client to one server session, and real deployments frequently ended up with sticky routing at the load balancer, a shared session store, or the pair of them.

In 2026-07-28 the handshake and the protocol session both disappear. Each request carries its protocol version, client capabilities and optional client identity inside _meta. Servers must implement server/discover, although clients needn't call it before every operation. A client may instead send its preferred version and retry if an UnsupportedProtocolVersionError comes back.

Over Streamable HTTP, a current request carries metadata like this:

MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search

The same version, method and name also appear in the JSON-RPC body. The body stays authoritative, and servers must reject any mismatch between headers and body. That stops a gateway from approving or routing one operation while the server runs another.

"Stateless" doesn't mean "store nothing"

The spec does not do away with application state; it simply stops hiding it. When a server needs continuity from one call to the next, it should mint a domain handle, for instance workspace_id, browser_id, basket_id, analysis_run_id or deployment_id. The client or model then supplies it as a regular tool argument in subsequent calls:

create_workspace()
→ { "workspace_id": "ws_7f3..." }

add_file(workspace_id="ws_7f3...", ...)
→ ...

run_analysis(workspace_id="ws_7f3...")
→ ...

That is cleaner than hidden transport state, but it hands the application new duties. Handles need ownership checks, tenant isolation, expiry, retention rules, authorization and defence against guessing or replay. Persistent workflows may still need a database or distributed cache, and long-running Tasks need durable storage by definition. The infrastructure can be stateless while the product stays stateful.

2. Where statelessness genuinely pays

Plain horizontal scaling

When a request holds all its own context, the server can sit behind a standard round-robin load balancer. On Kubernetes, a normal Deployment and Service are generally enough, with no session-affinity annotations and no StatefulSet purely to own MCP sessions. Autoscaling benefits in particular. A fresh pod needn't rebuild protocol sessions before it takes traffic, and a pod swapped out during a rolling deployment doesn't strand clients on a dead session.

There is one catch. If a server mints application handles or Tasks, those objects still live in an external durable store whenever they have to survive the loss of a process or pod.

Routing and policy at the gateway

Because Mcp-Method and Mcp-Name are plain headers, a gateway can route, meter and enforce policy without ever parsing a JSON body. In a multi-tenant service that opens the door to separate quotas for tools/list, costly search tools, deployment tools and anything destructive:

tools/list                  → high request allowance
tools/call + search         → standard allowance
tools/call + deploy_prod    → lower rate limit and stronger policy
resources/read              → data-volume quota

A gateway should also never read clientInfo as proof of who is calling. The field is self-declared and exists for display, debugging and logging. Who the tenant is has to be established from a validated token or some other trusted source.

Caching

Responses to resources/read, resources/templates/list, resources/list, prompts/list, tools/list and server/discover all carry two new fields, ttlMs and cacheScope. The first is a freshness hint, not a polling interval. The second says whether a result is public or private. Anything that varies by user, tenant, scope or authorization must not be handled as shared public data, and change notifications can invalidate a result that would otherwise be fresh.

Caching cuts repeated tool-catalogue requests and steadies model prompt inputs. A wrongly chosen scope also opens a new class of correctness and privacy bugs.

Observability

The spec documents W3C Trace Context propagation via the _meta keys traceparent, tracestate and baggage. A host, MCP client, gateway, server and downstream service then share one way to correlate a tool call along the whole execution path. Trace context aids correlation, but it isn't an authorization mechanism or an integrity guarantee, and sensitive data, tokens, raw prompts and personal information have no place in baggage.

3. Extensions become a first-class concept

Each extension now has an identifier, negotiation rules, designated maintainers, its own repository and its own release cycle. Clients declare the extensions they handle in the capabilities sent with every request, while servers announce theirs through server/discover. Only when both ends support an extension does it take effect; if the peer lacks it, the implementation has to revert to core behaviour or answer with a fitting error.

That's a big step for protocol evolution, since features no longer wait for a full core release. It also creates a compatibility matrix. A server can't assume every host supports Tasks, MCP Apps, Enterprise-Managed Authorization or any future extension, so production code needs explicit fallbacks:

  • A tool that supports Tasks also offers a synchronous path for clients that don't advertise Tasks, or returns a clear unsupported-capability error.
  • A tool backed by an MCP App returns useful structured or text content when the host can't render its interface.
  • Enterprise authorization falls back only where organisational policy allows.
  • Extension-specific fields never go to a client that didn't negotiate them.

Extensions loosen coupling to the core spec and raise the risk of ecosystem fragmentation.

4. Tasks make long-running tools durable

Tasks move out of the experimental core into an official extension, io.modelcontextprotocol/tasks. If the client says it supports Tasks, the server is allowed to reply an ordinary operation with a task handle in place of a final result. The client then uses tasks/get to read current state, tasks/update to supply requested input and tasks/cancel to ask for cancellation.

A task moves through working, input_required, completed, failed and cancelled. A server has to persist the task before it gives back the handle. Cancelling is cooperative, so an acknowledged request doesn't guarantee the underlying work stops at once.

Natural candidates are test suites, build pipelines, code generation, cloud deployments, data imports, document processing, steps awaiting human approval, batch jobs and thin wrappers over some external job API. What you really get is not async execution as such but the ability to recover: a client can drop off, restart, and carry on polling using the same task ID.

What a production server must add

Tasks need far more than a background thread:

  • a durable task repository
  • an authorization check each time tasks/get, tasks/update or tasks/cancel is called
  • ownership and tenant isolation
  • validation of status transitions
  • retention of results and errors
  • TTL enforcement and cleanup
  • limits on poll rate
  • propagation of cancellation
  • recovery when a worker crashes
  • idempotent job creation
  • protection against duplicate updates
  • metrics on queue age and stuck tasks

Treat a task ID as a resource identifier, not a secret. Holding the ID must never be enough to authorise anything.

5. Multi Round-Trip Requests replace server-initiated asks

A stateless server can't count on a persistent two-way connection for asking the client a question whenever it likes. Multi Round-Trip Requests (MRTR) take over. When a server needs confirmation, elicitation, sampling or other client-supplied input, it returns an InputRequiredResult. The client gathers the inputs and retries the original operation with inputResponses and, if provided, requestState.

Take a destructive tool:

delete_resources(resource_ids=[...])

Instead of opening a reverse request on an existing stream, the server answers:

input_required:
  "Confirm deletion of 53 resources"

The client obtains confirmation and repeats the original call. The retry is self-contained, so this works across instances, but it also means servers must be designed for retries.

Rules for production MRTR

  • Do no irreversible work until every required input is in hand.
  • Make retries idempotent.
  • Bind requestState to the specific operation and the caller who started it.
  • Expire old request state.
  • Reject answers that refer to keys the server never asked for, or has already received.
  • Put a ceiling on how many rounds are allowed, so loops cannot form.
  • Authorise the operation again on every retry.
  • Never assume the retry lands on the same instance.

Where the workflow is sensitive, make requestState either an opaque random handle with the real data kept on the server, or a value that carries a message authentication code so tampering shows.

6. MCP Apps change the product, not just the protocol

MCP Apps let a server tie a tool to an interactive HTML interface. Compatible hosts render it inside a sandboxed iframe. The app talks to the host over JSON-RPC via postMessage, and the host controls which capabilities and tools the app can reach. That enables forms, dashboards, confirmation dialogs, media viewers, deployment configurators, triage screens and other experiences awkward to express as text turns.

For a startup this can shift MVP economics: an interactive conversational workflow without first building a separate application shell and integration layer. Frontend engineering doesn't vanish, though. Teams still own accessible interface design, state handling, CSP setup, code that runs inside the sandbox, input validation, negotiating host capabilities, safe tool-call handling, compatibility testing across clients and a fallback for hosts without App support. Because Apps are an optional extension, host support varies, so a server should return meaningful structured content even when the view can't be shown.

7. Authorization gets stricter and harder

Under the HTTP authorization rules, a protected MCP server plays the part of an OAuth resource server and the MCP client the part of an OAuth client. The revision borrows selected pieces of OAuth 2.1 and neighbouring standards. Servers must publish Protected Resource Metadata so clients can find them, and both OAuth and OpenID Connect authorization-server metadata are accepted. PKCE is mandatory, as are Resource Indicators on authorization and token requests, and issuer checks are stricter. The notable rules:

  • Clients send a resource parameter naming the intended MCP server.
  • A server verifies that the token it receives was minted for its own audience.
  • Authorization servers should include iss, and clients check an issuer when present before redeeming the authorization code.
  • Credentials are tied to the authorization server that issued them.
  • Access tokens belong in the Authorization header and never in a query string.
  • A token received by the MCP server must not be forwarded to an unrelated downstream API.
  • Clients use PKCE, preferably S256.
  • Scope escalation is bounded and limited in retries.
  • Dynamic Client Registration is deprecated in favour of Client ID Metadata Documents.

Resource Indicators restrict a token's audience. They shouldn't be described as cryptographic token binding.

Corporate identity is a separate matter

Core MCP authorization covers the standard user-delegated OAuth flow. Centralised corporate access policy comes from the optional Enterprise-Managed Authorization extension, which lets an organisation's identity provider govern access to MCP servers, covering onboarding, offboarding, conditional access and enforcement. The client, the server's authorization system and the enterprise identity environment must all support it. For a security review, the architecture divides like this:

Core authorization
  OAuth flow
  issuer validation
  resource/audience validation
  scopes and step-up
  Protected Resource Metadata

Optional enterprise extension
  corporate IdP policy
  SSO
  centralized approval and revocation
  identity-assertion exchange

The spec clarifies the architecture without making OAuth operationally simple. Fetching client metadata brings SSRF and trust-policy concerns. Tokens and refresh credentials need secure storage. Multi-issuer deployments need separate registration and token state. Metadata, redirect URIs, scopes and canonical resource identifiers all have to stay consistent.

8. A real deprecation policy

Features now have three states: Active, Deprecated and Removed. A core feature generally stays Deprecated for at least twelve months before it can be removed, and deprecation requires a documented migration path plus an entry in the central registry. Removal may come later than the earliest date. An expedited route exists for active security risks, but even it normally needs at least 90 days.

HTTP+SSE, the older transport, has its own transition rule and could become removable earlier than the other newly deprecated features. Anyone still running it ought to plan the move to Streamable HTTP first. Note too that the twelve-month rule is about protocol features alone; SDK APIs carry separate support policies and timelines that may differ.

How it plays out in real applications

Enterprise internal tooling

Imagine a company that publishes internal knowledge, Jira, Confluence, service catalogues and runbooks through MCP. With the old model a remote deployment might rely on session affinity so that one employee kept landing on the same instance. With 2026-07-28 the MCP tier can be a set of stateless containers behind a normal Kubernetes Service and load balancer:

MCP host
  ↓
API gateway / authorization
  ↓
Stateless MCP Deployment
  ├─ Knowledge connector
  ├─ Jira connector
  ├─ Confluence connector
  └─ Service catalog connector
  ↓
OpenTelemetry backend

Everyday authorization can follow core OAuth, and the Enterprise-Managed Authorization extension steps in when central IdP policy is needed. How many clients actually support that extension is the main constraint.

Multi-tenant SaaS

Say a developer-tools vendor sells MCP as a paid API to hundreds or thousands of tenants. Statelessness permits plain multi-zone routing, and the gateway can meter by Mcp-Method and Mcp-Name, with the tenant taken from validated authorization instead of whatever names or headers a client sends. A sound implementation would partition handles and Tasks by tenant, mark tenant-specific catalogues cacheScope: "private", compare each header with the body, throttle expensive tools on their own limits, block Task lookups across tenants and keep authorization decisions out of local process memory. Session-aware routing is gone; tenant isolation is still your job.

AI coding assistants

A coding server can expose run_tests, build_project, generate_patch or deploy_preview as Tasks. It returns a task ID at once, queues the work and lets the agent carry on reading code or reviewing another issue. The client polls at the server's suggested interval, and when a destructive step needs approval the task enters input_required and the client replies with tasks/update. The payoff is resilience through editor restarts and network drops. The price is a genuine job system: a durable queue, worker leases, stored results, cancellation, isolated workspaces and a retention policy.

Healthcare and financial services

Resource Indicators and audience checks make it less likely that a token issued for one MCP server gets replayed at another, and issuer validation lowers the odds of OAuth mix-up attacks. W3C Trace Context lets a request be followed through the MCP path and the services behind it. Together they give security and compliance teams a clearer set of controls, though not a finished compliance answer. You still need authorization inside the application, immutable audit events, retention and deletion rules, data classification, consent handling, key management, logs of administrative access, an incident process and minimal trace data. Tracing aids diagnosis; it should not be the only audit record.

An AI-native startup

Consider a small team building an infrastructure assistant. Through MCP Apps it could ship a deployment-plan form, a cost-estimate dashboard, an approval dialogue, a rollout monitor and a rollback control. The host provides conversational context, the server provides tools and UI resources, and the app invokes those tools across a bridge the host controls. A separate dashboard product might become unnecessary at first, yet API design, authorization, UI testing, accessibility, CSP rules and compatibility fallbacks all remain.

Where the new spec adds complexity

State moved, it didn't vanish. Connection state becomes explicit domain state, an architectural improvement that forces deliberate design of handles, storage, expiry, ownership and idempotency.

Upgrading the SDK and adopting the protocol are two projects. While the release candidate was out, SDK maintainers urged teams to keep the SDK major-version upgrade apart from switching on the new wire protocol, and that advice still holds. Take the TypeScript v2 SDK: it splits the single package into separate server and client packages, ships as ESM only, runs on Node.js 20+, Bun and Deno, validates through Standard Schema-compatible libraries and includes a codemod for typical v1 changes. Python v2 is likewise a big rework, among other things renaming FastMCP to MCPServer. TypeScript v1 is to get fixes and security updates for at least six months once v2 lands, and Python v1 will still see critical fixes and security patches. A cautious order of work:

  1. Upgrade the SDK while keeping previous protocol behaviour where supported.
  2. Repair application-level API changes.
  3. Add dual-era protocol support.
  4. Validate with real clients and traffic.
  5. Enable modern stateless behaviour gradually.
  6. Retire legacy support only after watching client adoption.

Extensions fragment capabilities. A tool can't assume Tasks or MCP Apps exist everywhere, so product teams need compatibility matrices and fallback UX.

Retries become a correctness issue. Retry paths now arise from MRTR, protocol-version negotiation, dropped HTTP response streams, authorization step-up, Tasks polling and reconnecting subscriptions. Any operation with side effects therefore needs a deliberate idempotency plan.

OAuth interoperates better but stays demanding. The spec references OAuth 2.1 and Client ID Metadata Documents as drafts, so implementers must follow both MCP changes and the underlying standards.

Caching raises privacy questions. Marking an authorization-dependent response as public could expose one user's or tenant's catalogue to another. Conservative defaults suit: use private scope unless a result is truly identical for every caller.

Overall assessment

MCP 2026-07-28 moves the protocol closer to how the modern web operates: requests that stand alone, explicit versions, ordinary HTTP routing, real cache semantics, distributed tracing, standard authorization and optional capabilities that evolve separately. The real gain is not the absence of state but the absence of hidden protocol state.

Scaling out, routing across zones, recovering from failure, setting gateway policy and observing the system all get considerably easier. What surfaces in return is the work session state used to cover up: application handles, idempotency, durable Tasks, extension fallbacks, authorization metadata, privacy of caches and retries that behave.

If you run an existing production server, migrate in stages and support both eras. Treat the SDK upgrade and the wire protocol as separate steps, strip out connection assumptions, put long-lived work in explicit stores, test authorization and retries, and only retire legacy behaviour once real client adoption has been measured. For a brand-new server it is easier: begin with stateless request handlers and explicit state, use Streamable HTTP and current authorization, add OpenTelemetry, make caching deterministic, and plan extension negotiation from the first day.

The protocol is now easier to run, yet only for teams ready to spell out their application state, security boundaries and failure behaviour.