What happens during the MCP initialization handshake?

5 minintermediatemcpinitializationlifecyclehandshake

Quick Answer

Every MCP connection starts with a three-step handshake before any other request is valid. (1) The client sends an initialize request containing the protocol version it wants to use, its own capabilities, and clientInfo (name/version). (2) The server responds with the protocol version it has chosen to use (which may differ if it doesn't support the client's preferred version), its own capabilities (which tools/resources/prompts/etc. it supports), and serverInfo. (3) The client sends an initialized notification confirming the handshake is complete. Only after this exchange may the client send normal requests like tools/list or tools/call — sending them earlier is a protocol violation.

Detailed Answer

The handshake exists so neither side has to guess what the other supports. It's negotiated explicitly, once, up front.

The three steps

// 1. Client -> Server
{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {
  "protocolVersion": "2025-06-18",
  "capabilities": {"roots": {"listChanged": true}, "sampling": {}},
  "clientInfo": {"name": "example-host", "version": "1.0.0"}
}}

// 2. Server -> Client
{"jsonrpc": "2.0", "id": 1, "result": {
  "protocolVersion": "2025-06-18",
  "capabilities": {"tools": {"listChanged": true}, "resources": {"subscribe": true}},
  "serverInfo": {"name": "example-server", "version": "0.4.2"}
}}

// 3. Client -> Server (notification, no response)
{"jsonrpc": "2.0", "method": "notifications/initialized"}

Why each step matters

  • Version negotiation: the client proposes the newest protocol version it understands. The server either agrees, or replies with an older version it can actually support. If the client can't work with the server's chosen version, it should close the connection instead of proceeding with mismatched assumptions.
  • Capability negotiation: capabilities aren't just "yes/no, tools supported." They carry sub-flags too, like listChanged (can this side send list-changed notifications for this primitive?) or subscribe (can resources be subscribed to?). Each side only uses features the other side actually declared.
  • The initialized notification tells the server the client has processed its capabilities and is ready for normal traffic. Servers shouldn't push notifications, like a resource update, before receiving it.

What's off-limits before this completes

Sending tools/call, resources/read, or any other operational request before the handshake finishes is invalid. The server is entitled to reject or ignore it. The only messages allowed to cross the wire before initialized are the handshake messages themselves, plus logging in practice.

Related Resources