本节摘要:前两节我们用代码连服务端、调工具,但都是「打印到终端」的黑盒视角——你看不到模型实际看到的工具表单长什么样、资源列表怎么呈现、提示词消息什么形态。本节引入 MCP 检查器(Inspector),一个官方提供的可视化调试工具,它把你的服务端跑在一个图形界面里,让你逐个原语地体验与调试。我们讲清它怎么启动(一行命令)、它如何用 stdio 传输跑你的服务端文件、以及它的三大标签页(工具/资源/提示词)各自能做什么。读完本节,你将拥有开发期最顺手的调试利器,后续每一章遇到问题都知道去哪可视化排查。
检查器是 [cli] 那个可选依赖提供的命令。如果你按第 1.1 节装了 mcp[cli],在服务端文件所在目录执行:
uv run mcp dev server.py
或者(没用 uv 的话):
mcp dev server.py
它会做三件事:
mcp dev server.py 启动过程 ┌─────────────────────────────────────────────────┐ │ 1. 启动一个本地 Web 服务(检查器界面) │ │ 2. 把 server.py 当子进程跑起来(stdio 传输) │ │ 3. 检查器作为客户端,用 stdio 连上你的服务端 │ │ 4. 打印一个本地 URL,浏览器打开就是界面 │ └─────────────────────────────────────────────────┘
打开它打印的 URL(通常是 http://localhost:6274 之类),你就能看到一个图形界面,左侧是连接状态、右侧是三大原语的标签页。
⚠️ 注意:
server.py是你服务端文件的实际名字。检查器会在文件里找一个名为mcp的MCPServer实例(也就是你mcp = MCPServer("Demo")那一行创建的对象),自动连上它。所以你的服务端文件里要有这么一个模块级的mcp变量,这是检查器的约定。
这里藏着一个第 8 章才会详讲的概念,但本节值得先点破:检查器用 stdio 传输跑你的服务端。
具体机制是:
┌──────────────┐ ┌──────────────┐ │ 检查器 │ ── stdin ──► │ server.py │ │ (客户端) │ ◄─ stdout ── │ (子进程) │ └──────────────┘ └──────────────┘
检查器把你的 server.py 当成一个子进程启动,然后用它的标准输入(stdin)和标准输出(stdout)当 MCP 消息的「线缆」。你不需要在 server.py 里写任何「启动 stdio 服务」的代码——检查器替你处理这一层。
这就是为什么 mcp dev 这么好用:它让你不用关心传输怎么配置,直接把服务端文件喂给它就行。第 8 章会讲如何手动用 mcp.run() 自己启动 stdio 服务,但开发期,检查器是最省事的。
💡 技巧:
mcp dev跑起来后,你改了server.py需要重启检查器才能生效(它不会自动热重载)。一个常见的工作循环是:改代码 → 重启mcp dev→ 刷新浏览器验证。
检查器的第一个标签是 Tools。它会列出你的服务端声明的所有工具,展示模型实际看到的工具表单。
对第 1.2 节写的 add 工具,检查器会显示:
| 字段 | 显示内容 | 来源 |
|---|---|---|
| 工具名 | add |
函数名 |
| 描述 | Add two numbers. |
文档字符串 |
| 参数表单 | 两个必填整数输入框 a、b |
类型注解 a: int, b: int |
关键洞见:那个「两个必填整数输入框」的表单,是检查器从类型注解自动构造的——而这正是任何 MCP 客户端(Claude Desktop、Cursor、你的自研 Host)构造调用时依据的同一份 Schema。换句话说,你在检查器里看到的表单,就是模型会看到的工具接口。
填入 a=1, b=2,点调用,你会看到返回结果。这个返回就是上一节 call_tool 拿到的那个结构(文本内容 + 结构化数据)。
第二个标签是 Resources。这里有个第 5 章会详讲、但本节先要记住的区分:
Resources(具体资源) ── 列表为空(我们没注册具体资源) Resource Templates(模板) ── 列出 greeting://{name}
为什么 greeting 不在「具体资源」列表里?因为它是个模板——URI 里有 {name},没有具体的值就不是一个可读的资源,只是一份「模式」。要在检查器里读它,你得在模板详情里填入 name 的值(比如 World),检查器据此构造完整 URI greeting://World,发起读取,显示 Hello, World!。
这个区分反映了资源体系的核心理念:「能直接列出来」与「需要参数才能实例化」是两类不同的东西。第 5 章会展开。
第三个标签是 Prompts。对第 1.2 节没写、但官方示例里有的 summarize 提示词:
@mcp.prompt() def summarize(text: str) -> str: """Summarize a piece of text in one sentence.""" return f"Summarize the following text in one sentence:\n\n{text}"
检查器会显示一个名为 summarize 的条目,带一个必填字符串参数 text。填入文本后调用,你会收到一条消息——role: user,内容是函数返回的字符串。
这就是提示词的本质:一个函数,返回一段会变成「用户消息」注入对话的文本。它的参数只能是扁平的字符串列表(没有 JSON Schema),这是它与工具的关键差别,第 5 章详讲。
把检查器放进整个开发循环,你会看到它能填的几个特定空隙:
| 场景 | 用检查器 | 用内存客户端(1.3 节) |
|---|---|---|
| 快速看「模型会看到什么」 | ✅ 图形界面,直观 | ❌ 要打印才看得到 |
| 写自动化测试 | ❌ 人工操作 | ✅ 代码可断言 |
| 调试表单/Schema 渲染 | ✅ 专长 | ❌ 看不到表单 |
| 验证复杂调用链 | ❌ 手动太慢 | ✅ 脚本化快 |
💡 技巧:两者是互补的,不是替代关系。开发期用检查器快速看「界面长什么样」,验证完用内存客户端写成测试固化下来。本书后续章节遇到「这个工具/资源/提示词表现对不对」时,默认建议先用检查器肉眼看一遍。
最后列几个第一次用检查器容易卡的点,附录会再扩展:
| 现象 | 多半原因 | 解决 |
|---|---|---|
| 启动报「找不到 mcp」 | 装的是纯库版,没带 [cli] |
重装 mcp[cli] |
| 启动报「找不到 server」 | 文件名/路径不对 | 用实际文件名,在文件所在目录执行 |
| 连上了但工具列表空 | 文件里没有模块级 mcp 变量 |
确保 mcp = MCPServer(...) 在模块顶层 |
| 改了代码没生效 | 检查器不会热重载 | 重启 mcp dev,刷新浏览器 |
| Windows 下子进程卡住 | 编码/换行问题 | 附录会专门讲 Windows 排错 |
mcp dev server.py 一行启动检查器,它启动一个本地 Web 服务 + 把服务端文件当子进程跑。mcp dev,它不热重载;Windows 下子进程卡住见附录排错。至此第 1 章结束。你已经能装、能写、能用内存客户端验证、能用检查器可视化调试——一套完整的「跑起来」闭环。下一章我们退一步,从架构视角讲清楚这一切背后是怎么设计的。