MCP 调试实战:Inspector、日志规范与连接问题排查链
MCP 集成调试的官方方法:Inspector 交互式测试 UI 为什么是第一站、stdio 与 Streamable HTTP 的日志怎么打(notifications/message 已在 2026-07-28 规范版弃用)、启动失败三类根因与连接失败五步排查链。
操作步骤
看客户端日志
大多数 MCP 客户端都会暴露日志与连接状态(如 Claude Desktop 的日志入口),先读最近的连接错误。
确认进程存活
确认服务器进程真的在运行:命令路径是否正确、是否缺文件、是否有权限——启动失败三类根因逐项过。
Inspector 独立测试
把服务器与客户端解耦:单独用 Inspector 连接并调用一次 tools,区分'服务器本身坏了'与'集成层坏了'。
核对协议版本
调用 server/discover 查看服务器支持的协议版本;版本不匹配会报 UnsupportedProtocolVersionError(-32022),data 字段列出支持的版本列表。
核对 _meta 与能力声明
确认每个请求带 io.modelcontextprotocol/protocolVersion 与 clientCapabilities;缺失报 -32602,未声明能力报 MissingRequiredClientCapabilityError(-32021),按错误信息补声明。
MCP 集成的故障定位有一个官方给定的工具分层:MCP Inspector(交互式测试 UI)、服务端日志(stderr / OpenTelemetry)与客户端开发工具(日志与连接状态)。多数"连不上、调用失败"的问题不需要猜——按本文的排查链走,每一步都有明确的信号源。本文基于 MCP 官方调试指南(2026-09-02 核对),把它整理成可执行的实战流程,并补齐 2026-07-28 规范版带来的日志机制变化。
1. 调试工具总览:三层各管一段
| 工具层 | 管什么 | 关键事实 |
|---|---|---|
| MCP Inspector | 交互式、传输无关的服务器测试 | 连 stdio / Streamable HTTP;调用 tools / prompts / resources;观察通知流;官方定位"第一站" |
| 服务端日志 | 服务器在做什么 | stdio 走 stderr(宿主自动捕获);全传输可走 OpenTelemetry;协议内日志 notifications/message 已于 2026-07-28 规范版弃用 |
| 客户端开发工具 | 客户端视角的日志与连接状态 | 多数 MCP 客户端都有;官方以 Claude Desktop 为例 |
分工逻辑:Inspector 回答"服务器本身好不好",日志回答"运行时发生了什么",客户端工具回答"集成层发生了什么"。排查顺序也应该这样——先解耦服务器,再看运行时,最后看集成。
2. Inspector:把服务器从集成里解耦出来
Inspector 是交互式、与传输无关的测试 UI:连接 stdio 或 Streamable HTTP 服务器,直接调用 tools、prompts、resources,并实时观察通知流。启动方式(本站 MCP 教程既有事实):npx @modelcontextprotocol/inspector(Node 22.19.0+)。
它的核心价值是变量分离:客户端里连不上时,先用 Inspector 单独连一次服务器——
# 独立测试 stdio 服务器(与客户端解耦)
npx @modelcontextprotocol/inspector ./your-server --your-flags
# 在 Inspector UI 里:连接 → 列出 tools → 调用一次 → 看通知流
# 服务器在 Inspector 里正常 = 问题在集成层;在 Inspector 里也失败 = 问题在服务器
3. 服务端日志:stderr、OpenTelemetry 与一条弃用通知
stdio 传输:写到 stderr 的所有消息会被宿主应用自动捕获。严禁写 stdout——stdout 是协议通道,普通日志输出会干扰协议运行。这是 stdio 服务器最常见的自伤方式。
Streamable HTTP 传输:stderr 不会被客户端捕获。用自建日志聚合或 OpenTelemetry 收日志;检查单个请求与 SSE 流用 curl 和浏览器 DevTools 的 Network 面板。
协议内日志的变化:notifications/message 机制已于 2026-07-28 规范版弃用(弃用窗口内仍可用)。新代码把日志落到 stderr 或 OpenTelemetry。仍使用该机制时的两条规则:
- 日志分 8 个 RFC 5424 严重级别(debug 到 emergency);
- 客户端通过请求
_meta里的io.modelcontextprotocol/logLevel字段按请求订阅;服务器不得对未携带该字段的请求发送 notifications/message。
服务端记录日志的最小样子(官方示例形态):
import logging
from mcp.server import MCPServer
logger = logging.getLogger(__name__)
mcp = MCPServer("reports")
@mcp.tool()
async def fetch_report(report_id: str) -> str:
logger.info("Fetching report %s", report_id) # stderr:宿主自动捕获
return f"Report {report_id} is ready."
// Streamable HTTP / 显式协议日志(弃用窗口内):
await server.sendLoggingMessage({
level: "info",
data: "Server started successfully",
});
该记什么?官方点名的五类事件:启动步骤、资源访问、工具执行、错误条件、性能指标。
4. 启动失败:三类根因与两个高频子因
官方把启动问题归为三类:路径问题(可执行文件路径不对、缺必需文件、权限不足)、配置错误(JSON 语法、缺必填字段、类型不匹配)、环境问题(变量缺失、取值错误、权限限制)。其中两个子因出现频率远高于其他:
子因一:工作目录未定义。 客户端拉起 stdio 服务器时,工作目录可能是未定义的(macOS 上可能是 /)——所以配置与 .env 文件里一律用绝对路径。官方给的正反例(以 Claude Desktop 的 claude_desktop_config.json 为例,原则适用于任何 stdio 客户端):
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/username/data"
]
}
}
}
不要写 ./data 这样的相对路径——它在客户端环境里指向哪里,取决于客户端从哪里启动,而你控制不了。
子因二:环境变量继承受限。 stdio 启动的服务器只自动继承有限的、平台相关的环境变量子集。需要自定义时在配置里用 env 键显式注入:
{
"mcpServers": {
"myserver": {
"command": "mcp-server-myapp",
"env": {
"MYAPP_API_KEY": "some_key"
}
}
}
}
5. 连接失败:五步排查链
服务器连不上时,按官方排查链走,每步都有明确信号:
- 看客户端日志——多数客户端暴露日志与连接状态。
- 确认进程存活——路径、缺文件、权限,逐项过启动三类根因。
- Inspector 独立测试——把"服务器坏了"与"集成坏了"分开。
- 核对协议版本——调用
server/discover查看服务器支持的协议版本;不匹配报UnsupportedProtocolVersionError(-32022),data 字段列出支持的版本。 - 核对 _meta 与能力声明——每个请求必须带
io.modelcontextprotocol/protocolVersion与io.modelcontextprotocol/clientCapabilities(建议再带io.modelcontextprotocol/clientInfo);缺必填字段报 -32602(Invalid params,与很多其他畸形输入同码,需结合上下文判读);请求用到客户端未声明的能力(如 elicitation)报MissingRequiredClientCapabilityError(-32021),错误信息点名缺失的能力。
第 5 步的实用技巧:把请求 _meta 与 server/discover 的响应放在一起看——确认双方各自声明了你以为对方声明了的东西。
6. 常见错误与排查
- stdout 打日志:stdio 下必炸——stdout 是协议通道。日志一律 stderr。
- 相对路径:工作目录未定义导致"命令行能跑、客户端必挂"。配置与 .env 全部绝对路径。
- 还在用 notifications/message 做新代码:2026-07-28 规范版已弃用;弃用窗口内可用,但新代码走 stderr / OpenTelemetry,并遵守 logLevel 订阅规则。
- 跳过 Inspector 直接改客户端配置:解耦优先。先证明服务器本身在 Inspector 里可用,再动集成配置。
- 把 -32602 当成"参数写错了":它也可能来自 _meta 缺 protocolVersion / clientCapabilities——先核对 _meta 再查业务参数。
- 日志记了但没用:只记"请求到了"没有价值;按官方五类事件(启动、资源访问、工具执行、错误、性能)布点。
7. 下一步
- MCP 协议与三层架构全景:《Model Context Protocol 完全指南:MCP 工作机制与实战》。
- 从零写一个可被 Inspector 调试的 Server:《自己搭一个 MCP Server:从零到发布的完整指南》。
- 调试之外的安全边界(工具返回值按不可信输入处理):《MCP 安全指南:官方 8 类攻击面与缓解清单》。
关键要点
- MCP Inspector 是官方指定的第一站:交互式、传输无关,能连 stdio / Streamable HTTP 服务器,调用 tools / prompts / resources 并观察通知流
- stdio 服务器日志写 stderr(宿主自动捕获),严禁写 stdout——会干扰协议运行;Streamable HTTP 的 stderr 不被客户端捕获,用自建聚合或 OpenTelemetry,请求与 SSE 流用 curl / 浏览器 DevTools Network 面板
- 协议内日志 notifications/message 已于 2026-07-28 规范版弃用(弃用窗口内仍可用);日志分 8 个 RFC 5424 级别(debug 到 emergency),客户端经 _meta 的 io.modelcontextprotocol/logLevel 按请求订阅,服务器不得对未带该字段的请求发送
- stdio 服务器只继承有限的平台相关环境变量子集;配置里用 env 键注入;工作目录可能未定义(macOS 上可能是 /),配置与 .env 一律用绝对路径
- 启动失败三类根因:路径(可执行文件路径错、缺文件、权限)、配置(JSON 语法、缺必填字段、类型不匹配)、环境(变量缺失/取值错/权限限制)
- 连接失败排查链:客户端日志 → 进程存活 → Inspector 独立测试 → server/discover 验协议版本(UnsupportedProtocolVersionError -32022)→ _meta 必带 io.modelcontextprotocol/protocolVersion 与 clientCapabilities(缺失报 -32602 Invalid params)、未声明能力报 MissingRequiredClientCapabilityError(-32021)
- 该记日志的五类事件:启动步骤、资源访问、工具执行、错误条件、性能指标
常见问题
官方参考
相关文章
MCP 安全指南:官方 8 类攻击面与缓解清单
MCP 官方安全最佳实践拆解:Confused Deputy、Token Passthrough、SSRF、会话劫持、本地 Server 攻击、OAuth URL 校验、stdio 代理安全、权限最小化——每类攻击的原理与官方缓解要求。
阅读全文MCP 服务器开发实战:协议、调试、安全与生产部署
MCP 服务器 production 必备能力:协议深入(JSON-RPC 2.0 / lifecycle / capabilities 协商)、Inspector 调试、安全模式(prompt injection / OAuth scope / 审计)、三种传输选型(stdio / Streamable HTTP / SSE)实战。
阅读全文MCP Server 部署到 Cloudflare Workers:从边缘跑 MCP
把 MCP Server 部署到 Cloudflare Workers:std↔streamable HTTP 转换、Edge Runtime 限制、KV 持久化、wrangler 配置与生产部署清单。
阅读全文订阅 GPTMap Weekly
每周一封邮件,精选 OpenAI 重要更新、深度解读与最佳实践。无广告,可随时退订。