MCP (Model Context Protocol) Protocol Documentation

MCP (Model Context Protocol) Protocol Documentation

MCP (Model Context Protocol) Interaction Flow

Note: AI-assisted generation. Please refer to code for detailed implementation when developing backend services!

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 send tools/list request again with this cursor value in params 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

This document outlines the main interaction flow of MCP protocol in this project. Specific parameter details and tool functions need to refer to main/mcp_server.cc in McpServer::AddCommonTools and implementations of various tools.