如何将SignalR移植到Esp32实现小智设备无缝连接.NET功能拓展MCP服务?

摘要:前言 这段时间迷上了手搓Esp32的小智聊天机器人,也用.NET为小智AI开发了一些MCP转接平台和MCP服务。小智ESP32本身就具备MCP能力,可以调用本地MCP工具和服务端MCP工具,并将结果返回给设备,这个功能一直都有。 如果你有手
前言 这段时间迷上了手搓Esp32的小智聊天机器人,也用.NET为小智AI开发了一些MCP转接平台和MCP服务。小智ESP32本身就具备MCP能力,可以调用本地MCP工具和服务端MCP工具,并将结果返回给设备,这个功能一直都有。 如果你有手搓Esp32的硬件玩具打算,可以关注我的B站账号(绿荫阿广)https://space.bilibili.com/25228512 带你手搓玩具。 小智原本这套架构有个局限性:MCP工具执行完之后,只能同步返回结果或者通过异步邮件通知,设备无法被动接收服务端的消息。比如我想让服务端主动给设备推送一张图片、播放一段语音、或者发送一个文本通知,在之前的架构下是做不到的。 所以我就决定改造小智客户端,集成SignalR实时通信框架。这次改造的核心价值是:通过SignalR消息通道,让设备可以接收各种类型的消息(声音、图片、文本通知),服务端的MCP工具执行成功后,可以根据用户ID推送数据到对应的用户通道。 整个改造涉及SignalR C++客户端的集成、JWT Token认证、扫码登录(基于ESP32本地MCP工具实现)、以及服务端消息推送逻辑。客户端代码都是C++实现的,不过现在AI辅助编程很强大,帮我节省了大量时间。 问题解答 Q: 为什么选择SignalR而不是直接用WebSocket? A: 起初我确实考虑过直接用WebSocket,但SignalR提供了很多开箱即用的功能: Hub抽象:服务端可以轻松实现群组管理,按用户ID推送消息,比如Clients.Group($"Users:{userId}").SendAsync("Notification", message) 消息路由:不需要自己写消息分发逻辑,SignalR的Hub方法调用和事件推送已经很完善了 类型化调用:相比原始WebSocket的字符串消息,SignalR提供了类似RPC的调用体验,代码更清晰 虽然ESP32没有现成的SignalR库,但我找到了微软官方的C++ SignalR客户端(半成品),将它与ESP32的WebSocket组件整合后,就能用上SignalR的这些特性了。至于SignalR自带的重连机制,我没用,小智有自己的循环重连逻辑,更可控一些。 Q: 改造的核心价值是什么?解决了什么问题? A: 改造前,ESP32的MCP工具调用完成后,只能通过两种方式通知: 同步返回:工具执行结果直接返回给调用方 异步邮件:通过邮件发送执行结果 这两种方式都无法满足实时推送的需求。比如我想让服务端在生图完成后立即推送图片给设备显示,或者播放一段语音提示,之前的架构做不到。 改造后,通过SignalR建立了一条服务端到设备的实时消息通道: 服务端的MCP工具执行成功后,可以调用_hubContext.Clients.Group($"Users:{userId}").SendAsync("ShowImage", imageData)将图片推送给设备 设备通过SignalR的事件监听接收消息:connection->on("ShowImage", [](const std::vector<signalr::value>& args) { ... }) 支持推送任意类型的数据:文本、图片(Base64)、语音URL、JSON通知等 这才是这次改造的核心价值:让设备具备被动接收服务端消息的能力,而不仅仅是主动调用和同步返回。 Q: 扫码登录是怎么实现的? A: 扫码登录功能是基于ESP32本地MCP工具实现的,这是小智的固有功能,我只是进行了拓展: 设备启动时检查是否有JWT Token 如果没有Token,调用本地MCP工具display_qrcode在屏幕上显示二维码 二维码内容包含设备ID和服务端地址:https://mcp-server.com/device-login?deviceId=xxx 用户用手机扫码,完成授权。 设备获取Token后保存到NVS(Non-Volatile Storage),下次启动直接使用 这样就实现了设备的快速认证,用户体验很好。扫码认证的服务端是使用开源的keycloak做的,对接了设备认证类型。 名词解释 核心概念 SignalR:微软提供的实时通信框架,封装了WebSocket、Server‑Sent Events和长轮询等传输方式,支持Hub模型、自动重连与消息序列化。适合实现双向、低延迟的实时消息系统。将它移植到嵌入式设备时需考虑客户端实现的体积、内存消耗与线程模型。 Hub(集线器):SignalR的核心抽象,类似于MVC中的Controller。
阅读全文