MCP Replaces initialize Handshake With _meta Fields

A terminal window showing a real MCP 2026-07-28 request with protocol version and client capabilities carried in the _meta field instead of an initialize handshake
On this page

What’s actually changing

The specification changelog states it directly:

“Removed initialize/notifications/initialized handshake; requests now carry protocol version and capabilities in _meta (io.modelcontextprotocol/protocolVersion, io.modelcontextprotocol/clientCapabilities); version mismatches return UnsupportedProtocolVersionError

This follows directly from the removal of protocol-level sessions: if there’s no persistent session, there’s no connection-scoped handshake result to hold onto either. Every request has to be self-describing.

A real request under the new shape:

tools/call request with protocol version and capabilities in _meta
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search",
    "arguments": { "query": "stateless MCP" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "example-client",
        "version": "1.0.0"
      },
      "io.modelcontextprotocol/clientCapabilities": {
        "extensions": {}
      }
    }
  }
}

Structural Comparison Matrix

Operational AspectBefore (initialize handshake)After (2026-07-28+)
When negotiation happensOnce, at connection startEvery request
Where version/capabilities liveHandshake response, held for the session_meta.io.modelcontextprotocol/protocolVersion and clientCapabilities on each call
Version mismatch behaviorHandshake failureUnsupportedProtocolVersionError, listing supported revisions

Fix it: move negotiation into per-request _meta

Handle UnsupportedProtocolVersionError explicitly

Since the server’s error response lists the revisions it actually supports, a client should retry with a mutually supported version rather than treating any mismatch as a hard failure. Skipping that retry logic means a client that only speaks an older revision fails outright against a server that could have served it a compatible version.

Any code that previously stored a “session established” flag after a successful initialize call, then skipped re-sending capabilities on later calls, needs that flag and the associated shortcut removed. Every outgoing request needs the _meta block populated fresh, not conditionally based on connection state that no longer exists.

Confirmed version

Sourced from the official Model Context Protocol specification changelog, 2026-07-28 revision, published 2026-07-28, including the real example request shape from the spec’s own migration documentation. Browse more posts like this in the AI Productivity archive.

Frequently asked

Does every single request need the full _meta block, or just the first one?

Every request, per the 2026-07-28 spec, since there's no longer a persistent handshake to negotiate once and trust for the rest of a session. Protocol version and capabilities are evaluated per-request, which is the direct consequence of the protocol becoming stateless.

What happens if a client sends a protocol version the server doesn't support?

The server returns UnsupportedProtocolVersionError (tracked under SEP-2575), including the protocol revisions it does support, so the client can retry a mutually supported version in place rather than failing without a path forward.

Emitted as FAQPage JSON-LD from the same frontmatter — one source, no duplicated prose.

Recent posts

Full-text search via Pagefind · ↑↓ to navigate · ↵ to open