Server Response
Learn how to build the initialize response with serverInfo, capabilities, and negotiated version.
The Initialize Response
After receiving the initialize request, the server must respond with its own information: the negotiated protocol version, server capabilities, and server identity.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {},
"resources": {},
"prompts": {}
},
"serverInfo": {
"name": "my-mcp-server",
"version": "1.0.0"
}
}
}
Response Fields
The result object contains three main fields:
protocolVersion
The protocol version the server has chosen to use. This must be a version that both client and server support.
"protocolVersion": "2024-11-05"
The server should respond with the highest version it supports that is also supported by the client. If no compatible version exists, the server should return an error instead of a result.
serverInfo
Information about your server. This helps clients identify what server they're connected to and is useful for debugging.
"serverInfo": {
"name": "weather-mcp-server",
"version": "2.1.0"
}
capabilities
The capabilities your server provides. This tells the client what features are available.
"capabilities": {
"tools": {},
"resources": {
"subscribe": true,
"listChanged": true
},
"prompts": {
"listChanged": true
},
"logging": {}
}
Server Capabilities Explained
Here are the main capabilities a server can advertise:
| Capability | Description |
|---|---|
tools |
Server provides callable tools |
resources |
Server provides readable resources |
prompts |
Server provides prompt templates |
logging |
Server can send log messages to client |
experimental |
Non-standard experimental features |
Building the Response in Python
Here's how to construct the initialize response:
from dataclasses import dataclass, field, asdict
from typing import Any, cast
# Server configuration
SERVER_NAME = "my-mcp-server"
SERVER_VERSION = "1.0.0"
SUPPORTED_VERSIONS = ["2024-11-05", "2024-10-07"]
@dataclass
class ServerInfo:
"""Information about this MCP server."""
name: str
version: str
@dataclass
class ServerCapabilities:
"""Capabilities provided by this server."""
tools: dict = field(default_factory=dict)
resources: dict = field(default_factory=dict)
prompts: dict = field(default_factory=dict)
logging: dict = field(default_factory=dict)
@dataclass
class InitializeResult:
"""Result of the initialize request."""
protocolVersion: str
capabilities: ServerCapabilities
serverInfo: ServerInfo
def build_initialize_response(
request_id: int | str,
client_protocol_version: str
) -> dict:
"""Build the initialize response.
Args:
request_id: The ID from the initialize request
client_protocol_version: Version requested by client
Returns:
Complete JSON-RPC response dict
"""
# Negotiate protocol version
negotiated_version = negotiate_version(client_protocol_version)
# Build the result
result = InitializeResult(
protocolVersion=negotiated_version,
capabilities=ServerCapabilities(
tools={}, # We support tools
resources={}, # We support resources
prompts={} # We support prompts
),
serverInfo=ServerInfo(
name=SERVER_NAME,
version=SERVER_VERSION
)
)
# Convert to JSON-RPC response
return {
"jsonrpc": "2.0",
"id": request_id,
"result": asdict(result)
}
def negotiate_version(client_version: str) -> str:
"""Negotiate the protocol version.
Returns the highest mutually supported version.
Raises ValueError if no compatible version.
"""
if client_version in SUPPORTED_VERSIONS:
return client_version
# Try to find any compatible version
# In practice, you might have more complex logic here
raise ValueError(f"Unsupported protocol version: {client_version}")
# Example usage
response = build_initialize_response(
request_id=1,
client_protocol_version="2024-11-05"
)
print(response)
Example Responses
Full-Featured Server
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {},
"resources": {
"subscribe": true,
"listChanged": true
},
"prompts": {
"listChanged": true
},
"logging": {}
},
"serverInfo": {
"name": "full-featured-server",
"version": "3.0.0"
}
}
}
Tools-Only Server
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {}
},
"serverInfo": {
"name": "calculator-server",
"version": "1.0.0"
}
}
}
Only include capabilities your server actually implements. If you don't
have any resources, don't include "resources": {}. The client
uses this to know what requests are valid.
Error Response
If the server cannot complete initialization (e.g., incompatible version), return an error response instead:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Unsupported protocol version",
"data": {
"requested": "2023-01-01",
"supported": ["2024-11-05", "2024-10-07"]
}
}
}
Python Error Handling
def handle_initialize(request: dict) -> dict:
"""Handle the initialize request.
Returns either a success response or error response.
"""
request_id = cast(int | str, request.get("id"))
params = request.get("params", {})
try:
# Validate and parse parameters
client_version = params.get("protocolVersion")
if not client_version:
raise ValueError("Missing protocolVersion")
# Check version compatibility
if client_version not in SUPPORTED_VERSIONS:
return {
"jsonrpc": "2.0",
"id": request_id,
"error": {
"code": -32602,
"message": "Unsupported protocol version",
"data": {
"requested": client_version,
"supported": SUPPORTED_VERSIONS
}
}
}
# Build success response
return build_initialize_response(request_id, client_version)
except Exception as e:
return {
"jsonrpc": "2.0",
"id": request_id,
"error": {
"code": -32603,
"message": f"Internal error: {str(e)}"
}
}
Key Takeaways
- The server responds with negotiated protocol version, capabilities, and server info
- Only advertise capabilities your server actually implements
- Version negotiation should find the highest mutually supported version
- Return an error if no compatible version exists
- The response ID must match the request ID