跳到主内容

MCP 调试常见问题:从连不上到一直挂起的排查手册

100%
MCP 调试常见问题:从连不上到一直挂起的排查手册

先给结论

MCP 调试常见问题里,八成集中在三件事:路径没写绝对路径、环境变量没传进去、往 stdout 打了日志污染了协议流。剩下的两成是协议版本与能力声明不匹配。官方给出的第一原则很明确:先用 MCP Inspector 单独测通 server,再接进客户端——在客户端里调试等于蒙眼找针。

问题一:server 起不来

典型表现是客户端显示已连接但立刻断开,或直接报 spawn 失败。逐项排查:

  • 路径问题:客户端启动 stdio server 时的工作目录是不确定的(macOS 上可能是 /)。配置里必须用绝对路径,不要用 ./data 这种相对路径。
  • 可执行文件找不到:command 写 python / node 时,客户端可能拿不到你以为的那个解释器,直接写完整路径最稳。
  • 权限问题:脚本没有执行权限、虚拟环境未激活。
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem",
               "/Users/username/data"]
    }
  }
}

问题二:环境变量没生效

stdio 方式下,server 只继承客户端给的一小部分环境变量,.env 不会自动加载。密钥必须显式写进配置的 env 字段,或者在 Inspector 的连接面板里填。

{
  "mcpServers": {
    "myserver": {
      "command": "mcp-server-myapp",
      "env": { "MYAPP_API_KEY": "some_key" }
    }
  }
}

问题三:往 stdout 打了日志(stdio 的隐形杀手)

stdio 传输用 stdout 传 JSON-RPC 消息。任何 print / console.log 都会插进消息流,导致解析失败或进程挂死。正确做法是日志一律走 stderr,或用协议提供的日志通知。

import logging
logger = logging.getLogger(__name__)

@mcp.tool()
async def fetch_report(report_id: str) -> str:
    """Fetch a report by id."""
    logger.info("Fetching report %s", report_id)   # 走 stderr
    return f"Report {report_id} is ready."

注意:基于 notifications/message 的日志机制在新版协议中已标记废弃,新代码优先用 stderr 或 OpenTelemetry 。

“工具调用后一直转圈不返回”这种症状,第一反应就该去查是不是哪行 print 忘了删。这是 stdio server 最高频的故障,且报错信息往往完全指不到真凶。

问题四:协议版本与能力声明不匹配

  • 版本不兼容会拿到 UnsupportedProtocolVersionError (-32022),错误信息里会列出 server 支持的版本——用它来对齐客户端。
  • 请求缺少必需字段会返回 -32602 (Invalid params):每个请求都要带协议版本与客户端能力声明。
  • server 需要某项客户端能力(如 elicitation)而请求没声明,会返回 MissingRequiredClientCapabilityError (-32021),并指明缺哪个。

排查手段:调用 server/discover 看版本支持,同时检查请求里声明的能力是否与 server 期望一致。

标准排查流程


  1. 先在终端单独运行 server,确认它自己能启动、没有运行时报错。

  2. 用最新版 Inspector 连接(npx @modelcontextprotocol/inspector),看握手是否成功、工具列表是否齐全。

  3. 在 Inspector 里逐个测工具:正常参数 → 边界值 → 非法值,每个至少三个用例。

  4. 看通知面板的完整请求响应,确认参数传递与返回格式符合 inputSchema 。

  5. 做一次断线重连,确认 server 能正确处理重复初始化。

  6. Inspector 全绿后再接进客户端;仍失败则去查客户端日志(Claude Desktop 在 macOS 的 ~/Library/Logs/Claude/、 Windows 的 %APPDATA%\Claude\logs)。

常见报错速查表

症状最可能原因处理
连接后立刻断开server 启动崩溃终端单独跑一遍看报错
工具找不到未声明 tools 能力检查 ServerCapabilities 与注册代码
Invalid params参数与 inputSchema 不符收紧 schema 或修正调用
一直挂起无响应往 stdout 打了日志改走 stderr
版本不匹配客户端/服务端协议版本差异用 discover 对齐版本
配置改了没生效客户端未重启保存后完全退出重启

把日志做对,胜过事后乱猜

官方建议至少记录五类事件:启动步骤、资源访问、工具执行、错误条件、性能指标。日志用标准的 RFC 5424 八个级别,客户端通过请求里的日志级别字段按需订阅。 stdio server 打到 stderr 会被宿主自动捕获,这是最省事的路径;走 HTTP 传输时 stderr 不会被客户端收集,需要自己的日志聚合或 OpenTelemetry 。


Inspector 连不上,一定是 server 的问题吗?
不一定。先确认用的是最新版 Inspector(旧版可能不支持新协议特性),再确认连接面板里填了正确的环境变量——很多人卡在这一步,表现为”连上了但工具全报错”。

为什么在 Inspector 里正常,接到客户端就失败?
差异通常在环境与路径:客户端启动 server 时的工作目录和环境变量与你在终端里完全不同。把配置里的相对路径全改成绝对路径、密钥全写进 env,基本就能解决。

通知面板刷得太快看不清怎么办?
先把日志级别调到 warning 过滤掉 debug 消息,定位到具体问题后再切回 debug 看细节,配合面板的搜索过滤使用。

HTTP 传输的 server 怎么调试?
stderr 不会被客户端收集,需要服务端自己做日志聚合或接 OpenTelemetry;请求层面可以用 curl 或浏览器开发者工具的网络面板直接看请求与 SSE 流。

三句话记住 MCP 调试
① 永远先用 Inspector 测通再接客户端;② 路径一律绝对、密钥一律写进 env;③ stdio server 绝不往 stdout 打任何东西。

相关阅读:Claude Desktop 配置 MCP 教程、MCP Server 自己搭建教程、MCP 和 Function Calling 的区别。参考来源:Model Context Protocol 官方 Debugging 文档。

这篇有帮助吗?
云上的幻象
云上的幻象查看主页

七彩云博客,分享 WordPress 建站实战与 AI 工具测评,覆盖服务器运维、站长工具、软件资源与电商运营干货,专注原创实用的主题插件、网站加速与安全优化教程。

762文章4评论

相关文章

评论 (0)

欢迎你,新朋友,感谢参与互动!文明发言,理性交流 · 首次评论将在审核后展示