Stack-chan 的 MCP 客户端服务测试:在 Moddable 上验证 Model Context Protocol 客户端全流程

发布时间:2026/10/14 2:15:03
Stack-chan 的 MCP 客户端服务测试:在 Moddable 上验证 Model Context Protocol 客户端全流程 嵌入式物联网智能硬件机器人硬件开发前端AI 应用【免费下载链接】stack-chanA JavaScript-driven M5Stack-embedded super-kawaii robot.项目地址https://gitcode.com/gh_mirrors/sta/stack-chan点击查看免费下载Stack-chan 是一个由 JavaScript 驱动的 M5Stack 嵌入式机器人其固件在 Moddable SDK 之上实现了 Model Context ProtocolMCP能力既可以在设备上作为 MCP 服务器向 AI 客户端暴露工具也可以作为 MCP 客户端调用远端服务器的工具。本篇以firmware/host/modules/connectivity/mcp-client/__tests__/mcp-client-service/下的测试文档为骨架完整讲解如何通过本地 dummy 服务器 真实 MCP 客户端的方式验证MCPClientService的初始化、工具列举、工具调用、错误处理与重置重连等核心行为并结合仓库源码说明其底层协议实现与上层集成方式。读完本文你将掌握该测试的启动方法、执行流程、预期输出以及MCPClientService各公共 API 的语义与使用限制。测试目标一条端到端的 MCP 客户端验证链路测试文档README将本次测试概括为三个步骤启动一个带测试工具的 dummy MCP 服务器创建一个 MCP 客户端并连接该服务器验证一系列客户端操作包括初始化连接Initialize connection列举可用工具List available tools以不同参数调用工具Call tools with different parameters对非法请求的错误处理Error handling for invalid requests重置与重新初始化Reset and re-initialization这套链路的最大价值在于它不依赖任何外部服务在单台 Linux 主机上即可闭环验证客户端与服务器两端的协议行为。dummy 服务器由仓库内的MCPServerService实现mcp-server.ts客户端则直接使用被测对象MCPClientServicemcp-client.ts两者通过http://localhost:8081/mcp进行 Streamable HTTP 传输属于以真验证真的集成级测试而非简单的单元 mock。Dummy 服务器与三个测试工具测试入口 mcp-client-service.test.ts 首先定义了三个Tool对象并注入MCPServerService工具名说明参数处理逻辑echo回显输入消息messagestring必填返回Echo: messageadd两数相加a、bnumber均必填校验数字合法性后返回a b 和get_status返回服务器状态无返回Server is running normally这三个工具的设计非常有代表性echo覆盖字符串参数add覆盖数值参数并展示参数校验失败时的异常路径Number.isNaN检查get_status覆盖无参数工具调用。其中add在参数非法时会抛出Both arguments must be valid numbers该异常会被服务器端#handleToolsCall捕获并包装为Tool execution failed: ...最终以 JSON-RPC error 形式返回客户端。服务器以如下方式启动测试代码 L74-L78const _server new MCPServerService({ port: 8081, // 使用不同端口以避免冲突 token: test-token, tools: testTools, })注意测试特意选用8081端口注释明确说明是为了与默认端口8080错开、避免冲突。随后await asyncWait(1000)等待服务器完成启动再创建客户端const client new MCPClientService({ url: http://localhost:8081/mcp, token: test-token, })客户端与服务器共用同一个test-token对应服务器端POST /mcp的Authorization: Bearer token鉴权要求。运行方式环境准备与执行命令文档给出的 Linux 运行方式为source ~/.local/share/xs-dev-export.sh npm run test:moddable -- ./host/modules/connectivity/mcp-client/__tests__/mcp-client-service/manifest.test.json其中第一条命令导入 Moddable SDK 的xs-dev环境变量MODDABLE路径等这是后续mcconfig构建与mcsim模拟器运行的前提第二条命令将测试清单文件作为参数传给固件模块测试运行器。在 package.json 中test:moddable对应脚本为node scripts/run-module-tests.js。该运行器run-module-tests.js会递归扫描参数指定的manifest.test.json默认根目录为host/app、host/modules、mods/examples用mcconfig -d -m -p lin -t build将清单构建为mc.so通过mcsim模拟器运行并借助 xsbug 日志服务监听输出以日志中出现logok/log判定测试通过对应测试文件末尾的trace(ok\n)超时或出现XS abort、stack overflow等致命标记则判定失败。因此该测试本质上是在 Linux 桌面模拟器lin平台上完整运行 Moddable 的 fetch、HTTP 服务与 Timer 能力而不是在真实 ESP32 硬件上执行。测试清单 manifest.test.json 拆解manifest.test.json 定义了该测试的构建依赖与平台配置{ include: [ $(MODDABLE)/examples/manifest_base.json, $(MODDABLE)/examples/manifest_net.json, $(MODDABLE)/examples/manifest_typings.json, $(MODDABLE)/examples/io/listener/listen/manifest_listen.json, ../../../../../app/manifest_typings.json, ../../manifest.json, ../../../mcp-server/manifest.json, ../../../../testing/manifest.json ], modules: { main: ./mcp-client-service.test }, platforms: { lin: { config: { network: { interface: ethernet } } } } }各 include 项的作用manifest_base.json/manifest_net.jsonModdable 基础运行库与网络栈manifest_typings.jsonTypeScript 类型定义manifest_listen.json监听相关能力app/manifest_typings.json应用层类型定义../../manifest.json即 mcp-client 模块清单它 include 了$(MODDABLE)/examples/io/tcp/fetch/manifest_fetch.json并将模块名mcp-client映射到./mcp-client同时preload该模块../../../mcp-server/manifest.json引入MCPServerService实现供测试搭建 dummy 服务器../../../../testing/manifest.json提供testing/assert等测试基础设施。platforms.lin.config.network.interface ethernet显式指定模拟器走以太网接口保证 fetch 与 HTTP 服务在lin平台下可用。这是该测试能够在一个进程内同时起服务端与客户端的关键。六个测试步骤与预期输出测试主体用trace()打印每一步的通过✓或失败✗状态对应文档Expected Output一节描述的观察点。六个步骤依次为Test 1Initialize clientL92-L102 调用client.initialize()成功后打印协议版本Protocol Version、服务器名称与版本Server Name/Server Version。客户端发送的初始化请求参数见 mcp-client.ts L124-L133为{ protocolVersion: 2024-11-05, capabilities: { tools: {} }, clientInfo: { name: stack-chan-mcp-client, version: 1.0.0 } }服务器端#handleInitialize则返回protocolVersion: 2024-11-05、capabilities.tools以及serverInfo: { name: stack-chan-mcp-server, version: 1.0.0 }。Test 2List toolsL108-L119 调用client.listTools()遍历返回结果逐行打印- name: description预期能看到echo、add、get_status三个工具。Test 3Call echo toolL124-L131client.callTool(echo, { message: Hello Stack-chan! })预期结果为Echo: Hello Stack-chan!。Test 4Call add toolL136-L143client.callTool(add, { a: 42, b: 58 })预期结果为42 58 100。Test 5Call get_status toolL148-L155client.callTool(get_status)预期结果为Server is running normally。Test 6Re-initialize after resetL160-L172 先调用client.reset()再重新initialize()随后再次调用echo验证工具在重置后依然可用。这一步验证的是会话断开后可重新建立连接的状态恢复能力。步骤之间穿插await asyncWait(30)注释说明是为了给垃圾回收留出时间。整体流程覆盖了文档声称的初始化、工具列举、不同参数的工具调用、错误处理、重置与重新初始化全部要点。深入MCPClientService协议与状态机细节MCPClientService是本次测试的被测对象实现于 mcp-client.ts。其公共 API 与内部状态机如下配置项 MCPClientConfigexport interface MCPClientConfig { url: string // MCP 服务端地址如 http://localhost:8081/mcp token?: string // Bearer token可选 }构造函数会去除url末尾多余的/L112避免拼出//mcp之类的路径。公共方法语义方法行为关键实现细节initialize()与服务器建立连接已初始化时重复调用会抛出Client is already initialized成功后将#initialized置为true并返回InitializeResult协议版本、能力、服务器信息listTools()获取可用工具列表内部先调用#ensureInitialized()未初始化时抛Client not initialized. Call initialize() first.callTool(name, args?)执行指定工具同样要求先初始化arguments缺省时发送空对象{}isInitialized()查询是否已初始化供上层在接入客户端前做可用性判断reset()清空客户端状态将#initialized置false、请求 ID 归零、清空#sessionId底层请求发送#sendRequest每次请求都构造标准 JSON-RPC 2.0 报文L195-L203{ jsonrpc: 2.0, id: 1, method: initialize, params: { ... } }请求 ID 由#generateRequestId()自增产生确保同一客户端实例内消息可关联。HTTP 头部的构造体现了对 MCP 规范的遵循L207-L221Content-Type: application/jsonAccept: application/json, text/event-stream注释明确说明客户端必须同时接受两种内容类型以兼容服务器的 JSON 或 SSE 响应配置了 token 时附加Authorization: Bearer token初始化之后的所有请求附带Mcp-Session-Id头在initialize响应的mcp-session-id响应头中提取并保存。响应侧做了三层校验HTTP 状态码非 2xx 时抛HTTP error: status statusTextJSON 响应必须满足jsonrpc 2.0且id与请求 ID 一致否则分别抛Invalid JSON-RPC response/Response ID mismatchJSON-RPC 层出现error字段时抛出包含error.message的异常。这些校验正是对非法请求的错误处理能产生可观测输出的实现基础。SSE 响应的兼容处理#handleSSEResponse当服务器以text/event-stream响应时客户端逐行解析 SSE 帧仅关心data:前缀的数据行遇到[DONE]结束标记或找到id与当前请求匹配的 JSON 载荷即停止mcp-client.ts L271-L311。注释指出由于 Moddable 环境缺乏完善的流式支持当前实现采用退化为整体文本解析的方式属于适配嵌入式环境的务实取舍。服务器侧支撑鉴权、路由与工具分发测试能闭环得益于仓库同时提供了服务器实现。MCPServerServicemcp-server.ts暴露两个 HTTP 端点GET /health免鉴权返回{status:ok}与POST /mcp必须携带 Bearer token。POST /mcp内部按initialize、tools/list、tools/call三个方法名分发L274-L286未知方法返回 JSON-RPC 标准错误-32601 Method not foundJSON 解析失败返回-32700 Parse error。Bearer token 的校验实现在 mcp-auth.tsauthorizeMCPRequest会依次检查是否配置了 tokenmissing-token-configuration、是否携带 Authorization 头missing-authorization、头是否符合Bearer token格式且值一致invalid-authorization。值得注意的是token 比较使用constantTimeEqual常量时间比较实现避免时序侧信道token 未配置时POST /mcp将被一律拒绝。服务器构造时的 token 优先级为构造参数tokenPreference中的mcp.token通过Preference.get(DOMAIN.mcp, token)读取。上层集成MCP 客户端如何变成机器人可用的工具测试文档虽然只覆盖客户端自身行为但MCPClientService在 Stack-chan 固件中的实际用途可以追溯两处源码对话模块桥接mcp-tools.ts 的createMCPChatTools(clients)会遍历传入的MCPClientService[]逐个listTools()并把远端工具转换为本地ChatToolexecute内部调用client.callTool并将content[].text归一化为字符串。其测试 mcp-chat-tools.test.ts 验证了远端 MCP 工具被转成 ChatTool 且调用结果被正确归一化。ChatGPT 对话示例dialogue-chatgpt.ts 的ChatGPTDialogue接受mcpClients?: MCPClientService[]构造参数构造时用isInitialized()过滤未就绪的客户端并在生成工具表时把每个客户端的tools/list结果注册为可执行工具执行时转调mcpClient.callTool。这两处集成印证了客户端测试的价值只有initialize/listTools/callTool/isInitialized/reset这套状态机行为正确上层对话系统才能把机器人自己的工具安全地暴露给 AI 模型调用。排错与延伸验证建议如果测试未通过可优先从以下几方面排查MODDABLE未设置source ~/.local/share/xs-dev-export.sh未执行或路径与本地xs-dev安装位置不一致run-module-tests.js会直接报错退出端口冲突dummy 服务器固定使用8081若本地已有进程占用会触发#startServer的 failed 状态测试输出中将看不到正常的 MCP Client Service Test 流程token 不一致客户端与服务器 token 不匹配时POST /mcp返回401 Unauthorizedinitialize会抛 HTTP 错误重复初始化在未reset()的情况下再次调用initialize()会抛Client is already initialized这正是 Test 6 先reset()再初始化所要规避的场景。延伸验证时也可以参考服务器端测试 mcp-server-service 测试 提供的 curl 命令对独立启动的 MCP 服务器直接发起initialize、tools/list、tools/call请求从 HTTP 层面交叉验证协议行为。小结mcp-client-service测试用约 180 行 TypeScript 在一个进程内搭建了服务器 客户端的完整 MCP 闭环覆盖了MCPClientService的全部公共 API 与关键状态流转初始化握手携带协议版本与客户端信息、工具列举、三种参数形态的工具调用、非法请求的错误传播以及reset()后的重新连接。结合 mcp-client.ts 的源码可以看到这层实现以 JSON-RPC 2.0 为消息格式、以 Streamable HTTP 为传输并针对 Moddable 嵌入式环境做了 SSE 降级解析与轻量状态管理等适配——这正是 Stack-chan 得以在资源受限设备上参与 MCP 生态的工程基础。赞分享嵌入式物联网智能硬件机器人硬件开发前端AI 应用【免费下载链接】stack-chanA JavaScript-driven M5Stack-embedded super-kawaii robot.项目地址https://gitcode.com/gh_mirrors/sta/stack-chan点击查看免费下载相关推荐awesome-mcp-clients开源Model Context Protocol客户端集锦awesome mcp clients开源Model Context Protocol客户端集锦 项目介绍 在当今AI技术飞速发展的背景下Model Con文档知识库QtScrcpy 手机投屏键鼠控制入门无线连接按键映射一次到位QtScrcpy 手机投屏键鼠控制入门无线连接按键映射一次到位 在把手机接上电脑之前帮人查手机只能盯着他的屏幕喊往左滑一点。QtScrcpy 改变的就桌面应用音视频Model Context Protocol开发者指南从零开始构建MCP客户端Model Context Protocol开发者指南从零开始构建MCP客户端 Model Context ProtocolMCP是一个开源协议它让AI人工智能AI Agent工具调用上一篇FIRRTL安全分析硬件编译器中的安全漏洞与防护下一篇Bridgy完整指南掌握反向反馈Backfeed技术让社交互动回归你的网站创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询