基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
  • 知识卡片碎片时间过考点
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
    • AI 热点每日 AI 资讯与动向
AI 工作台
简历
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
开源项目2026-11-05 13:07

MCP 工具列表为空?先排查标准输出

dev.to · AI#MCP#开源#故障排查
Editor brief · 编辑速览

文章解释 stdio 模式下普通日志污染 JSON-RPC 输出,如何导致解析失败、工具不可见或连接中断。配套 MIT 许可的 TypeScript 模板还针对异常隔离、密钥配置和 CI 缺失等问题提供防护。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

MCP server 明明连上了,客户端却看不到工具,问题可能出在业务代码之外:一条启动日志就能污染协议通信,缺少 API key 也可能让服务提前退出。作者做过 LinkedIn、Twitter/X、Medium 和 Kaggle 的 MCP server,把遇到的接线问题整理成了 TypeScript、MIT 许可的 mcp-server-starter。

它的价值在于把日志、参数校验、错误处理和 CI 这些容易漏掉的环节提前收好。不过,原文提供的是实现思路和使用入口,没有给出故障率或不同模板的对照测试。

连上了却没有工具,先查 stdout

使用 stdio 传输时,stdout 是 MCP 的协议通道,每个字节都必须属于 JSON-RPC 消息。随手写一句 console.log("starting..."),就会把普通文本塞进协议流。客户端可能报 JSON 解析错误、显示空工具列表,或者直接断开连接。

在 stdio MCP server 里,日志写到哪里会影响协议能否正常工作。

模板让 src/logger.ts 统一写 stderr,Claude Desktop 和 Cursor 会把它作为服务日志展示。LOG_LEVEL 支持 debug、info、warn、error。

同时,ESLint 的 no-console 规则只放行 console.error,让误写的 console.log 在 lint 和 CI 阶段就被拦住。启动日志里的密钥也只展示类似 sk-t…7890 的掩码。

这几层分别解决输出位置、代码约束和敏感信息暴露,不能靠一句「记得别打印」替代。

参数错误和上游失败,应该停在哪一层

模板使用 SDK 1.x 的 McpServer.registerTool API,通过 zod 的 inputSchema 校验工具参数。SDK 会先校验,再执行 handler;.describe() 则给模型提供填写参数时的说明。

下面这段定义同时约束搜索词和结果数量:

export const exampleSearchInput = {
  query: z.string().trim().min(1, 'query must not be empty').max(200).describe('Text to search for'),
  limit: z.number().int().min(1).max(50).default(10).describe('Maximum number of results (1-50)')
};

重点看 query 的 .trim().min(1):只有空格的输入也过不了校验。query 最长 200 个字符,limit 必须是 1–50 的整数,默认 10。

进入 handler 后,执行过程由 runTool() 包裹。作者称,handler 抛出的错误会转换成带 isError: true 的 MCP 结果,返回简短、可供模型采取下一步行动的信息;完整错误和堆栈写入 stderr。

这里保护的是工具执行的错误边界。原文没有展示 runTool() 的实现,也没有讨论进程级异常、超时或重试,不能据此认定所有故障都能被兜住。

缺少密钥时,为什么还要让工具可见

src/config.ts 延迟读取 EXAMPLE_API_KEY。没有配置密钥,服务依然启动并列出工具;调用依赖密钥的工具时,才返回明确的 ConfigError,提示把密钥加入 MCP 客户端配置的 env 块。

这个取舍能把「工具有没有注册」和「凭据能不能用」分开排查。密钥可以放在客户端的 env 中,也可以放入已被 .gitignore 排除的本地 .env;maskSecret() 用于展示配置状态。

下面是原文的启动和检查命令:

git clone https://github.com/Dishant27/mcp-server-starter.git my-mcp-server
cd my-mcp-server
npm install && npm run build
EXAMPLE_API_KEY=your-key npm run inspect   # 打开 MCP Inspector

最后一行会为这次检查提供 EXAMPLE_API_KEY,并启动 MCP Inspector;your-key 需要换成实际值。

新增工具需要复制 src/tools/exampleSearch.ts,在 src/tools/index.ts 注册,然后重新构建。README 还提供了 Claude Desktop 和 Cursor 配置。GitHub Actions 会在每次 push 和 PR 时,分别用 Node 20、22 执行 npm ci、typecheck、lint 和 build。

我的判断

这套模板最值得借鉴的是把约定变成约束:stdout 的使用有 lint 把关,参数有 schema 把关,工具失败有统一返回格式。对于第一次写 MCP server 的程序员,这些比多放几个示例工具更实用。

但「多数 starter 会坏」属于作者的经验判断,原文没有样本和对照数据。密钥掩码及 .gitignore 也只覆盖部分泄露路径,不能替代完整的凭据管理。

延迟校验密钥适合本地接入和调试;如果团队要求部署时立即发现配置缺失,启动即校验也有合理性。取舍取决于更看重工具发现体验,还是部署检查的及时性。

能拿来做什么

  • 写 Node 或 TypeScript 的 stdio MCP server 时,先统一日志入口,再用 no-console 限制 stdout 输出,把协议污染提前挡在 CI。
  • 给 AI 调用的工具定义输入时,同时写清 zod 约束和 .describe(),覆盖空字符串、数量范围及默认值。
  • 遇到工具列表为空时,先检查 stdout 和启动阶段的配置读取,再用 MCP Inspector 验证注册与调用,逐步缩小故障范围。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
AI 功能上线后,如何发现质量退化
下一篇
Conductor云端停服,用户需迁移数据

资讯速览

dev.to · AI · 2026-11-05 13:07

AI 评分 8.0 / 10

相关标签

#MCP#开源#故障排查

继续阅读

  • CUDA 13.5 强化 Rubin 与多卡计算
  • AI 功能上线后,如何发现质量退化
  • Conductor云端停服,用户需迁移数据
  • 把人工审批绑定到AI的具体执行动作
  • AI客服上线前先测工单状态流转