ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

xiaozhi-esp32 MCP 协议全解析:ESP32 设备作为 MCP 服务器的交互流程与工具调用实现

xiaozhi-esp32 MCP 协议全解析:ESP32 设备作为 MCP 服务器的交互流程与工具调用实现 xiaozhi-esp32 MCP 协议全解析ESP32 设备作为 MCP 服务器的交互流程与工具调用实现【免费下载链接】xiaozhi-esp32An MCP-based chatbot | 一个基于MCP的聊天机器人项目地址: https://gitcode.com/GitHub_Trending/xia/xiaozhi-esp32导读本文档全面讲解 xiaozhi-esp32 项目中 MCPModel Context Protocol协议的完整交互流程后台 API作为 MCP 客户端如何通过 WebSocket / MQTT 消息通道发现并调用 ESP32 设备作为 MCP 服务器上注册的各类工具Tool。读完本文你将掌握 MCP 消息的 JSON-RPC 2.0 封装格式、hello → initialize → tools/list → tools/call 的完整握手时序、设备端工具注册机制公共工具与仅用户工具以及如何基于 main/mcp_server.cc 和 main/mcp_server.h 的源码理解底层实现细节。说明本文档为基于仓库源码的技术解析实现后台服务时请以代码为准核对细节。MCP 在 xiaozhi-esp32 中的角色本项目中的 MCP 协议用于后台 APIMCP 客户端与 ESP32 设备MCP 服务器之间的通信以便后台能够发现和调用设备提供的功能工具。设备端的能力抽象由McpServer单例承载各工具通过回调函数绑定到具体硬件操作例如设置音量、调节屏幕亮度、切换主题、拍照、查询设备状态等。从源码结构看MCP 相关核心实现集中在三个文件main/mcp_server.hMcpServer、McpTool、Property、PropertyList、ImageContent等核心类定义main/mcp_server.ccMCP 消息解析、initialize/tools/list/tools/call分发与工具注册main/protocols/protocol.ccSendMcpMessage将 MCP payload 封装进基础协议消息体。协议格式JSON-RPC 2.0 封装在基础协议消息体中根据代码main/protocols/protocol.cc、main/mcp_server.ccMCP 消息是封装在基础通信协议如 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)。源码印证封装与解析的落点发送方向Protocol::SendMcpMessagemain/protocols/protocol.cc将 payload 包装为{session_id:...,type:mcp,payload:...}后经SendText下发即文档中的外层结构。接收方向Application在 main/application.cc 中按type mcp分支取出payload对象交给McpServer::GetInstance().ParseMessage(payload)处理。JSON-RPC 版本校验McpServer::ParseMessagemain/mcp_server.cc首先校验jsonrpc必须为2.0随后校验method、params若存在必须为对象与数值型id任一不满足即打日志并丢弃。响应消息的构造成功响应ReplyResultmain/mcp_server.cc构造{jsonrpc:2.0,id:N,result:...}并通过Application::SendMcpMessage发出。错误响应ReplyErrormain/mcp_server.cc构造{jsonrpc:2.0,id:N,error:{message:...}}。注意当前实现中错误对象只携带message字段未显式填充标准 JSON-RPCcode字段对接后台时需留意。交互流程及发送时机MCP 的交互主要围绕客户端后台 API发现和调用设备上的工具Tool进行。1. 连接建立与能力通告时机设备启动并成功连接到后台 API 后。发送方设备。消息设备发送基础协议的 hello 消息给后台 API消息中包含设备支持的能力列表例如通过支持 MCP 协议 (mcp: true)。示例 (非 MCP 负载而是基础协议消息):{ type: hello, version: ..., features: { mcp: true, ... }, transport: websocket, // 或 mqtt audio_params: { ... }, session_id: ... // 设备收到服务器hello后可能设置 }源码印证WebSocket 通道的WebsocketProtocol::GetHelloMessagemain/protocols/websocket_protocol.cc与 MQTT 通道的MqttProtocol::GetHelloMessagemain/protocols/mqtt_protocol.cc均在features中写入mcp: true同时携带transportwebsocket / udp、audio_paramsopus、16000Hz、单声道、frame_duration等字段。WebSocket 与 MQTT 两条链路都宣告 MCP 能力后台可按需选择任一通道收发 MCP 消息。2. 初始化 MCP 会话时机后台 API 收到设备 hello 消息确认设备支持 MCP 后通常作为 MCP 会话的第一个请求发送。发送方后台 API (客户端)。方法initialize消息 (MCP payload):{ jsonrpc: 2.0, method: initialize, params: { capabilities: { // 客户端能力可选 // 摄像头视觉相关 vision: { url: ..., // 摄像头: 图片处理地址 (必须是 http 地址, 不是 websocket 地址) token: ... // url token } // ... 其他客户端能力 } }, id: 1 // 请求 ID }设备响应时机设备收到initialize请求并处理后。设备响应消息 (MCP payload):{ jsonrpc: 2.0, id: 1, // 匹配请求 ID result: { protocolVersion: 2024-11-05, capabilities: { tools: {} // 这里的 tools 似乎不列出详细信息需要 tools/list }, serverInfo: { name: ..., // 设备名称 (BOARD_NAME) version: ... // 设备固件版本 } } }源码印证McpServer::ParseMessage对initialize分支main/mcp_server.cc先解析params.capabilities中可选的vision对象ParseCapabilities会把url/token交给摄像头模块SetExplainUrl见 main/mcp_server.cc随后读取esp_app_get_description()的固件版本构造固定protocolVersion: 2024-11-05、capabilities.tools: {}、serverInfo.name BOARD_NAME的响应。3. 发现设备工具列表时机后台 API 需要获取设备当前支持的具体功能工具列表及其调用方式时。发送方后台 API (客户端)。方法tools/list消息 (MCP payload):{ jsonrpc: 2.0, method: tools/list, params: { cursor: // 用于分页首次请求为空字符串 }, id: 2 // 请求 ID }设备响应时机设备收到tools/list请求并生成工具列表后。设备响应消息 (MCP payload):{ jsonrpc: 2.0, id: 2, // 匹配请求 ID result: { tools: [ // 工具对象列表 { name: self.get_device_status, description: ..., inputSchema: { ... } // 参数 schema }, { name: self.audio_speaker.set_volume, description: ..., inputSchema: { ... } // 参数 schema } // ... 更多工具 ], nextCursor: ... // 如果列表很大需要分页这里会包含下一个请求的 cursor 值 } }分页处理如果nextCursor字段非空客户端需要再次发送tools/list请求并在params中带上这个cursor值以获取下一页工具。源码印证GetToolsListmain/mcp_server.cc以cursor定位起始工具为空则从头开始按约 8000 字节的max_payload_size上限逐个累加工具 JSON超出即把当前工具名写入nextCursor提前终止同时支持params.withUserTools布尔参数控制是否列出仅用户工具见下文第 6 节。分页 cursor 用的是下一个未返回工具的名称字符串而非偏移量。4. 调用设备工具时机后台 API 需要执行设备上的某个具体功能时。发送方后台 API (客户端)。方法tools/call消息 (MCP payload):{ jsonrpc: 2.0, method: tools/call, params: { name: self.audio_speaker.set_volume, // 要调用的工具名称 arguments: { // 工具参数对象格式 volume: 50 // 参数名及其值 } }, id: 3 // 请求 ID }设备响应时机设备收到tools/call请求执行相应的工具函数后。设备成功响应消息 (MCP payload):{ jsonrpc: 2.0, id: 3, // 匹配请求 ID result: { content: [ // 工具执行结果内容 { type: text, text: true } // 示例set_volume 返回 bool ], isError: false // 表示成功 } }设备失败响应消息 (MCP payload):{ jsonrpc: 2.0, id: 3, // 匹配请求 ID error: { code: -32601, // JSON-RPC 错误码例如 Method not found (-32601) message: Unknown tool: self.non_existent_tool // 错误描述 } }源码印证ParseMessage的tools/call分支main/mcp_server.cc校验params.name为字符串、params.arguments为对象允许为空随后进入DoToolCallmain/mcp_server.cc按工具名在注册表中查找找不到即返回Unknown tool: name错误将客户端arguments逐字段按Property类型布尔/整数/字符串匹配赋值必填参数缺失或类型不匹配返回Missing valid argument: name整数值超出min/max范围会抛出异常并回错误参数校验通过后通过Application::Schedule把工具回调投递到主线程执行保证与显示、音频等 FreeRTOS 任务的线程安全执行中抛出的异常统一转为ReplyError。关于错误码的说明文档示例中的code: -32601为 JSON-RPC 规范约定错误码从 main/mcp_server.cc 看当前设备端ReplyError构造的错误对象仅含message字段后台服务对接时建议以message文本为准并自行兜底。5. 设备主动发送消息 (Notifications)时机设备内部发生需要通知后台 API 的事件时例如状态变化虽然代码示例中没有明确的工具发送此类消息但Application::SendMcpMessage的存在暗示了设备可能主动发送 MCP 消息。发送方设备 (服务器)。方法可能是以notifications/开头的方法名或者其他自定义方法。消息 (MCP payload):遵循 JSON-RPC Notification 格式没有id字段。{ jsonrpc: 2.0, method: notifications/state_changed, // 示例方法名 params: { newState: idle, oldState: connecting } // 没有 id 字段 }后台 API 处理接收到 Notification 后后台 API 进行相应的处理但不回复。源码印证McpServer::ParseMessage中main/mcp_server.cc凡method以notifications开头的方法会被直接return即设备端对通知不做任何应答同时 main/application.cc 的Application::SendMcpMessage作为统一出口存在说明设备具备向后台主动推送 MCP 消息的能力例如工具回调内部需要上报事件时可复用该通道。交互序列图下面是一个简化的交互序列图展示了主要的 MCP 消息流程设备端工具注册机制公共工具AddCommonToolsMcpServer::AddCommonToolsmain/mcp_server.cc在设备启动阶段注册与板型无关的通用工具并刻意把公共工具放在工具列表最前面以利用服务端 prompt cache 提升响应速度。当前公共工具包括工具名说明参数self.get_device_status返回设备实时状态 JSON音频、屏幕、电池、网络等也是执行控制类工具前的推荐第一步无self.audio_speaker.set_volume设置扬声器音量volume(integer, 0–100)self.screen.set_brightness设置屏幕亮度板级存在背光时注册brightness(integer, 0–100)self.screen.set_theme切换屏幕主题light/dark启用 LVGL 且存在主题时注册theme(string)self.camera.take_photo拍照并返回图片解释结果启用 LVGL 且板载摄像头时注册question(string)从 main/mcp_server.h 可见Property支持布尔/整数/字符串三种类型可声明默认值、整数minimum/maximum范围越界在赋值时抛异常并在to_json中生成对应 JSON Schema 片段McpTool::Callmain/mcp_server.h把bool/int/string/cJSON*/ImageContent*五类返回值统一序列化为content[0].text图片类型则为type:image的 image 内容并固定附加isError: false。仅用户工具AddUserOnlyToolsMcpServer::AddUserOnlyToolsmain/mcp_server.cc注册面向用户而非 AI 模型管理的系统级工具通过set_user_only(true)标记并在McpTool::to_jsonmain/mcp_server.h中为其附加annotations.audience [user]。这些工具在默认tools/list未传withUserTools中不可见后台若需列出它们须在请求参数中携带withUserTools: true。当前仅用户工具包括self.get_system_info返回系统信息 JSONself.reboot延时 1 秒后重启设备self.upgrade_firmware从指定 URL 下载并安装固件后重启参数url(string)self.screen.get_info启用 LVGL 时屏幕宽高、是否单色等信息self.screen.snapshot启用 LVGL 且开启CONFIG_LV_USE_SNAPSHOT屏幕截图并以 multipart/form-data 上传到指定 URL参数url(string)、quality(integer, 1–100, 默认 80)self.screen.preview_image同上条件从 URL 下载图片并预览到屏幕参数url(string)self.assets.set_download_url设置资源包的下载地址写入assets命名空间 Settings。板级自定义工具InitializeToolsMcpServer::AddCommonTools中明确注释自定义工具必须在板级InitializeTools函数中注册main/mcp_server.cc。Board基类约定各板卡实现InitializeTools()在构造流程中被调用例如 main/boards/freenove-esp32s3-display-2.8-lcd/freenove-esp32s3-display-2.8-lcd.cc典型示例如机械狗板卡 main/boards/espressif/esp-hi/esp_hi.cc 通过McpServer::GetInstance().AddTool(...)注册self.dog.basic_controlforward/backward/turn_left/turn_right/stop与self.dog.advanced_control等运动控制工具其余数十款板卡如 waveshare、lilygo、movecall、wdmomo 等均遵循同一模式在InitializeTools中注册各自外设灯环、舵机、摄像头、按键等的 MCP 工具。AddTool注册时会对同名工具去重并打印Add tool: name [user]日志main/mcp_server.cc便于排查重复注册问题。后台 API 对接要点综合以上协议与实现后台服务MCP 客户端在对接设备时需注意通道选择WebSocket 与 MQTT 链路均声明mcp: trueMCP 消息统一以type: mcppayload形式在通道内传输先与设备完成基础握手拿到session_id时序要求先initialize可携带capabilities.vision激活摄像头视觉解释能力再tools/list可传withUserTools: true获取含系统级工具的完整列表最后按列表中的inputSchema构造tools/call分页处理tools/list响应中nextCursor非空时用其值作为下一次请求的cursor继续拉取直到nextCursor为空响应匹配设备端id原样回传后台据此关联请求与响应Notification无id不需要应答错误处理tools/call可能返回error如未知工具、缺失参数、参数越界、执行异常后台应针对error分支与result.isError分支分别处理。总结这份文档概述了该项目中 MCP 协议的主要交互流程外层消息体由session_id、type: mcp与 JSON-RPC 2.0 格式的payload构成交互按hello 能力通告 → initialize 初始化 → tools/list 工具发现可分页、可选含用户工具→ tools/call 工具调用 → notifications 设备通知的顺序展开。具体的参数细节和工具功能可进一步参考 main/mcp_server.cc 中McpServer::AddCommonTools、AddUserOnlyTools以及各板卡InitializeTools中的工具实现。【免费下载链接】xiaozhi-esp32An MCP-based chatbot | 一个基于MCP的聊天机器人项目地址: https://gitcode.com/GitHub_Trending/xia/xiaozhi-esp32创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表