小智ESP32代码(6):MCP

MCP(Model Context Protocol)协议是一个基于JSON-RPC 2.0的标准化协议,用于AI模型与外部工具之间的通信。它是一个开放标准,旨在为AI模型提供访问外部工具和数据的标准化方式。在物联网场景中,它允许后台服务(如AI助手)发现设备能力并调用相应功能,而无需了解具体的硬件实现细节。

本文将深入分析小智这个项目中的MCP协议实现,探讨其架构设计和技术特点。

系统架构设计

整体架构图

graph TB subgraph "后台服务 (MCP Client)" AI[AI助手/后台API] MCPClient[MCP客户端] end subgraph "通信层" WS[WebSocket/MQTT] end subgraph "ESP32设备 (MCP Server)" MCPServer[MCP服务器] ToolRegistry[工具注册表] ThreadPool[线程池] end subgraph "硬件抽象层" Audio[音频控制] Display[显示控制] Camera[摄像头] LED[LED控制] end AI --> MCPClient MCPClient --> WS WS --> MCPServer MCPServer --> ToolRegistry MCPServer --> ThreadPool ToolRegistry --> Audio ToolRegistry --> Display ToolRegistry --> Camera ToolRegistry --> LED ThreadPool --> Audio ThreadPool --> Display ThreadPool --> Camera ThreadPool --> LED

核心组件关系

classDiagram class McpServer { -tools_: vector~McpTool*~ -tool_call_thread_: thread +AddTool(name, desc, props, callback) +ParseMessage(json) +DoToolCall(id, name, args, stack_size) +GetToolsList(id, cursor) } class McpTool { -name_: string -description_: string -properties_: PropertyList -callback_: function +Call(properties): string +to_json(): string } class PropertyList { +GetRequired(): vector~string~ +to_json(): string } class Property { -name_: string -type_: PropertyType -value_: variant +set_value~T~(value) +value~T~(): T } McpServer --> McpTool : contains McpTool --> PropertyList : has PropertyList --> Property : contains McpTool --> PropertyList : validates

核心实现分析

1. 工具注册机制

MCP服务器通过AddTool方法注册各种功能工具,每个工具包含名称、描述、参数定义和执行回调:

void McpServer::AddCommonTools() {
    auto& board = Board::GetInstance();
    
    // 注册设备状态查询工具
    AddTool("self.get_device_status",
        "提供设备的实时信息,包括音频、屏幕、电池、网络等状态",
        PropertyList(),
        [&board](const PropertyList& properties) -> ReturnValue {
            return board.GetDeviceStatusJson();
        });
    
    // 注册音量控制工具
    AddTool("self.audio_speaker.set_volume", 
        "设置音频扬声器音量",
        PropertyList({
            Property("volume", kPropertyTypeInteger, 0, 100)
        }), 
        [&board](const PropertyList& properties) -> ReturnValue {
            auto codec = board.GetAudioCodec();
            codec->SetOutputVolume(properties["volume"].value<int>());
            return true;
        });
}

2. 消息解析与路由

系统支持三种主要的MCP方法:

flowchart TD A[接收MCP消息] --> B{解析JSON-RPC} B --> C{检查方法类型} C -->|initialize| D[初始化会话] C -->|tools/list| E[获取工具列表] C -->|tools/call| F[调用工具] D --> G[返回协议版本和服务器信息] E --> H[分页返回工具列表] F --> I[验证工具和参数] I --> J{参数验证} J -->|成功| K[创建执行线程] J -->|失败| L[返回错误信息] K --> M[执行工具回调] M --> N[返回执行结果]

3. 工具调用执行流程

sequenceDiagram participant Client as MCP客户端 participant Server as MCP服务器 participant Tool as 具体工具 participant Thread as 执行线程 Client->>Server: tools/call请求 Note over Client,Server: {name: "self.audio_speaker.set_volume", arguments: {volume: 50}} Server->>Server: 查找工具 Server->>Server: 验证参数类型和必需性 alt 参数验证失败 Server->>Client: 返回错误信息 else 参数验证成功 Server->>Thread: 创建执行线程 Thread->>Tool: 调用工具回调函数 Tool->>Thread: 返回执行结果 Thread->>Server: 返回结果 Server->>Client: 返回成功响应 end

4. 异步执行与线程管理

为了避免阻塞主线程,工具调用在独立线程中执行:

void McpServer::DoToolCall(int id, const std::string& tool_name, 
                          const cJSON* tool_arguments, int stack_size) {
    // 配置线程参数
    esp_pthread_cfg_t cfg = esp_pthread_get_default_config();
    cfg.thread_name = "tool_call";
    cfg.stack_size = stack_size;
    cfg.prio = 1;
    esp_pthread_set_cfg(&cfg);
    
    // 在新线程中执行工具调用
    tool_call_thread_ = std::thread([this, id, tool_iter, arguments]() {
        try {
            ReplyResult(id, (*tool_iter)->Call(arguments));
        } catch (const std::exception& e) {
            ESP_LOGE(TAG, "tools/call: %s", e.what());
            ReplyError(id, e.what());
        }
    });
    tool_call_thread_.detach();
}

技术特点与优势

1. 解耦设计

  • 工具定义与具体实现分离
  • 通过回调函数实现功能绑定
  • 支持动态添加新工具

2. 类型安全

  • 强类型参数验证
  • 运行时类型检查
  • 支持默认值设置

3. 异步执行

  • 非阻塞工具调用
  • 可配置线程栈大小
  • 异常安全处理

4. 标准化协议

  • 基于JSON-RPC 2.0
  • 支持分页查询
  • 完整的错误处理

实际应用场景

1. 智能家居控制

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "self.screen.set_brightness",
    "arguments": {"brightness": 80}
  },
  "id": 1
}

2. 设备状态监控

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

3. 多媒体控制

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "self.camera.take_photo",
    "arguments": {"question": "这是什么物体?"}
  },
  "id": 3
}

扩展性设计

1. 新工具添加

只需实现回调函数并注册到MCP服务器:

// 添加新的LED控制工具
mcp_server.AddTool("self.led.set_color",
    "设置LED颜色",
    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>();
        SetLedColor(r, g, b);
        return true;
    });

2. 参数类型扩展

系统支持三种基本类型,可根据需要扩展:

enum PropertyType {
    kPropertyTypeBoolean,
    kPropertyTypeInteger,
    kPropertyTypeString
    // 可扩展:kPropertyTypeFloat, kPropertyTypeArray等
};

MCP协议为物联网设备提供了一个优雅的解决方案,让设备能够以标准化的方式与AI系统交互,这为构建更智能、更灵活的物联网生态系统奠定了基础。


本文基于ESP32项目中的实际MCP协议实现进行分析,代码示例来自开源项目,遵循相应的开源协议。

posted @ 2025-09-03 23:24  icuic  阅读(99)  评论(0)    收藏  举报