initialize
initialize is the first request in an MCP connection on revisions up to 2025-11-25. The client sends the protocol revision it wants plus its own name and version; the server replies with the revision it will actually use, its own identity, and its capabilities. Nothing else can be called until this exchange completes. The 2026-07-28 revision removed it.
Updated
What is the initialize request?
initialize is the handshake. The client proposes a protocol revision and identifies itself, and the server answers with the revision it is going to use, a serverInfo block naming itself, and the capabilities it supports.
The client then sends a notifications/initialized notification to confirm, and only after that is the connection considered open.
What does the request look like?
One JSON-RPC request, POSTed to the server's endpoint:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": { "name": "my-client", "version": "1.0.0" }
}
}
Over HTTP it needs two headers: Content-Type: application/json, and Accept listing both application/json and text/event-stream. The transport specification says the client must send both, because the server may answer with either.
Leaving out text/event-stream is the usual cause of an HTTP 406 Not Acceptable on initialize. A server that enforces the rule refuses the request before reading it, and OpenLiberty issue 35727, opened in September 2026, is exactly that case. If you see a 406, check the Accept header first.
What comes back in the response?
Three useful things: protocolVersion, which may not be the one you asked for, serverInfo with a name and version, and capabilities. Many servers also send an optional instructions string.
This is what our own server at https://mcp-hunter.com/mcp answered on 3 October 2026, with the instructions text cut:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-11-25",
"capabilities": { "tools": { "listChanged": false } },
"serverInfo": { "name": "MCP Hunter", "version": "1.0.0" }
}
}
It also sent an mcp-session-id header. A server may hand one out here, and when it does, every later request has to carry it back as Mcp-Session-Id.
The server's name is the server's own claim about itself, which is why a listing built from a handshake reports what the server said rather than what a directory typed. Of the 14 servers in our tools/list sample, 8 also sent a non-empty instructions string.
Is initialize still used?
By almost every server, yes. The 2026-07-28 revision removed the initialize handshake and Mcp-Session-Id, moved client info into _meta on every request, and added a server/discover method. But when we called the remote servers in the official registry on 20 August 2026, 691 of the 694 that completed a handshake answered on an older revision and only 3 on 2026-07-28 (protocol revision).
So a client that skips initialize today reaches almost nobody. The specification's answer is to try the modern request first and fall back to initialize when the server does not answer like a modern one (versioning), which is what our tester does. Our own implementation keeps each revision's exchange behind its own class rather than a helper per message, because the difference between revisions is the shape of the conversation, not one field inside it.
Example
Our tester sent initialize to https://mcp.deepwiki.com/mcp asking for revision 2025-11-25. The server answered on 2025-11-25, named itself "DeepWiki", and the connection proceeded to tools/list, which returned 3 tools. Against https://knowledge-mcp.global.api.aws the same request came back on 2025-03-26 instead, and the client has to accept that or hang up.
The full sequence, from this request through tools/list, is on testing an MCP server with curl.