MCP (Model Context Protocol) プロトコル文書

MCP (Model Context Protocol) プロトコル文書

MCP (Model Context Protocol) 相互作用フロー

注意: AI支援生成、バックエンドサービス実装時は、コードを参照して詳細を確認してください!

このプロジェクトのMCPプロトコルは、バックエンドAPI(MCPクライアント)とESP32デバイス(MCPサーバー)間の通信に使用され、バックエンドがデバイスが提供する機能(ツール)を発見・呼び出しできるようにします。

プロトコル形式

コード(main/protocols/protocol.cc, main/mcp_server.cc)によると、MCPメッセージは基本通信プロトコル(WebSocketやMQTTなど)のメッセージ本体にカプセル化されています。その内部構造はJSON-RPC 2.0仕様に従います。

全体のメッセージ構造例:

{
  "session_id": "...", // セッションID
  "type": "mcp",       // メッセージタイプ、固定で"mcp"
  "payload": {         // JSON-RPC 2.0ペイロード
    "jsonrpc": "2.0",
    "method": "...",   // メソッド名 ("initialize", "tools/list", "tools/call"など)
    "params": { ... }, // メソッドパラメータ (requestの場合)
    "id": ...,         // リクエストID (requestとresponseの場合)
    "result": { ... }, // メソッド実行結果 (success responseの場合)
    "error": { ... }   // エラー情報 (error responseの場合)
  }
}

その中で、payload部分は標準のJSON-RPC 2.0メッセージです:

  • jsonrpc: 固定文字列"2.0"。
  • method: 呼び出すメソッド名 (Requestの場合)。
  • params: メソッドのパラメータ、構造化値、通常はオブジェクト (Requestの場合)。
  • id: リクエストの識別子、クライアントがリクエスト送信時に提供、サーバーが応答時にそのまま返す。リクエストと応答をマッチングするために使用。
  • result: メソッド成功実行時の結果 (Success Responseの場合)。
  • error: メソッド実行失敗時のエラー情報 (Error Responseの場合)。

相互作用フローと送信タイミング

MCPの相互作用は主にクライアント(バックエンドAPI)がデバイス上の「ツール」(Tool)を発見・呼び出すことを中心に行われます。

1. 接続確立と能力通知

  • タイミング: デバイス起動後、バックエンドAPIに正常に接続した後。
  • 送信者: デバイス。
  • メッセージ: デバイスがバックエンドAPIに基本プロトコルの"hello"メッセージを送信、メッセージにはデバイスがサポートする能力リストが含まれ、例えばMCPプロトコルサポート("mcp": true)。
  • 例(MCPペイロードではなく、基本プロトコルメッセージ):
    {
      "type": "hello",
      "version": 3,
      "features": {
        "mcp": true
      },
      "transport": "websocket", // または"mqtt"
      "audio_params": { ... },
      "session_id": "..." // デバイスがサーバーhello受信後に設定可能
    }

2. MCPセッション初期化

  • タイミング: バックエンドAPIがデバイス"hello"メッセージを受信し、デバイスがMCPをサポートすることを確認後、通常MCPセッションの最初のリクエストとして送信。

  • 送信者: バックエンドAPI(クライアント)。

  • メソッド: initialize

  • メッセージ(MCPペイロード):

    {
      "jsonrpc": "2.0",
      "method": "initialize",
      "params": {
        "capabilities": {
          // クライアント能力、オプション
    
          // カメラ視覚関連
          "vision": {
            "url": "...", //カメラ: 画像処理アドレス(httpアドレス必須、websocketアドレスではない)
            "token": "..." // urlトークン
          }
    
          // ... その他のクライアント能力
        }
      },
      "id": 1 // リクエストID
    }
  • デバイス応答タイミング: デバイスがinitializeリクエストを受信・処理後。

  • デバイス応答メッセージ(MCPペイロード):

    {
      "jsonrpc": "2.0",
      "id": 1, // リクエストIDをマッチング
      "result": {
        "protocolVersion": "2024-11-05",
        "capabilities": {
          "tools": {} // ここのtoolsは詳細情報をリストしない、tools/listが必要
        },
        "serverInfo": {
          "name": "...", // デバイス名 (BOARD_NAME)
          "version": "..." // デバイスファームウェアバージョン
        }
      }
    }

3. デバイスツールリスト発見

  • タイミング: バックエンドAPIがデバイスの現在サポートする具体的機能(ツール)リストとその呼び出し方法を取得する必要がある時。
  • 送信者: バックエンドAPI(クライアント)。
  • メソッド: tools/list
  • メッセージ(MCPペイロード):
    {
      "jsonrpc": "2.0",
      "method": "tools/list",
      "params": {
        "cursor": "" // ページング用、初回リクエストは空文字列
      },
      "id": 2 // リクエストID
    }
  • デバイス応答タイミング: デバイスがtools/listリクエストを受信し、ツールリストを生成後。
  • デバイス応答メッセージ(MCPペイロード):
    {
      "jsonrpc": "2.0",
      "id": 2, // リクエストIDをマッチング
      "result": {
        "tools": [ // ツールオブジェクトリスト
          {
            "name": "self.get_device_status",
            "description": "...",
            "inputSchema": { ... } // パラメータスキーマ
          },
          {
            "name": "self.audio_speaker.set_volume",
            "description": "...",
            "inputSchema": { ... } // パラメータスキーマ
          }
          // ... より多くのツール
        ],
        "nextCursor": "..." // リストが大きくページングが必要な場合、次のリクエストのcursor値が含まれる
      }
    }
  • ページング処理: nextCursorフィールドが空でない場合、クライアントは再度tools/listリクエストを送信し、paramsにこのcursor値を含めて次のページのツールを取得する必要があります。

4. デバイスツール呼び出し

  • タイミング: バックエンドAPIがデバイス上の特定の具体的機能を実行する必要がある時。
  • 送信者: バックエンドAPI(クライアント)。
  • メソッド: tools/call
  • メッセージ(MCPペイロード):
    {
      "jsonrpc": "2.0",
      "method": "tools/call",
      "params": {
        "name": "self.audio_speaker.set_volume", // 呼び出すツール名
        "arguments": {
          // ツールパラメータ、オブジェクト形式
          "volume": 50 // パラメータ名とその値
        }
      },
      "id": 3 // リクエストID
    }
  • デバイス応答タイミング: デバイスがtools/callリクエストを受信し、対応するツール関数を実行後。
  • デバイス成功応答メッセージ(MCPペイロード):
    {
      "jsonrpc": "2.0",
      "id": 3, // リクエストIDをマッチング
      "result": {
        "content": [
          // ツール実行結果内容
          { "type": "text", "text": "true" } // 例:set_volumeがboolを返す
        ],
        "isError": false // 成功を示す
      }
    }
  • デバイス失敗応答メッセージ(MCPペイロード):
    {
      "jsonrpc": "2.0",
      "id": 3, // リクエストIDをマッチング
      "error": {
        "code": -32601, // JSON-RPCエラーコード、例:Method not found (-32601)
        "message": "Unknown tool: self.non_existent_tool" // エラー説明
      }
    }

5. デバイス能動メッセージ送信(Notifications)

  • タイミング: デバイス内部でバックエンドAPIに通知が必要なイベントが発生した時(例:状態変化、コード例では明確にこのようなメッセージを送信するツールはないが、Application::SendMcpMessageの存在はデバイスが能動的にMCPメッセージを送信する可能性を示唆)。
  • 送信者: デバイス(サーバー)。
  • メソッド: notifications/で始まるメソッド名、またはその他のカスタムメソッドの可能性。
  • メッセージ(MCPペイロード): JSON-RPC Notification形式に従い、idフィールドなし。
    {
      "jsonrpc": "2.0",
      "method": "notifications/state_changed", // 例メソッド名
      "params": {
        "newState": "idle",
        "oldState": "connecting"
      }
      // idフィールドなし
    }
  • バックエンドAPI処理: Notification受信後、バックエンドAPIは対応する処理を行うが、返信しない。

相互作用図

以下は主要なMCPメッセージフローを示す簡略化された相互作用シーケンス図です:

  sequenceDiagram
    participant Device as ESP32 Device
    participant BackendAPI as バックエンドAPI (Client)

    Note over Device, BackendAPI: WebSocket / MQTT接続確立

    Device->>BackendAPI: Hello Message ("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 オプショナルページング
        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 ツール呼び出し成功
        Device->>BackendAPI: MCP Tool Call Success Response
        Note over Device: result: { content: [...], isError: false }
    else ツール呼び出し失敗
        Device->>BackendAPI: MCP Tool Call Error Response
        Note over Device: error: { code: ..., message: ... }
    end

    opt デバイス通知
        Device->>BackendAPI: MCP Notification
        Note over Device: method: notifications/...
        Note over Device: params: { ... }
    end

関連文書

この文書はプロジェクトにおけるMCPプロトコルの主要な相互作用フローを概説しています。具体的なパラメータ詳細とツール機能はmain/mcp_server.ccMcpServer::AddCommonToolsおよび各ツールの実装を参照する必要があります。