Discovery

server/discover is the sessionless capability discovery method of MCP 2026-07-28 (SEP-2575). It responds before initialize and without an Mcp-Session-Id, so a client learns what a server offers in a single exchange, without creating a session.

The Discovery Result

The result carries the modern supportedVersions, capabilities, and instructions, together with the required ttlMs/cacheScope cache hints, and the server identity as the optional io.modelcontextprotocol/serverInfo stamp in the result _meta.

The request takes no parameters:

{ "jsonrpc": "2.0", "id": 1, "method": "server/discover" }

The server answers with the full discovery result:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "supportedVersions": ["2026-07-28"],
    "capabilities": { "tools": { "listChanged": true } },
    "instructions": "Use the tools of this server as a last resort",
    "_meta": { "io.modelcontextprotocol/serverInfo": { "name": "my_server", "version": "1.0.0" } },
    "ttlMs": 0,
    "cacheScope": "private",
    "resultType": "complete"
  }
}

The Stateless Modern Lifecycle

Beyond answering server/discover, the server serves the full stateless modern lifecycle: requests carrying the SEP-2575 _meta envelope (io.modelcontextprotocol/protocolVersion, clientInfo, and clientCapabilities) are validated per request, and the Streamable HTTP transport serves them on a sessionless single-exchange path. Calling server/discover first is not required: the envelope alone selects the modern lifecycle for a request, while a client performing the classic initialize handshake is served on the handshake lifecycle - the lifecycle is a per-request property, not a server-wide mode.

The bundled transports serve server/discover and the per-request _meta envelope alongside the initialize handshake with no configuration needed. The protocol_version pin scopes the handshake only and does not affect the modern lifecycle; see Configuration for details.

Client Side

On the client, MCP::Client#connect negotiates the lifecycle automatically by default (probe server/discover, fall back to the initialize handshake), connect(mode: :modern) skips the handshake entirely, connect(mode: :legacy) forces the classic handshake, and MCP::Client#discover exposes the raw discovery result. See the client-side Lifecycle page for details.