Newsletter image

Subscribe to the Newsletter

Join 10k+ people to get notified about new posts, news and tips.

Do not worry we don't spam!

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Search

GDPR Compliance

We use cookies to ensure you get the best experience on our website. By continuing to use our site, you accept our use of cookies, Privacy Policy, and Terms of Service.

Anthropic - AI Agent, Cybersecurity

MCP 2026-07-28 Spec: Stateless Core, Auth Hardening, RufRoot Fallout

The biggest MCP revision since remote servers arrived lands the same week as the protocol's ugliest CVE. What changed, what breaks, and the checks to run on your own bridge tonight.

TL;DR
  • MCP 2026-07-28 removes the initialize handshake and Mcp-Session-Id: every request is self-describing, and any server instance can answer it.
  • Auth gets teeth: RFC 9207 issuer validation is required, credentials are bound to their auth server, and DCR is deprecated in favor of CIMD.
  • CVE-2026-59726 RufRoot (CVSS 10.0): Ruflo shipped its MCP bridge on 0.0.0.0:3001 with zero auth. Patch to 3.16.3 and rotate your keys.

Two MCP stories landed inside one 48-hour window, and they belong in the same article. On July 28, the Agentic AI Foundation published the 2026-07-28 revision of the Model Context Protocol, the standard your agents use to call external tools. It is the largest change since remote MCP servers arrived: the handshake is gone, sessions are gone, and OAuth grows teeth. A day or two later, researchers went public with CVE-2026-59726, a CVSS 10.0 hole in Ruflo's MCP bridge that handed 233 tools, shell execution included, to anyone who could reach port 3001.

If you build or run MCP servers, both stories are about you. The protocol you target changed shape this week, and the failure mode the new auth rules exist to prevent just got a name, a nickname, and a patch you should already be running.

The MCP 2026-07-28 spec: what shipped

  • The stateless core removes the initialize handshake and the Mcp-Session-Id header. Every request describes itself, so any server instance can answer it (SEP-2575, SEP-2567).
  • Authorization gets hardened: RFC 9207 issuer validation becomes mandatory, client credentials are bound to the server that issued them, and Dynamic Client Registration is deprecated in favor of Client ID Metadata Documents.
  • Deprecations now run on a formal clock: a feature keeps working at least 12 months after deprecation, shortened to 90 days only for security emergencies.

The spec went final on July 28 under the Agentic AI Foundation, the Linux Foundation directed fund that now stewards the protocol Anthropic open-sourced in late 2024. The release candidate was locked on May 21 and then sat through ten weeks of validation by SDK maintainers and client implementers before publication. Lead maintainer David Soria Parra is not underselling it: "The new release is MCP's most important since remote MCP first launched over a year ago."

The scale explains the caution. The Tier 1 SDKs (TypeScript, Python, Go and C#) pull close to half a billion downloads a month, with TypeScript and Python each past one billion total. All four speak 2026-07-28 as of publication day with migration notes included, Rust support is in beta, and FastMCP 4.0 ships stateless out of the box.

Stateless core: the handshake is gone

Until now, every MCP connection opened with an initialize/initialized exchange that negotiated versions and capabilities, and remote transports pinned the result to an Mcp-Session-Id header. That made every server stateful by default. Load balancers needed sticky sessions, a restart dropped your clients, and scaling horizontally meant shared session storage.

2026-07-28 deletes the ceremony. The handshake and the session header are gone, and each request carries its protocol version, client identity and capabilities in the _meta field, so the server learns everything it needs from the request itself:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": { "elicitation": {} }
    },
    "name": "confirmThenGreet",
    "arguments": {}
  }
}

That wire format is lifted straight from the Go SDK's 2026-07-28 conformance suite, not paraphrased. A version mismatch returns UnsupportedProtocolVersionError, and clients that want to probe first can call the new server/discover RPC, which advertises supported versions and capabilities. The payoff: any instance can answer any request, so a plain round-robin load balancer is enough. The servers you already wire into Claude Code get simpler to deploy, not harder to use.

Multi round-trip requests replace server-initiated calls

MCP servers could previously call the client mid-request: elicitation/create to ask the user something, sampling/createMessage to request a completion, roots/list to inspect the workspace. Server-initiated calls are the natural enemy of statelessness, so SEP-2322 inverts the flow. A server that needs input finishes its response instead, returning resultType "input_required" plus a machine-readable list of what it needs:

{
  "resultType": "input_required",
  "requestState": "step=1",
  "inputRequests": {
    "who": {
      "method": "elicitation/create",
      "params": {
        "mode": "form",
        "message": "What is your name?",
        "requestedSchema": {
          "type": "object",
          "properties": { "name": { "type": "string" } }
        }
      }
    }
  }
}

The client gathers answers and retries the original call, attaching "inputResponses": {"who": {"action": "accept", "content": {"name": "MCP Go"}}} and echoing the opaque requestState token back. The server then completes with resultType "complete". No channel held open to the client, no state parked on the server between the two calls, and the SDKs run the retry loop for you by default.

Routing headers and cacheable lists

Two smaller changes matter to anyone running MCP behind real infrastructure. SEP-2243 requires clients to send Mcp-Method and Mcp-Name HTTP headers with each call, so gateways, WAFs and metering proxies can route on the operation without parsing JSON bodies. Your rate limiter can treat a shell-adjacent tools/call differently from a harmless resources/read without deep packet inspection.

SEP-2549 makes list results cacheable: tools/list, prompts/list, resources/list and resources/read responses now carry ttlMs and cacheScope fields. Caching a tool catalog used to be pointless because lists could vary per connection. Stateless servers return the same lists to everyone, so a CDN can finally hold them for the advertised lifetime.

Auth hardening: issuer checks, bound credentials, CIMD

The authorization changes read like a direct response to a year of agent-security incidents. Clients must validate the iss parameter of an authorization response before redeeming the code (RFC 9207, SEP-2468). That blocks mix-up attacks, where a malicious server maneuvers a client into spending its credentials at the wrong authorization server. Client credentials are also bound to the server that issued them (SEP-2352): if a resource migrates, the client re-registers instead of reusing credentials across servers.

Token audience is enforced at protocol level through RFC 8707 resource indicators: a token minted for server A is dead on arrival at server B, closing the confused-deputy replay that security write-ups have warned about since 2025. Operators must publish RFC 9728 metadata at /.well-known/oauth-protected-resource. Dynamic Client Registration is formally deprecated in favor of Client ID Metadata Documents (CIMD), with backward compatibility for authorization servers that have not caught up, and the new application_type parameter finally makes localhost redirects behave for desktop and CLI apps (SEP-837).

All of this assumes one thing: that your bridge has authentication to harden. Last week showed how low the ecosystem's floor still sits.

RufRoot: the CVSS 10.0 argument for all of this

Ruflo is the multi-agent orchestration platform that started life as Claude Flow, with more than 66,500 GitHub stars. Its MCP bridge, the Express.js server that fronts all tool invocations, shipped a default docker-compose.yml that bound port 3001 to 0.0.0.0 and answered POST /mcp with no authentication of any kind. Noma Labs researcher Eli Ainhorn found that one unauthenticated HTTP POST reached 233 tools, including ruflo__terminal_execute.

ItemDetail
CVECVE-2026-59726 "RufRoot"
CVSS10.0
AffectedRuflo (ex Claude Flow), all versions before 3.16.3
ExposureMCP bridge on port 3001, bound to 0.0.0.0 by default docker-compose
AuthNone on POST /mcp and POST /mcp/:group
Surface233 tools: shell execution, database ops, agent management, memory store
Found byNoma Labs (Eli Ainhorn), reported June 30
Fixv3.16.3 within 24 hours: loopback bind, terminal_execute gated, MongoDB auth on

From that single request an attacker could run shell commands inside the container, read every LLM provider key from the environment, dump stored conversations from the bundled MongoDB, drop a payload into /app for persistence, and poison the AgentDB pattern store so the platform's agents learn attacker-chosen behavior. Spawning agent swarms billed to the victim's API keys was the closing insult. The public write-ups landed this week.

Credit where due: maintainer Reuven Cohen shipped 3.16.3 within 24 hours of the June 30 report. The lesson is not that one project was uniquely careless. The lesson is that "an MCP bridge on 0.0.0.0 with no auth" was a shippable default in 2026 at all. A spec cannot patch a door that ships open, but audience-bound tokens and mandatory issuer checks are the same class of failure finally taken seriously at protocol level.

Extensions, deprecations, and the 12-month clock

Tasks leave the experimental core and become the io.modelcontextprotocol/tasks extension. The blocking tasks/result call is removed, long-running work is polled through tasks/get, and notification streams collapse into a single subscriptions/listen per type (SEP-2663). Roots, sampling and logging are deprecated (SEP-2577), and the legacy HTTP+SSE transport starts a one-year goodbye in favor of stateless Streamable HTTP.

Deprecated does not mean dead. The new feature lifecycle guarantees at least twelve months between deprecation and the earliest possible removal, with a 90-day exception reserved for security emergencies. Nothing switches off on you today: servers speaking 2025-11-25 keep working, and nobody is forced to upgrade this quarter. The clock is real, though, and it started on Monday.

What this means for your server

We run MCP servers in production ourselves, so here is the migration map we are actually working from, not a rewording of the changelog.

ChangeSEPIf you run a server todayDo this
Handshake removed2575Requests carry version and capabilities in _meta; mismatches return UnsupportedProtocolVersionErrorRead _meta per request; implement server/discover
Sessions removed2567List results no longer vary per connection; sticky routing is pointlessMint explicit handles, pass them as ordinary tool arguments
Server-initiated calls gone2322elicitation/create, sampling/createMessage, roots/list no longer originate server-sideReturn resultType "input_required", handle inputResponses retries
Blocking tasks/result removed2663Long-running calls no longer blockAdopt the tasks extension, poll tasks/get
OAuth tightened2468, 2352Clients validate iss; credentials stop working across auth serversServe RFC 9728 protected-resource metadata; publish a CIMD
HTTP+SSE deprecatedtransportWorks for one more yearMove to stateless Streamable HTTP

The session removal is the one that changes your code. If your server stashes per-connection state behind Mcp-Session-Id, that pattern is dead: mint explicit handles and pass them as ordinary tool arguments, the way REST APIs have passed resource IDs forever. It is more honest anyway, since hidden session state is exactly how list results ended up varying per connection. Read _meta on every request, implement server/discover, and delete your handshake path with prejudice.

Your 10-minute audit

RufRoot's root cause was not exotic. It was a listener on the wrong interface with nothing in front of it. Check your own machines tonight:

# Anything bound to 0.0.0.0 on these ports answers the internet, not just you
ss -tlnp | grep -E ':(3001|27017)'

# Probe your own bridge: anything but 401, 403 or connection refused
# means it talks to strangers
curl -s -o /dev/null -w '%{http_code}\n' -X POST http://localhost:3001/mcp \
  -H 'Content-Type: application/json' -d '{}'

If you run Ruflo, upgrade to 3.16.3, close ports 3001 and 27017 at the firewall, rotate every LLM key the container could read, and audit the AgentDB store for patterns you did not put there. If you exposed an n8n workflow as an MCP tool, ask the same question: who can reach that endpoint, and what tells them no? Run the two commands above before you close this tab. That is the whole ten minutes.

Sources and further reading

Tested on: not independently tested. No 2026-07-28 SDK ran on our bench long enough for a compliance pass; spec details are read from the official announcement and spec text, the JSON wire formats are copied verbatim from the Go SDK's conformance suite, and RufRoot details come from the Noma Labs advisory and The Hacker News reporting, not reproduced by us.
Date checked: 2026-07-31

Frequently asked questions

Does my existing MCP server stop working after the 2026-07-28 spec?

No. Servers speaking the 2025-11-25 revision keep working, and deprecated features get a 12-month minimum window before removal, shortened to 90 days only for security emergencies.

What replaces the initialize handshake in MCP 2026-07-28?

Every request carries its protocol version, client identity and capabilities in the _meta field, and clients can probe the new server/discover RPC. Version mismatches return UnsupportedProtocolVersionError.

Am I affected by CVE-2026-59726 (RufRoot)?

If you ran Ruflo before v3.16.3 with the default docker-compose, assume exposure. Upgrade, close ports 3001 and 27017, rotate every LLM API key the container could read, and audit your AgentDB store.

Which MCP SDKs support the new spec today?

TypeScript, Python, Go and C# are Tier 1 compliant as of July 28, Rust support is in beta, and FastMCP 4.0 ships with stateless support.
Prev Article
Run Kimi K3 Locally: Unsloth GGUFs Land at 594 GB
Next Article
Mistral released Le Chat

Related to this topic: