The next MCP specification is not a routine version bump. The 2026-07-28 release candidate removes the protocol-level session, adds first-class extensions and tasks, formalizes caching and trace context, and tightens the lifecycle for deprecated features.
The final specification is scheduled for July 28, 2026. If you maintain an MCP client, server, gateway, or coding-agent integration, the useful question is not “when do I upgrade?” It is “which assumptions in my stack are about to become invalid?”
This is a practical migration checklist based on the official release candidate, not a claim that every SDK has already adopted it.
What changes in the release candidate
| Area | Before | 2026-07-28 direction | Why it matters |
|---|---|---|---|
| Protocol lifecycle | Initialize/initialized handshake and session ID | Stateless request model | Easier horizontal scaling, fewer sticky-session assumptions |
| HTTP routing | Gateways often need body-aware routing or session affinity |
Mcp-Method and Mcp-Name headers |
Route and observe operations at the edge |
| Results | Limited cache semantics |
ttlMs and cacheScope for list/resource reads |
Make freshness an explicit product decision |
| Observability | Trace propagation varied by implementation | W3C Trace Context in _meta
|
Correlate model, gateway, tool, and backend work |
| Composition | Extensions were mostly experimental | Negotiated, independently versioned extensions | Add capabilities without coupling every change to the core spec |
| Long-running work | Request/response was the dominant shape | Tasks and multi-round-trip patterns | Model asynchronous work explicitly |
The candidate is still a release candidate. Treat the final specification and your SDK’s support matrix as the compatibility authority.
1. Remove accidental session state
The biggest operational change is the removal of the protocol-level session and the Mcp-Session-Id header. A remote server should no longer depend on a request returning to the same process because a prior MCP handshake happened there.
That does not mean your application cannot have state. It means application state must be explicit rather than hidden inside the protocol connection.
Audit for:
- in-memory maps keyed only by session ID;
- sticky-session requirements in the load balancer;
- initialization code that populates process-local capabilities;
- connection cleanup that is doing business-state cleanup;
- tests that send a handshake once and reuse an implicit server session.
A safer shape is to make the request carry the identity your application actually needs:
from dataclasses import dataclass
@dataclass
class AgentContext:
tenant_id: str
run_id: str
user_id: str
def authorize_tool_call(ctx: AgentContext, tool_name: str) -> None:
policy.check(tenant=ctx.tenant_id, run=ctx.run_id, tool=tool_name)
Keep this context in your auth layer, task store, or trace system. Do not recreate protocol session affinity under a new name.
2. Make the gateway boring
Stateless MCP is valuable only if the edge can treat requests as ordinary routable traffic. Before changing the load balancer, test that every instance can handle:
- a fresh request;
- a request after another instance handled the previous request;
- a retry after a timeout;
- a request with no process-local warm-up;
- a request whose backend operation is still running asynchronously.
Log the protocol method, MCP name, request ID, server instance, tenant, and trace ID. Never put API keys, tokens, or user content into routing headers. Headers are visible to proxies, access logs, and telemetry systems.
3. Add cache policy, not just a cache
The candidate’s ttlMs and cacheScope fields make caching inspectable, but they do not decide whether your data is safe to reuse.
For every list or resource read, answer:
- Is the result public, tenant-scoped, user-scoped, or run-scoped?
- What event invalidates it?
- Is stale data acceptable for this tool?
- Can a cache key include the full authorization scope?
- Will the agent mistake a cached result for a live check?
A useful default is short-lived and scope-bound. Cache documentation and immutable metadata more aggressively than issue status, permissions, or deployment state.
4. Wire trace context end to end
Propagating traceparent, tracestate, and baggage in _meta is only useful if your system keeps one trace across the whole action:
agent run -> model call -> MCP gateway -> MCP server -> database/API -> tool result
At minimum, record latency, retry count, authorization decision, tool name, result size, and failure class. Redact secrets before exporting metadata. This is especially important for coding agents, where a “successful” tool call can still produce an unsafe edit or an incomplete migration.
Zira’s earlier guide on observability for coding agents covers the broader instrumentation trade-offs. MCP trace context gives that instrumentation a protocol-level place to travel.
5. Treat Tasks as a resource with limits
Tasks are a better fit for long-running work than holding an HTTP request open, but they introduce lifecycle and capacity questions. Define:
- who may create a task;
- maximum runtime and queue depth;
- polling or notification policy;
- cancellation semantics;
- retention and deletion rules;
- idempotency behavior after client retries;
- what the agent is allowed to do while the task is pending.
Do not let “async” become “unbounded.” A task that invokes tools, starts builds, or touches a repository needs the same approval and sandbox policy as a synchronous call.
6. Validate extensions and deprecations explicitly
The release candidate makes extensions first-class and introduces a formal deprecation policy. That is healthier than silently depending on undocumented behavior, but it means capability negotiation belongs in tests.
Create a compatibility matrix for each client/server pair:
- negotiated protocol version;
- supported extension IDs and versions;
- Tasks support;
- Apps support, if applicable;
- transport support;
- deprecated feature usage;
- fallback behavior when a capability is missing.
Run it in CI against the exact SDK versions you ship. The previous finalized specification may remain in use while SDKs adopt the candidate at different speeds.
A 72-hour migration plan
Today: inventory session, routing, cache, trace, task, and deprecated-feature assumptions. Pin current SDK versions and save representative request fixtures.
Next: run a two-instance server behind a non-sticky load balancer. Add negative tests for missing capabilities, expired tasks, unauthorized scopes, duplicate retries, and stale cache entries.
Before July 28: read the final specification, check your SDK release notes, and canary one low-risk server. Keep rollback support for the previous finalized version until your clients have converged.
The practical takeaway
MCP 2026-07-28 is a scaling opportunity, not a reason to delete every state store. Remove hidden protocol coupling, make application state explicit, bind caches to authorization scope, propagate traces, and put hard limits around asynchronous work.
The teams that migrate safely will be the ones that test the boundaries around the protocol, not just the happy-path tool call.
If you maintain an MCP server today, which assumption is hardest to remove: sticky sessions, cache scope, trace propagation, or long-running task control?
Top comments (0)