MCP (Model Context Protocol) Protocol Documentation
MCP (Model Context Protocol) Interaction Flow
The MCP protocol in this project is used for communication between backend APIs (MCP client) and ESP32 devices (MCP server), enabling the backend to discover and invoke functions (tools) provided by devices.
Protocol Format
According to the code (main/protocols/protocol.cc
, main/mcp_server.cc
), MCP messages are encapsulated within the message body of underlying communication protocols (such as WebSocket or MQTT). The internal structure follows the JSON-RPC 2.0 specification.
Overall message structure example:
{
"session_id": "...", // Session ID
"type": "mcp", // Message type, fixed as "mcp"
"payload": { // JSON-RPC 2.0 payload
"jsonrpc": "2.0",
"method": "...", // Method name (e.g., "initialize", "tools/list", "tools/call")
"params": { ... }, // Method parameters (for request)
"id": ..., // Request ID (for request and response)
"result": { ... }, // Method execution result (for success response)
"error": { ... } // Error information (for error response)
}
}
The payload
section is a standard JSON-RPC 2.0 message:
jsonrpc
: Fixed string “2.0”.method
: Name of the method to be called (for Request).params
: Method parameters, a structured value, typically an object (for Request).id
: Request identifier provided by client when sending request, returned as-is by server in response. Used to match requests and responses.result
: Result when method executes successfully (for Success Response).error
: Error information when method execution fails (for Error Response).
Interaction Flow and Sending Timing
MCP interaction mainly revolves around client (backend API) discovering and calling “tools” on the device.
1. Connection Establishment and Capability Announcement
- Timing: After device startup and successful connection to backend API.
- Sender: Device.
- Message: Device sends basic protocol “hello” message to backend API, including device capability list, e.g., MCP protocol support (
"mcp": true
). - Example (non-MCP payload, basic protocol message):
{ "type": "hello", "version": 3, "features": { "mcp": true }, "transport": "websocket", // or "mqtt" "audio_params": { ... }, "session_id": "..." // May be set after device receives server hello }
2. MCP Session Initialization
Timing: After backend API receives device “hello” message and confirms MCP support, typically sent as first MCP session request.
Sender: Backend API (client).
Method:
initialize
Message (MCP payload):
{ "jsonrpc": "2.0", "method": "initialize", "params": { "capabilities": { // Client capabilities, optional // Camera vision related "vision": { "url": "...", // Camera: image processing address (must be http address, not websocket) "token": "..." // url token } // ... other client capabilities } }, "id": 1 // Request ID }
Device Response Timing: After device receives and processes
initialize
request.Device Response Message (MCP payload):
{ "jsonrpc": "2.0", "id": 1, // Matching request ID "result": { "protocolVersion": "2024-11-05", "capabilities": { "tools": {} // tools here doesn't list details, need tools/list }, "serverInfo": { "name": "...", // Device name (BOARD_NAME) "version": "..." // Device firmware version } } }
3. Discover Device Tool List
- Timing: When backend API needs to get specific function (tool) list and calling methods currently supported by device.
- Sender: Backend API (client).
- Method:
tools/list
- Message (MCP payload):
{ "jsonrpc": "2.0", "method": "tools/list", "params": { "cursor": "" // For pagination, empty string for first request }, "id": 2 // Request ID }
- Device Response Timing: After device receives
tools/list
request and generates tool list. - Device Response Message (MCP payload):
{ "jsonrpc": "2.0", "id": 2, // Matching request ID "result": { "tools": [ // Tool object list { "name": "self.get_device_status", "description": "...", "inputSchema": { ... } // Parameter schema }, { "name": "self.audio_speaker.set_volume", "description": "...", "inputSchema": { ... } // Parameter schema } // ... more tools ], "nextCursor": "..." // If list is large and needs pagination, this contains cursor value for next request } }
- Pagination Handling: If
nextCursor
field is non-empty, client needs to sendtools/list
request again with thiscursor
value inparams
to get next page of tools.
4. Call Device Tool
- Timing: When backend API needs to execute specific function on device.
- Sender: Backend API (client).
- Method:
tools/call
- Message (MCP payload):
{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "self.audio_speaker.set_volume", // Tool name to call "arguments": { // Tool parameters, object format "volume": 50 // Parameter name and value } }, "id": 3 // Request ID }
- Device Response Timing: After device receives
tools/call
request and executes corresponding tool function. - Device Success Response Message (MCP payload):
{ "jsonrpc": "2.0", "id": 3, // Matching request ID "result": { "content": [ // Tool execution result content { "type": "text", "text": "true" } // Example: set_volume returns bool ], "isError": false // Indicates success } }
- Device Failure Response Message (MCP payload):
{ "jsonrpc": "2.0", "id": 3, // Matching request ID "error": { "code": -32601, // JSON-RPC error code, e.g., Method not found (-32601) "message": "Unknown tool: self.non_existent_tool" // Error description } }
5. Device Proactive Messages (Notifications)
- Timing: When device internal events occur that need to notify backend API (e.g., status changes, although code examples don’t clearly show tools sending such messages, but existence of
Application::SendMcpMessage
suggests device may proactively send MCP messages). - Sender: Device (server).
- Method: Possibly methods starting with
notifications/
, or other custom methods. - Message (MCP payload): Follows JSON-RPC Notification format, no
id
field.{ "jsonrpc": "2.0", "method": "notifications/state_changed", // Example method name "params": { "newState": "idle", "oldState": "connecting" } // No id field }
- Backend API Handling: After receiving Notification, backend API processes accordingly but doesn’t reply.
Interaction Diagram
Below is a simplified interaction sequence diagram showing main MCP message flows:
sequenceDiagram participant Device as ESP32 Device participant BackendAPI as Backend API (Client) Note over Device, BackendAPI: Establish WebSocket / MQTT Connection Device->>BackendAPI: Hello Message (includes "mcp": true) BackendAPI->>Device: MCP Initialize Request Note over BackendAPI: method: initialize Note over BackendAPI: params: { capabilities: ... } Device->>BackendAPI: MCP Initialize Response Note over Device: result: { protocolVersion: ..., serverInfo: ... } BackendAPI->>Device: MCP Get Tools List Request Note over BackendAPI: method: tools/list Note over BackendAPI: params: { cursor: "" } Device->>BackendAPI: MCP Get Tools List Response Note over Device: result: { tools: [...], nextCursor: ... } loop Optional Pagination BackendAPI->>Device: MCP Get Tools List Request Note over BackendAPI: method: tools/list Note over BackendAPI: params: { cursor: "..." } Device->>BackendAPI: MCP Get Tools List Response Note over Device: result: { tools: [...], nextCursor: "" } end BackendAPI->>Device: MCP Call Tool Request Note over BackendAPI: method: tools/call Note over BackendAPI: params: { name: "...", arguments: { ... } } alt Tool Call Successful Device->>BackendAPI: MCP Tool Call Success Response Note over Device: result: { content: [...], isError: false } else Tool Call Failed Device->>BackendAPI: MCP Tool Call Error Response Note over Device: error: { code: ..., message: ... } end opt Device Notification Device->>BackendAPI: MCP Notification Note over Device: method: notifications/... Note over Device: params: { ... } end
Related Documentation
- MCP Protocol Usage Guide - Specific usage of MCP protocol in IoT control
- WebSocket Communication Protocol - WebSocket underlying communication protocol
- MQTT + UDP Hybrid Protocol - MQTT + UDP hybrid communication protocol
main/mcp_server.cc
in McpServer::AddCommonTools
and implementations of various tools.