资讯动态

ESP32 上的 MCP 落地实践:基于 esp-iot-solution 的 mcp-c-sdk 服务端与客户端开发指南

发布时间:2026/9/19 12:43:09 来源:尧图企业网站定制
ESP32 上的 MCP 落地实践基于 esp-iot-solution 的 mcp-c-sdk 服务端与客户端开发指南【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution本文聚焦 esp-iot-solution 仓库中components/mcp-c-sdk组件及其配套示例系统讲解如何在 ESP32 系列芯片上实现Model Context ProtocolMCP服务端与客户端从芯片支持范围、三层架构设计、工程配置构建到 JSON-RPC 工具调用、Resource/Prompt/Completion 注册、SSE 流式传输与自定义工具扩展帮助你快速把 AI Agent 能力接入嵌入式设备。MCP 与 ESP32为什么要在设备上实现模型上下文协议Model Context ProtocolMCP为 AI 应用与外部系统之间定义了标准化接口让 AI Agent 能够发现并调用工具。在 esp-iot-solution 中MCP 落地为 mcp-c-sdk 组件它为访问常用 MCP 功能提供了简化的 C API 接口支持 HTTP 等常见传输场景。借助它ESP32 可以作为 MCP 服务端对外暴露设备控制能力如音量、亮度、主题、颜色也可以作为 MCP 客户端调用远端服务。官方文档 docs/zh_CN/ai/mcp.rst 明确了该方案支持的芯片范围支持的芯片ESP32ESP32-C2ESP32-C3ESP32-C6ESP32-S3支持状态✅✅✅✅✅说明组件依赖 Wi-Fi 联网能力HTTP 传输实际部署时请以芯片是否具备对应网络外设为准上述表格以仓库文档声明为准。mcp-c-sdk 组件的三层架构与协议能力从 components/mcp-c-sdk/README.md 可以看出SDK 采用三层统一命名架构Manager / Router 层esp_mcp_mgr_*负责初始化/启动/停止、端点路由、传输集成是请求分发的入口传输层esp_mcp_transport_*具体传输实现内置 HTTP Server 与 HTTP Client 两种传输引擎层esp_mcp_*协议语义与工具调度包括 JSON-RPC 编解码、initialize、tools/list、tools/call等核心流程。在协议层面SDK 默认目标协议版本为2025-11-25同时保留2024-11-05的旧版 HTTP 传输可通过 Kconfig 选择JSON-RPC 版本为2.0。支持的方法包括会话生命周期initialize、notifications/initialized2025 协议下做门控工具tools/list支持基于 cursor 的分页params.limit上限为 128、tools/call支持params.task任务增强模式资源resources/list、resources/read、resources/subscribe、resources/unsubscribe、resources/templates/listPromptprompts/list、prompts/get补全completion/complete可选 Provider任务实验性tasks/list、tasks/get、tasks/result、tasks/cancel其他logging/setLevel、pingMCP 2025 返回{}所有列表操作均受 mutex 保护支持多线程环境下的安全访问内置参数校验类型检查 范围约束。快速上手 MCP Server在 ESP32 上运行设备控制服务示例结构与功能特性服务端示例位于 examples/mcp/mcp_server核心实现见 main/mcp_server.c。它展示如何在 ESP32 上实现 MCP 服务端覆盖设备状态查询、音量控制、亮度调节、主题切换、HSV/RGB 颜色控制以及 Resource / Prompt / Completion / Tasks 四类能力完整特性包括设备状态查询JSON 返回音量控制0–100及范围校验屏幕亮度调节0–100主题切换light/darkHSV 颜色控制数组参数、RGB 颜色控制对象参数资源注册与读取resources/list、resources/readPrompt 注册与渲染prompts/list、prompts/get参数补全 Providercompletion/complete任务模式工具调用tools/callparams.task{}可用tasks/*轮询完整 JSON-RPC 2.0 支持、内置参数校验、工具与属性链表的线程安全管理、HTTP 传输硬件要求与工程配置搭载 ESP32/ESP32-S2/ESP32-S3/ESP32-C3/ESP32-C6 SoC 的开发板USB 数据线供电与烧录、Wi-Fi 路由器在配置和构建前先设置正确的芯片目标idf.py set-target chip_name打开 menuconfig在Example Connection Configuration菜单下设置 Wi-Fi SSID 与密码idf.py menuconfig编译、烧录并监视串口输出idf.py -p PORT flash monitor退出串口监视器按Ctrl-]。烧录后设备联网并启动 MCP 服务端串口日志形如I (2543) wifi:connected with MySSID, aid 1, channel 6, BW20, bssid xx:xx:xx:xx:xx:xx I (3542) example_connect: - IPv4 address: 192.168.1.100 I (3552) mcp_server: MCP Server started on port 80 I (3553) mcp_server: MCP endpoint registered: /mcp_server默认 endpoint 为/mcp_server默认端口为 80。用 curl 验证服务端从工具列表到任务模式服务端启动后可用 curl 或任意 HTTP 客户端向http://设备IP/mcp_server发送 JSON-RPC 2.0 请求验证。获取工具列表curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d { jsonrpc: 2.0, id: 1, method: tools/list, params: {} }调用工具获取设备状态curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d { jsonrpc: 2.0, id: 2, method: tools/call, params: { name: self.get_device_status, arguments: {} } }设置音量带范围校验curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d { jsonrpc: 2.0, id: 3, method: tools/call, params: { name: self.audio_speaker.set_volume, arguments: { volume: 75 } } }设置亮度、主题、HSV 与 RGB# 亮度 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:4,method:tools/call,params:{name:self.screen.set_brightness,arguments:{brightness:60}}} # 主题 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:5,method:tools/call,params:{name:self.screen.set_theme,arguments:{theme:dark}}} # HSV数组参数 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:6,method:tools/call,params:{name:self.screen.set_hsv,arguments:{HSV:[180,50,80]}}} # RGB对象参数 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:7,method:tools/call,params:{name:self.screen.set_rgb,arguments:{RGB:{red:255,green:128,blue:0}}}}资源操作list / read / templates / subscribe / unsubscribe# 列出资源 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:8,method:resources/list,params:{}} # 读取资源 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:9,method:resources/read,params:{uri:device://status}} # 列出资源模板 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:10,method:resources/templates/list,params:{}} # 订阅 / 取消订阅资源更新 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:11,method:resources/subscribe,params:{uri:device://status}} curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:12,method:resources/unsubscribe,params:{uri:device://status}}Prompt 操作与参数补全# 列出 Prompt curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:13,method:prompts/list,params:{}} # 获取 Prompt curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:14,method:prompts/get,params:{name:status.summary,arguments:{device:screen}}} # 参数补全 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:15,method:completion/complete,params:{ref:{type:ref/prompt,name:status.summary},argument:{name:device,value:s}}}任务模式异步工具调用与轮询# 启动异步任务taskId 位于响应的 result.task 中 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:16,method:tools/call,params:{name:self.get_device_status,arguments:{},task:{}}} # 查询任务列表 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:17,method:tasks/list,params:{}} # 按 task id 查询状态 / 结果 / 取消 curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:18,method:tasks/get,params:{taskId:task_id}} curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:19,method:tasks/result,params:{taskId:task_id}} curl -X POST http://192.168.1.100/mcp_server \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:20,method:tasks/cancel,params:{taskId:task_id}}说明tasks/result返回的是底层tools/call的结果对象如content/isError响应中不会重复回显taskId。任务模式属于 MCP 2025 实验性能力。SSE 流式传输与端到端测试notifications/resources/updated属于服务端通知需通过 Streamable HTTP SSE 下发notifications/resources/list_changed在资源注册表变化如资源 add/remove时触发。本示例中的self.resource.touch_status会刻意执行 removeadd因此可以观察到这两类通知。资源订阅是**会话级session-scoped**的POST 与 SSE 需要携带同一个MCP-Session-Id才能观察到该会话的更新通知。打开 SSE 流curl -N http://192.168.1.100/mcp_server \ -H Accept: text/event-stream \ -H MCP-Protocol-Version: 2025-11-25启用 SSE 时服务端会额外注册一个仅 SSE 的入口/mcp_server_sse该入口要求所有 POST 请求必须携带MCP-Session-Id来自 SSE 响应头HTTP 层返回 202/空 bodyJSON-RPC 响应通过 SSE 事件下发# 1) 打开 SSE 流并记录响应头中的 MCP-Session-Id curl -N -D /tmp/mcp_sse.hdr http://192.168.1.100/mcp_server_sse \ -H Accept: text/event-stream \ -H MCP-Protocol-Version: 2025-11-25 # 2) 使用 session id 发送 POST响应通过 SSE 返回 SESSION_ID$(sed -nE s/^MCP-Session-Id:[[:space:]]*([^[:space:]\r]).*/\1/ip /tmp/mcp_sse.hdr | sed -n 1p | tr -d \r) curl -i -X POST http://192.168.1.100/mcp_server_sse \ -H Content-Type: application/json \ -H MCP-Protocol-Version: 2025-11-25 \ -H MCP-Session-Id: ${SESSION_ID} \ -d {jsonrpc:2.0,id:1,method:ping,params:{}}仓库还提供了 test_sse_e2e.sh 全链路 smoke test 脚本覆盖initialize、ping、全部tools/call、resources/*、prompts/*、completion/complete、任务模式、JSON-RPC batch、错误包校验以及 SSE 通知与带MCP-Session-IdLast-Event-ID的重连流程# 默认执行基于 Streamable HTTP请对 /mcp_server 使用 bash test_sse_e2e.sh 192.168.1.100 mcp_server # 打印每个 JSON-RPC 响应 bash test_sse_e2e.sh 192.168.1.100 mcp_server --verbose # 严格模式对响应关键字段做断言会等待 SSE heartbeat额外约 15-20 秒 bash test_sse_e2e.sh 192.168.1.100 mcp_server --strict--strict模式会额外校验resources/templates/list必须包含device://sensors/{id}、prompts/list必须包含status.summary、任务模式响应必须包含taskId等关键字段。深入示例实现工具、属性与资源是如何注册的已注册工具一览工具名参数说明self.get_device_status无获取设备状态JSONself.audio_speaker.set_volumevolume(0-100)设置音量self.screen.set_brightnessbrightness(0-100)设置亮度self.screen.set_themetheme(string)设置主题self.screen.set_hsvHSV(array[3])设置 HSVself.screen.set_rgbRGB(object)设置 RGBself.resource.touch_status无触发notifications/resources/updated以测试 SSEself.server.roots_list无向当前会话发送服务端主动roots/list请求self.server.sampling_create无向当前会话发送服务端主动sampling/create请求self.server.elicitation_request无向当前会话发送服务端主动elicitation/request请求已注册 Resource / Prompt / Completion类型名称/URI说明Resourcedevice://status返回当前模拟设备状态 JSONResource Templatedevice://sensors/{id}按传感器维度组织的模板 URIPromptstatus.summary生成设备状态总结 PromptCompletion参数theme/device返回建议补全值以资源读取为例源码 mcp_server.c 中的回调函数展示了一个标准的resources/read实现回调接收uri通过输出参数返回 MIME 类型与文本内容此处为application/json类型的设备状态 JSON体现引擎层对 Resource 语义的处理方式。属性类型示例为工具声明参数模式工具属性通过esp_mcp_property_*系列 API 创建并挂载到工具上支持带范围、带默认值的多种类型// 整型带范围 esp_mcp_property_t *property esp_mcp_property_create_with_range(volume, 0, 100); esp_mcp_tool_add_property(tool, property); // 整型带默认值 property esp_mcp_property_create_with_int(param, 10); esp_mcp_tool_add_property(tool, property); // 布尔带默认值 property esp_mcp_property_create_with_bool(enabled, true); esp_mcp_tool_add_property(tool, property); // 字符串带默认值 property esp_mcp_property_create_with_string(theme, light); esp_mcp_tool_add_property(tool, property); // 数组JSON 字符串默认值 property esp_mcp_property_create_with_array(HSV, [0, 100, 360]); esp_mcp_tool_add_property(tool, property); // 对象JSON 字符串默认值 property esp_mcp_property_create_with_object(RGB, {\red\:0,\green\:120,\blue\:240}); esp_mcp_tool_add_property(tool, property);HTTP 传输的初始化方式示例默认使用 HTTP 传输MCP 服务端通过 HTTP POST 接收 JSON-RPC 2.0 请求初始化代码展示了 Manager 层与传输层的协作httpd_config_t http_config HTTPD_DEFAULT_CONFIG(); esp_mcp_mgr_config_t mcp_mgr_config { .transport esp_mcp_transport_http_server, .config http_config, .instance mcp, }; ESP_ERROR_CHECK(esp_mcp_mgr_init(mcp_mgr_config, mcp_mgr_handle)); ESP_ERROR_CHECK(esp_mcp_mgr_start(mcp_mgr_handle)); ESP_ERROR_CHECK(esp_mcp_mgr_register_endpoint(mcp_mgr_handle, mcp_server, NULL));默认 endpoint 为/mcp_server默认端口为 80可通过esp_mcp_mgr_register_endpoint()按需修改路径启用 SSE 时会额外提供/mcp_server_sse。扩展自定义工具的四步流程定义工具回调从属性列表读取参数并返回esp_mcp_value_tstatic esp_mcp_value_t my_tool_callback(const esp_mcp_property_list_t* properties) { int value esp_mcp_property_list_get_property_int(properties, param); ESP_LOGI(TAG, Tool called with param: %d, value); return esp_mcp_value_create_bool(true); }创建工具esp_mcp_tool_t *tool esp_mcp_tool_create(my_tool, Tool description, my_tool_callback);添加属性可选esp_mcp_property_t *property esp_mcp_property_create_with_int(param, 10); esp_mcp_tool_add_property(tool, property);注册工具esp_mcp_add_tool(mcp, tool);MCP Client让 ESP32 主动调用远端 MCP 服务客户端示例位于 examples/mcp/mcp_client演示将 ESP 设备作为 MCP 客户端通过 HTTP 调用远端 MCP 服务端。其核心流程为连接 Wi-Fiprotocol_examples_common使用内置HTTP 客户端传输初始化 MCP 管理器按顺序发送 JSON-RPC 请求先initialize并等待其响应返回再做tools/list可通过nextCursor分页、动态/静态tools/call可选resources/*、prompts/*演示请求由 Kconfig 控制。initialize 与 notifications/initialized 的协商细节示例会请求较新的 MCP 协议版本initialize返回中协商得到的protocolVersion决定是否必须发送notifications/initialized。MCP 管理器esp_mcp_mgr在协商版本按字典序新于2024-11-05时会自动发送notifications/initializedSDK 内为字典序比较无需再自行调用esp_mcp_mgr_post_initialized若你在initialize响应回调里手动发送管理器不会再发第二份。在initialize响应尚未完成时就发送tools/list或tools/call可能破坏会话顺序因此示例会等待挂起的initialize响应结束再继续。工程配置构建前先idf.py set-target chip_name然后idf.py menuconfigExample Connection Configuration菜单设置 Wi-Fi SSID 与密码Example Configuration菜单下客户端相关的可配置项包括配置项说明Remote MCP server hostMCP 服务端主机名或 IPRemote MCP server portMCP 服务端端口Remote MCP endpoint name用作POST /endpoint的 HTTP 路径Enable resources/* demo requests启用resources/list、resources/templates/list、resources/readDemo resources/read URI启用时resources/read使用的 URIEnable prompts/* demo requests启用prompts/list与prompts/getDemo prompts/get name启用时prompts/get使用的 prompt 名称Enable tools/list pagination demo使用nextCursor请求后续页Max tools/list pages分页循环的上限Enable dynamic tools/call from tools/list result对列表中首个发现的工具以{}调用编译烧录idf.py -p PORT flash monitor示例输出形如I (...) example_connect: - IPv4 address: 192.168.1.10 I (...) mcp_client: Remote base_urlhttp://192.168.1.100:80, endpointmcp_server I (...) mcp_client: [Success] Endpoint: mcp_server与 mcp_server 示例联调编译、烧录并运行 examples/mcp/mcp_server在日志中记下设备 IP在mcp_client示例中配置Remote MCP server host填服务端 IP如192.168.1.100、Remote MCP server port填服务端端口默认80、Remote MCP endpoint name与端点路径一致默认mcp_server烧录并运行mcp_client观察initialize、tools/list、tools/call等回调输出。客户端侧若需自定义 JSON-RPC也可使用esp_mcp_mgr_perform_handle()直接发送自构造的 JSON 请求SDK 也支持通过回调实现自定义传输。API 参考速览按能力分组的接口模块官方文档将 MCP API 按能力分组便于按需查阅详见 docs/zh_CN/mcp/模块用途核心与管理器MCP 生命周期、请求分发以及传输管理器/会话处理相关接口工具与数据工具定义与执行接口以及公共属性/数据值结构Prompt/Resource/CompletionPrompt/Resource 提供接口以及 Completion 回调接口对应的头文件分散在 components/mcp-c-sdk/include/核心与管理器esp_mcp_engine.h引擎核心、esp_mcp_mgr.h管理器/传输层工具与数据esp_mcp_tool.h工具接口、esp_mcp_property.h属性接口、esp_mcp_data.h数据值接口Prompt/Resource/Completionesp_mcp_prompt.h、esp_mcp_resource.h、esp_mcp_completion.h。作为独立组件mcp-c-sdk 也支持通过 ESP Component Registry 安装到任意 ESP-IDF 工程需 ESP-IDF v5.4idf.py add-dependency espressif/mcp-c-sdk*常见问题排查Wi-Fi 连接失败检查 menuconfig 中的 Wi-Fi 配置SSID/密码并确保设备在信号覆盖范围内无法访问 MCP 服务确认设备 IP确保客户端与设备在同一局域网核对host/port/endpoint是否与服务端一致工具调用报错检查 JSON-RPC 请求格式与参数值是否符合工具的属性模式类型与范围SSE 通知观察不到确认 POST 与 SSE 使用同一个MCP-Session-Id会话级订阅若未启用 SSEGET 返回 405可先验证resources/subscribe/resources/unsubscribe的请求响应行为。小结通过 mcp-c-sdk 组件ESP32 系列芯片可以在资源受限的嵌入式环境中完整承载 MCP 服务端与客户端角色服务端侧以标准化 JSON-RPC 工具对外暴露设备能力客户端侧则能主动发现并调用远端 MCP 服务。结合 docs/zh_CN/ai/mcp.rst 提供的官方说明、mcp_server 示例与 mcp_client 示例你可以快速完成从联调验证到自定义工具扩展的完整开发闭环将 AI Agent 能力真正落地到 IoT 设备端。【免费下载链接】esp-iot-solutionEspressif IoT Library. IoT Device Drivers, Documentations and Solutions.项目地址: https://gitcode.com/GitHub_Trending/es/esp-iot-solution创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价