MCP Tool Token Counter
See what your tool definitions cost in context tokens.
The <strong>2026-07-28</strong> revision is the largest change to the Model Context Protocol since launch. It makes the protocol stateless, removing the <code>initialize</code> handshake and the <code>Mcp-Session-Id</code> header outright; it replaces server-initiated requests with a retry-based pattern; it moves tasks into an extension; and it renumbers four error codes. Paste your server or client source below to see which of those changes touch your code, what each one breaks, and how to migrate. It runs entirely in your browser, so unreleased server code never leaves your machine.
tools/list result, or a raw JSON-RPC transcript. Click "Load sample" to see a server written against the old revision.The through-line of this revision is that MCP became stateless. Previously a client opened a connection, ran an initialize handshake, received a Mcp-Session-Id, and every subsequent request rode that session — which meant horizontal deployments needed sticky routing or a shared session store, and list endpoints could vary per connection. All of that is gone. Every request now carries its own protocol version and client capabilities in _meta, under the keys io.modelcontextprotocol/protocolVersion and io.modelcontextprotocol/clientCapabilities, so any request can hit any server instance. Servers that genuinely need cross-call state now mint an explicit handle and pass it back as an ordinary tool argument, making the state visible in the protocol rather than hidden in the transport.
Statelessness is also what forced the second-largest change. A server could previously call back to the client mid-request — roots/list to ask what directories it may read, sampling/createMessage to borrow the client's model, elicitation/create to ask the user a question. Server-initiated requests assume a live, identified connection, so they are replaced by the Multi Round-Trip Requests pattern: the server returns an InputRequiredResult describing what it needs, and the client retries the original request carrying the answers. That single change is why resultType is now required on every result, and why the elicitation completion notification and its correlation ID were both deleted.
The rest is consolidation. A mandatory server/discover RPC replaces the handshake's discovery role. A single subscriptions/listen stream replaces the HTTP GET endpoint and the resources/subscribe pair, with clients opting in to specific notification types. Tasks graduate out of the experimental core into the official io.modelcontextprotocol/tasks extension, losing tasks/list and swapping the blocking tasks/result for polling via tasks/get. List and read results gain required ttlMs and cacheScope fields so clients can cache instead of poll. Four error codes are renumbered under a new allocation policy. And Roots, Sampling, Logging, Dynamic Client Registration and the old HTTP+SSE transport all enter a formal twelve-month deprecation window — the first time MCP has had one.
2025-11-25.Mcp-Session-Id header are removed. The initialize / notifications/initialized handshake is removed and replaced by per-request _meta fields. ping, logging/setLevel and notifications/roots/list_changed are removed. resources/subscribe and resources/unsubscribe plus the HTTP GET endpoint are replaced by subscriptions/listen. SSE resumability and the Last-Event-ID header are removed. Tasks move to an extension, losing tasks/list and replacing tasks/result with polling. Server-initiated requests are replaced by the Multi Round-Trip Requests pattern. All results gain a required resultType field. And a new server/discover RPC becomes mandatory for servers.-32000 to -32019 stays implementation-defined and existing SDK usage there is grandfathered, while -32020 to -32099 is reserved for the specification. Four codes move: resource-not-found goes from -32002 to -32602 (Invalid Params, aligning with JSON-RPC), HeaderMismatch from -32001 to -32020, MissingRequiredClientCapability from -32003 to -32021, and UnsupportedProtocolVersion from -32004 to -32022.stderr or use OpenTelemetry instead of Logging.roots/list, sampling/createMessage and elicitation/create, which no longer fit a stateless protocol. Instead of calling back to the client, the server returns an InputRequiredResult with resultType: "input_required", whose inputRequests field carries what it needs. The client then retries the original request with inputResponses attached. Because the client learns outcomes by retrying, the notifications/elicitation/complete notification and the elicitationId field are both removed; servers needing to correlate across retries encode their own identifier in requestState.