Lesson 4 - Step 2 of 6

The Initialize Request

Learn what the client sends to start the MCP handshake.

The First Message

The initialize request is always the first message in an MCP session. The client sends this to tell the server who it is and what it can do.

json
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
        "protocolVersion": "2024-11-05",
        "capabilities": {
            "roots": {
                "listChanged": true
            },
            "sampling": {}
        },
        "clientInfo": {
            "name": "claude-desktop",
            "version": "1.0.0"
        }
    }
}

Breaking Down the Request

Let's examine each field in the params object:

protocolVersion

The MCP protocol version the client wants to use. This is a date-based version string following the format YYYY-MM-DD.

json
"protocolVersion": "2024-11-05"
Protocol Versions

MCP uses date-based versioning. The server should respond with a version it supports. If there's no compatible version, the server must reject the connection.

capabilities

The capabilities object tells the server what features the client supports. This enables the server to adjust its behavior accordingly.

json
"capabilities": {
    "roots": {
        "listChanged": true
    },
    "sampling": {}
}

Common client capabilities include:

Capability Description
roots Client can provide filesystem roots to the server
roots.listChanged Client supports notifications when roots change
sampling Client supports LLM sampling requests from server
experimental Client supports experimental/non-standard features

clientInfo

The clientInfo object identifies the client application. This is useful for debugging and logging.

json
"clientInfo": {
    "name": "claude-desktop",
    "version": "1.0.0"
}

Parsing the Initialize Request

Here's how to parse and validate the initialize request in Python:

python
from dataclasses import dataclass, field
from typing import Any

@dataclass
class ClientInfo:
    """Information about the MCP client."""
    name: str
    version: str

@dataclass
class ClientCapabilities:
    """Capabilities supported by the client."""
    roots: dict = field(default_factory=dict)
    sampling: dict = field(default_factory=dict)
    experimental: dict = field(default_factory=dict)

@dataclass
class InitializeParams:
    """Parameters for the initialize request."""
    protocolVersion: str
    capabilities: ClientCapabilities
    clientInfo: ClientInfo

def parse_initialize_params(params: dict) -> InitializeParams:
    """Parse and validate initialize request parameters."""
    # Extract required fields
    protocol_version = params.get("protocolVersion")
    if not protocol_version:
        raise ValueError("Missing protocolVersion")

    # Parse client info
    client_info_data = params.get("clientInfo", {})
    client_info = ClientInfo(
        name=client_info_data.get("name", "unknown"),
        version=client_info_data.get("version", "unknown")
    )

    # Parse capabilities
    caps_data = params.get("capabilities", {})
    capabilities = ClientCapabilities(
        roots=caps_data.get("roots", {}),
        sampling=caps_data.get("sampling", {}),
        experimental=caps_data.get("experimental", {})
    )

    return InitializeParams(
        protocolVersion=protocol_version,
        capabilities=capabilities,
        clientInfo=client_info
    )

# Example usage
params = {
    "protocolVersion": "2024-11-05",
    "capabilities": {
        "sampling": {}
    },
    "clientInfo": {
        "name": "claude-desktop",
        "version": "1.0.0"
    }
}

init_params = parse_initialize_params(params)
print(f"Client: {init_params.clientInfo.name} v{init_params.clientInfo.version}")
print(f"Protocol: {init_params.protocolVersion}")
print(f"Has sampling: {bool(init_params.capabilities.sampling)}")

Real-World Examples

Here are examples of initialize requests from popular MCP clients:

Claude Desktop

json
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
        "protocolVersion": "2024-11-05",
        "capabilities": {
            "roots": {
                "listChanged": true
            },
            "sampling": {}
        },
        "clientInfo": {
            "name": "claude-desktop",
            "version": "0.7.0"
        }
    }
}

Minimal Client

json
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
        "protocolVersion": "2024-11-05",
        "capabilities": {},
        "clientInfo": {
            "name": "my-test-client",
            "version": "1.0.0"
        }
    }
}
Empty Capabilities

A client with empty capabilities ({}) is perfectly valid. It simply means the client doesn't support any optional features. The server should still work, just with reduced functionality.

Validation Rules

When your server receives an initialize request, validate:

  • Method must be "initialize" — This is always the first request
  • protocolVersion is required — Must be a valid version string
  • clientInfo is recommended — Should have name and version
  • capabilities can be empty — An empty object is valid
python
SUPPORTED_PROTOCOL_VERSIONS = ["2024-11-05", "2024-10-07"]

def validate_initialize_request(params: dict) -> tuple[bool, str]:
    """Validate initialize request parameters.

    Returns (is_valid, error_message).
    """
    # Check protocol version
    version = params.get("protocolVersion")
    if not version:
        return False, "Missing protocolVersion"

    if version not in SUPPORTED_PROTOCOL_VERSIONS:
        return False, f"Unsupported protocol version: {version}"

    # Validate clientInfo structure if present
    client_info = params.get("clientInfo", {})
    if client_info:
        if not isinstance(client_info.get("name"), str):
            return False, "clientInfo.name must be a string"
        if not isinstance(client_info.get("version"), str):
            return False, "clientInfo.version must be a string"

    return True, ""

Key Takeaways

  • The initialize request is always the first message
  • It contains protocol version, client capabilities, and client info
  • Protocol version uses date-based format (YYYY-MM-DD)
  • Capabilities tell the server what optional features the client supports
  • The server must validate and respond appropriately