首页 › tutorials › MCP工具调试闭环实战

用 MCP Inspector 打通自造工具的调试闭环

概述

本教程教你用官方调试工具 MCP Inspector,把"写一个 MCP 工具"和"在 Claude Code 里跑通它"之间的黑箱彻底打开。学完后你能:独立启动 Inspector 连接任意 MCP 服务器、在可视化界面里逐个调用工具并观察通知流、读懂 stderr 与日志通知的区别、导出配置一键接入 Claude Code 验证。适合已经写过或准备写第一个 MCP 服务器的开发者——尤其是那些"服务器接进 Claude Code 后莫名报错、却完全不知道哪一步出问题"的人。

前置条件


一、为什么 Inspector 是你的"第一站"

很多人写完 MCP 服务器后,直接把它塞进 claude_desktop_config.json 或 Claude Code 的 MCP 配置里,然后在聊天框里问:"帮我调用一下那个工具"。如果没反应,就陷入了盲调试——你既看不到握手是否成功,也看不到工具列表是否被识别,更看不到调用时传了什么参数、服务端报了什么错。

官方文档对这一点的态度非常明确,把 Inspector 列为调试工具体系的第一项,原话是:"This should be your first stop"(这应该是你的第一站)。

MCP 的调试工具栈分三层,Inspector 占据最底层也最关键的位置:

层级 工具 解决什么问题
交互式测试 MCP Inspector 连服务器、调工具、看通知流——全程可视化
结构化日志 Server logging(stderr / notifications/message) 服务器自己暴露内部状态
客户端开发工具 客户端的日志面板(如 Claude Desktop 日志) 看客户端这一侧发生了什么

关键认知是:在把服务器交给 Claude Code 之前,先用 Inspector 把它彻底跑通。一旦 Inspector 里能正常调用、返回正确、日志清晰,再接入客户端时 90% 的问题就不存在了。

二、看懂 Inspector 的双组件架构

Inspector 不是一个单体程序,而是两个进程协同工作。理解这个架构,后面所有的端口、认证、传输问题都能对号入座。

flowchart LR
    subgraph Browser["浏览器"]
        UI["MCPI Client UI<br/>React 应用"]
    end
    subgraph Local["本地进程"]
        Proxy["MCPP Proxy Server<br/>Node.js :6277"]
        Server["你的 MCP Server<br/>stdio 进程"]
    end
    UI -- "HTTP / WebSocket" --> Proxy
    Proxy -- "stdio 管道<br/>(spawn 子进程)" --> Server
    Server -. "stderr 日志 +<br/>notifications/message" .-> Proxy
    Proxy -. "通知流转发" .-> UI

    style UI fill:#e1f5ff,stroke:#0288d1
    style Proxy fill:#fff3e0,stroke:#ef6c00
    style Server fill:#e8f5e9,stroke:#388e3c

两个组件各司其职:

小知识:6274 和 6277 这两个端口不是随便选的,它们来自手机的 T9 九宫格键盘——6274 对应字母 MCPI,6277 对应 MCPP,是个好记的助记符。

注意:这里的 Proxy 不是抓包用的网络代理,它不会拦截流量,它的作用是让"只能讲 stdio 的服务器"也能被"只会发 HTTP 的浏览器"操控。

三、5 分钟启动 Inspector

方式一:npx 直接拉起(最常用)

# 只启动 Inspector UI,稍后在界面里手动填服务器命令
npx @modelcontextprotocol/inspector

浏览器会自动打开 http://localhost:6274。如果你要直接调试一个本地的 MCP 服务器,把启动命令追加在后面:

# 调试一个构建产物为 build/index.js 的 TS 服务器
npx @modelcontextprotocol/inspector node build/index.js

# 调试一个 Python 服务器
npx @modelcontextprotocol/inspector python temp_tool.py

需要给服务器传环境变量或参数时,用 -e 和 --:

# 只传环境变量
npx @modelcontextprotocol/inspector -e API_KEY=sk-xxx -e DEBUG=true python temp_tool.py

# 同时传环境变量和参数,用 -- 分隔 Inspector 自己的标志
npx @modelcontextprotocol/inspector -e API_KEY=sk-xxx -- python temp_tool.py --port 8080

方式二:Docker 容器(隔离环境)

docker run --rm \
  -p 127.0.0.1:6274:6274 \
  -p 127.0.0.1:6277:6277 \
  -e HOST=0.0.0.0 \
  -e MCP_AUTO_OPEN_ENABLED=false \
  ghcr.io/modelcontextprotocol/inspector:latest

注意 127.0.0.1: 前缀——这是有意只绑定本地回环,不暴露到局域网(见后文安全章节)。

自定义端口

如果默认端口被占用:

CLIENT_PORT=8080 SERVER_PORT=9000 npx @modelcontextprotocol/inspector python temp_tool.py

预期结果:终端打印一行 🔑 Session token: <一长串十六进制>,并给出一个带 token 的 URL,浏览器自动打开。这就是你的调试入口。

四、实战:调试一个"有 bug"的温度工具

光看文档没用,我们来调试一个真实的小项目。这个服务器做温度换算,里面故意埋了一个常见 bug——空列表除零。

第 1 步:写服务器

# temp_tool.py —— 温度换算 MCP 服务器(故意留了一个 bug)
import sys
from fastmcp import FastMCP

mcp = FastMCP("temp-converter")


@mcp.tool()
def celsius_to_fahrenheit(celsius: float) -> str:
    """把摄氏度换算成华氏度"""
    # 关键:调试日志写到 stderr,而不是 stdout
    print(f"[debug] 收到输入 celsius={celsius}", file=sys.stderr)
    fahrenheit = celsius * 9 / 5 + 32
    return f"{celsius}°C = {fahrenheit:.1f}°F"


@mcp.tool()
def average_temps(temps: list[float]) -> str:
    """计算多个温度的平均值"""
    total = sum(temps)
    avg = total / len(temps)   # bug:temps 为空列表时会抛 ZeroDivisionError
    return f"平均温度 {avg:.1f}°C"


if __name__ == "__main__":
    mcp.run(transport="stdio")

第 2 步:用 Inspector 连接它

npx @modelcontextprotocol/inspector python temp_tool.py

浏览器打开后,左侧已经自动填好了 Command=python、Args=temp_tool.py。点击 Connect,Inspector 通过 Proxy 拉起你的服务器进程并完成 MCP 握手。

第 3 步:在 UI 里逐项验证

连接成功后,顶部会看到三个标签页,对应 MCP 的三原语:

点击 celsius_to_fahrenheit,右侧弹出参数表单(由 JSON Schema 自动生成),填入 celsius: 25,点 Run Tool:

预期返回:25°C = 77.0°F

同时,下方的 Notifications 面板会刷出一条 [debug] 收到输入 celsius=25——这就是你那条 print(..., file=sys.stderr) 被捕获的证据。

第 4 步:触发 bug 并捕获

现在调用 average_temps,把 temps 留空(或填 []),点 Run。UI 会直接展示一个错误响应,而 Notification 面板里能看到服务端的 traceback。这就是 Inspector 的核心价值:在接入 Claude Code 之前,你已经定位到了"空列表除零"这个 bug,而不是等到用户在聊天里踩坑。

修复很简单:

    if not temps:
        return "错误:温度列表不能为空"
    avg = total / len(temps)

五、日志:调试的命脉(以及一个致命陷阱)

调试 MCP 服务器,本质是"让服务器说话"。但怎么说、往哪说有严格规矩,踩错了会让整个协议崩溃。

致命陷阱:stdout 是协议通道

MCP 的 stdio 传输,把标准输出(stdout)整个当成了协议消息通道。这意味着:

⚠️ 本地 MCP 服务器绝不能往 stdout 打印任何日志,否则会污染协议、导致客户端解析失败、握手直接断开。

这是新手最常犯的错误。一个无辜的 print("server started")(默认走 stdout)就足以让 Claude Code 报"服务器未响应"。正确做法是写 stderr:

# 错误:会破坏协议
print("server started")

# 正确:stderr 是安全的
print("server started", file=sys.stderr)
import sys  # 别忘了导入

官方文档对此专门用黄色警告框强调。记住这条规则,能帮你省掉几个小时的盲调。

协议级日志:notifications/message

除了 stderr,MCP 还定义了一条正式的日志通知通道,适用于所有传输方式(不只 stdio):

@mcp.tool()
async def my_tool(ctx) -> str:
    await ctx.session.send_log_message(
        level="info",
        data="开始处理请求",
    )
    return "done"

这条消息会作为 notifications/message 推送给客户端(包括 Inspector),和 stderr 日志的区别在于:

维度 stderr 日志 notifications/message
适用传输 仅 stdio(被客户端捕获) 所有传输
语义 非正式调试输出 协议正式日志
日志级别 无结构 RFC 5424 八级(debug→emergency)
客户端可调级别 否 是,运行时用 logging/setLevel

MCP 定义了八个 RFC 5424 严重级别(debug、info、notice、warning、error、critical、alert、emergency)。客户端可以在运行时通过 logging/setLevel 请求动态调整最低级别——这意味着用户能在不重启服务器的前提下,把日志从"只看 error"切换到"全量 debug"。Inspector 的 UI 里就有这个级别开关,调高后能看到服务器内部每一步的细粒度通知。

实战建议:stderr 用于开发期的临时调试(最快),notifications/message 用于生产期的正式日志(结构化、可被任何客户端消费)。

六、闭环关键:导出配置,接入 Claude Code

Inspector 真正的设计巧思在于——它不只是个调试器,还是接入客户端的跳板。调通之后,你不用手写 JSON 配置。

Inspector UI 里有两个导出按钮(配置好服务器后出现):

stdio 服务器导出长这样:

{
  "mcpServers": {
    "default-server": {
      "command": "python",
      "args": ["temp_tool.py", "--debug"],
      "env": {
        "API_KEY": "your-api-key",
        "DEBUG": "true"
      }
    }
  }
}

把这段粘进 Claude Code 的项目配置(.mcp.json)或用户配置后,在 Claude Code 里验证:

# 查看所有 MCP 服务器连接状态
/mcp

/mcp 会列出已连接的服务器及其工具数。如果你的 temp-converter 显示 connected 且工具数为 2,闭环就完成了。

整个开发闭环如下:

flowchart TD
    A["写/改 MCP 服务器代码"] --> B["npx inspector 启动调试"]
    B --> C["Inspector UI 测试工具"]
    C --> D{"调用成功?"}
    D -- "失败/有bug" --> E["看 Notification 与 stderr 日志"]
    E --> A
    D -- "成功" --> F["点 Server Entry 导出 JSON"]
    F --> G["粘进 Claude Code 的 .mcp.json"]
    G --> H["/mcp 验证已连接"]
    H --> I["在对话里实际调用"]
    I --> J{"符合预期?"}
    J -- "否" --> A
    J -- "是" --> K["✅ 闭环完成"]

    style A fill:#e8f5e9,stroke:#388e3c
    style K fill:#c8e6c9,stroke:#2e7d32
    style D fill:#fff9c4,stroke:#f9a825
    style J fill:#fff9c4,stroke:#f9a825

七、常见问题排查表

现象 根因 解决
Inspector 连接后 Tools 为空 服务器没注册工具,或握手失败 看 Notification 面板的初始化日志;确认 @mcp.tool() 装饰器写对
客户端报"服务器未响应" 日志打到 stdout 污染了协议 全部改用 print(..., file=sys.stderr)
长任务超时被取消 默认请求超时 60 秒 调大 MCP_REQUEST_MAX_TOTAL_TIMEOUT,或配合进度通知
工具能跑但读不到文件 工作目录未定义(macOS 上是 /) 配置里一律用绝对路径,别依赖 cwd
Inspector 报 401/认证失败 新版默认开启 session token 认证 用终端打印的 ?MCP_PROXY_AUTH_TOKEN=xxx 那个 URL 打开
Streamable HTTP 服务器看不到 stderr HTTP 传输不捕获 stderr 改用 notifications/message 或 curl 抓包

超时相关的配置项(在 Inspector 的 Configuration 面板里改):

配置项 默认 含义
MCP_SERVER_REQUEST_TIMEOUT 300000ms 单次请求客户端超时
MCP_REQUEST_TIMEOUT_RESET_ON_PROGRESS true 收到进度通知就重置超时
MCP_REQUEST_MAX_TOTAL_TIMEOUT 60000ms 配合进度通知的总超时上限
MCP_AUTO_OPEN_ENABLED true 启动时是否自动开浏览器

八、安全警示:别让调试工具变成后门

Inspector 默认绑定了多层安全防护,理解它们能避免把开发机变成靶机:

1. 默认 localhost 绑定 + session token 认证。 新版 Inspector 启动时生成随机 token,必须带在 URL 里才能访问 UI。终端里那一行 🔑 Session token: 不是装饰,是认证凭据。

2. CVE-2025-49596——一个真实的 RCE 漏洞。 安全公司 Oligo 曾披露 Inspector 存在远程代码执行漏洞:攻击者只要诱导你访问一个恶意网页(甚至恶意广告),就能通过浏览器反向打穿你的 Inspector Proxy,进而在你机器上执行任意命令。所以官方强烈警告:

🚨 DANGEROUSLY_OMIT_AUTH=true(关闭认证)极其危险——不只是暴露到公网时危险,即便只在本机,访问恶意网站也可能导致远程入侵。除非你完全理解风险,否则不要关闭它。

3. DNS 重绑定防护。 Inspector 校验请求的 Origin 头,默认只允许来自客户端端口(6274)的请求。需要放行额外来源时:

ALLOWED_ORIGINS=http://localhost:6274,http://localhost:8000 npm start

实战守则:永远别关认证、永远别 HOST=0.0.0.0 绑公网、别在生产机常驻 Inspector。它是开发期工具,用完即关。

延伸阅读

训练营适用性评估

维度 评估
适合的训练营类型 AI 应用开发营、MCP/智能体工具开发营、企业内部"自建工具"实操营
学员基础 已完成至少一个 MCP 服务器 Hello World,懂 Python/TS 基础
建议教学时长 1.5–2 小时(含动手调 bug 环节)
最佳教学顺序 放在"造第一个 MCP 工具"之后、"接入客户端"之前,作为承上启下的调试课
核心收获 学员能独立排查"工具接进去没反应"类问题,建立"先 Inspector 后客户端"的工程习惯
可拓展 可与 Hooks、Skills 课程联动——把调通的工具再用 Skill 封装触发

参考来源

  1. MCP Inspector - Model Context Protocol 官方文档 — Inspector 的官方使用说明,本文架构与启动章节的主要依据
  2. Debugging - Model Context Protocol 官方文档 — 调试工具栈、stderr/stdout 规则、notifications/message 日志机制的权威来源
  3. modelcontextprotocol/inspector - GitHub — 源码与 README 全文,含端口助记符、导出配置、认证、安全章节的完整原文
  4. Critical RCE Vulnerability in Anthropic MCP Inspector - CVE-2025-49596 (Oligo) — Inspector RCE 漏洞技术分析,安全警示章节来源
  5. MCP Inspector: Debug and Test Your MCP Servers (2026 Guide) - Apigene — 实战调试经验补充,stdio 限制与替代方案

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入