MCP 協議物聯網控制用法說明

本文件介紹如何基於 MCP 協議實作 ESP32 裝置的物聯網控制。詳細協議流程請參考 MCP 協議文件

簡介

MCP(Model Context Protocol)是新一代推薦用於物聯網控制的協議,透過標準 JSON-RPC 2.0 格式在後台與裝置間發現和呼叫「工具」(Tool),實作靈活的裝置控制。

典型使用流程

  1. 裝置啟動後透過基礎協議(如 WebSocket/MQTT)與後台建立連線。
  2. 後台透過 MCP 協議的 initialize 方法初始化會話。
  3. 後台透過 tools/list 取得裝置支援的所有工具(功能)及參數說明。
  4. 後台透過 tools/call 呼叫具體工具,實作對裝置的控制。

詳細協議格式與互動請見 MCP 協議文件

裝置端工具註冊方法說明

裝置透過 McpServer::AddTool 方法註冊可被後台呼叫的「工具」。其常用函式簽名如下:

void AddTool(
    const std::string& name,           // 工具名稱,建議唯一且有層次感,如 self.dog.forward
    const std::string& description,    // 工具描述,簡明說明功能,便於大模型理解
    const PropertyList& properties,    // 輸入參數清單(可為空),支援類型:布林、整數、字串
    std::function<ReturnValue(const PropertyList&)> callback // 工具被呼叫時的回呼實作
);

參數說明

  • name:工具唯一標識,建議用「模組.功能」命名風格。
  • description:自然語言描述,便於 AI/使用者理解。
  • properties:參數清單,支援類型有布林、整數、字串,可指定範圍和預設值。
  • callback:收到呼叫請求時的實際執行邏輯,回傳值可為 bool/int/string。

典型註冊範例(以 ESP-Hi 為例)

void InitializeTools() {
    auto& mcp_server = McpServer::GetInstance();
    
    // 例1:無參數,控制機器人前進
    mcp_server.AddTool("self.dog.forward", "機器人向前移動", PropertyList(), 
        [this](const PropertyList&) -> ReturnValue {
            servo_dog_ctrl_send(DOG_STATE_FORWARD, NULL);
            return true;
        });
    
    // 例2:帶參數,設定燈光 RGB 顏色
    mcp_server.AddTool("self.light.set_rgb", "設定RGB顏色", PropertyList({
        Property("r", kPropertyTypeInteger, 0, 255),
        Property("g", kPropertyTypeInteger, 0, 255),
        Property("b", kPropertyTypeInteger, 0, 255)
    }), [this](const PropertyList& properties) -> ReturnValue {
        int r = properties["r"].value<int>();
        int g = properties["g"].value<int>();
        int b = properties["b"].value<int>();
        led_on_ = true;
        SetLedColor(r, g, b);
        return true;
    });
}

常見工具呼叫 JSON-RPC 範例

1. 取得工具清單

{
  "jsonrpc": "2.0",
  "method": "tools/list",
  "params": { "cursor": "" },
  "id": 1
}

2. 控制底盤前進

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "self.chassis.go_forward",
    "arguments": {}
  },
  "id": 2
}

3. 切換燈光模式

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "self.chassis.switch_light_mode",
    "arguments": { "light_mode": 3 }
  },
  "id": 3
}

4. 攝影機翻轉

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "self.camera.set_camera_flipped",
    "arguments": {}
  },
  "id": 4
}

工具註冊最佳實務

1. 命名規範

  • 使用有層次的命名:self.模組.功能
  • 保持名稱簡潔且具有描述性
  • 避免使用特殊字元和空格
// 好的命名範例
"self.light.set_brightness"
"self.motor.rotate_left"  
"self.sensor.get_temperature"
"self.display.show_text"
// 不推薦的命名
"light-control"  // 缺少層次
"setBrightness"  // 缺少模組資訊
"控制燈光"       // 非英文命名
"self.light.set brightness" // 包含空格

2. 參數設計

  • 使用清晰的參數名稱
  • 設定合理的參數範圍和預設值
  • 提供詳細的參數描述
// 參數設計範例
PropertyList({
    Property("volume", kPropertyTypeInteger, 0, 100, "音量大小,範圍0-100"),
    Property("enabled", kPropertyTypeBool, true, "是否啟用功能"),
    Property("message", kPropertyTypeString, "", "要顯示的文字內容")
})

3. 錯誤處理

在工具回呼中進行適當的錯誤處理:

mcp_server.AddTool("self.servo.set_angle", "設定舵機角度", PropertyList({
    Property("angle", kPropertyTypeInteger, 0, 180)
}), [this](const PropertyList& properties) -> ReturnValue {
    try {
        int angle = properties["angle"].value<int>();
        if (angle < 0 || angle > 180) {
            return "角度超出範圍:0-180";
        }
        SetServoAngle(angle);
        return true;
    } catch (const std::exception& e) {
        return std::string("設定角度失敗:") + e.what();
    }
});

除錯技巧

1. 日誌記錄

在工具實作中新增日誌:

mcp_server.AddTool("self.debug.test", "測試工具", PropertyList(), 
    [this](const PropertyList& properties) -> ReturnValue {
        ESP_LOGI("MCP", "測試工具被呼叫");
        // 執行測試邏輯
        return "測試完成";
    });

2. 參數驗證

新增詳細的參數驗證:

int volume = properties["volume"].value<int>();
if (volume < 0 || volume > 100) {
    ESP_LOGE("MCP", "音量參數無效:%d", volume);
    return "音量必須在0-100之間";
}

注意事項

  • 工具名稱、參數及回傳值請以裝置端 AddTool 註冊為準。
  • 推薦所有新專案統一採用 MCP 協議進行物聯網控制。
  • 詳細協議與進階用法請查閱 MCP 協議文件

相關文件

常見問題

Q: 如何處理工具呼叫逾時?

A: 在工具回呼中避免長時間阻塞操作,對於耗時操作可以非同步處理並立即回傳狀態。

Q: 可以動態新增或刪除工具嗎?

A: 目前實作通常在裝置啟動時註冊工具,動態管理需要重新設計工具註冊機制。

Q: 如何處理工具呼叫權限?

A: 可以在工具回呼中新增權限檢查邏輯,或在後台API層面進行權限控制。