🔌 第7章 MCP开发进阶
📄 一句话概括

Inspector 就是把「握手、列表、调用」这三步做成按钮。它不多做任何协议上的事。 四块屏对应四个协议动作:连接、工具、请求、响应。没有第五块。 它真正值钱的地方是同时给你两个视角:表单看参数,原文看报文。

📝 本章和前面几章的关系

第 6 章写完了 Server 和 Client,但少说了一件事:写完之后怎么知道它写对了。 这一节讲 Inspector,教材里叫调试工具。它本身不是协议的一部分,是一个客户端。 所以会协议就会用它——反过来,用它也顺便把协议看熟了。

一、没有它的时候,怎么调

演示第一段是「裸手调」:不用任何工具,直接往管道里写一行 JSON,也能把 Server 问明白。 发 initialize、读一行回来,就这么简单。协议本来就不需要工具。 麻烦的是后面:每一步都要手打,参数还要自己拼 JSON,拼错了看到的是语法错不是业务错。

所以 Inspector 干的事只有一件:把这三步做成按钮。 它不多做任何协议上的事。理解这一点,就不会把它当成「必须装的东西」——它是方便,不是前提。

二、四块屏幕,对应四个协议动作

第一块连接:填传输方式、命令、参数,点连接。对应「起进程还是连地址」。 第二块工具:列出工具表,每个工具点开能看到参数树。对应 tools/list。 第三块请求:按 schema 自动生成输入框,填完点发送。对应 tools/call 的 arguments。

第四块响应:结果正文、原始 JSON、耗时。对应 result 或 error。 四块一一对应,没有第五块。 你在界面上看到的一切,都能在报文里找到出处。

三、一步步走一遍

连上之后第一件事是看工具表。演示里三个工具,参数个数分别是 2、1、1,必填分别是 text、无、keyword。 这一栏看着平淡,其实最有用:必填那一栏空着的工具,模型最容易调错——因为它可以什么都不填。 第二件事是点开一个工具看参数树。 Inspector 会按 schema 画成输入框,string 是文本框、enum 是下拉、必填会标出来。

这一屏最重要的用法是【看描述写得够不够清楚】。自己读一遍都含糊,模型更读不懂。 第三件事才是调一次。演示里调 note.add,回来是 id 为 1、total 为 1,耗时一毫秒多。

四、调试时最常做的三件事

第一种现象:工具列表是空的。先看连接状态灯——进程没起来,或者握手失败,这两种都会让列表空着。 第二种现象:调用报 -32602。对照参数树看你填的类型,多半是类型或必填不对。 第三种现象:调用卡住不回。看响应区的耗时——是「已发出、未收到」,说明工具函数自己死循环了。

第三种最需要分清:是协议没回,还是工具没算完。两者的修法完全不同,一个查传输,一个查代码。 Inspector 显示「已发出、未收到」,就是后者——去看工具函数里那个循环。

五、Inspector 不做什么

它不替你写 Server,不检查业务逻辑对不对,也不告诉你「这个工具该不该存在」。 它也不模拟模型。它只保证「报文能通、参数能进、结果能出」这三件事。 所以工具「能调通」和「模型会调」是两件事。前者靠 Inspector,后者靠描述写得好。

教材里这一节还讲了在浏览器里打开 Inspector 的步骤(本沙箱不执行):装好之后跑一条命令, 它会起一个本地网页,地址带一个端口号,浏览器打开就是那四块屏。 判据很简单:连接状态灯变绿、工具数不是零、随便调一个能回结果。三样都对了,Server 这一半就是通的。

六、动手 Demo:把 Inspector 拆开看

先用裸手调一次,看协议本身有多简单;再把 Inspector 的四块屏对应到四个协议动作上。 然后按它那三步走一遍:连上、看工具表、调一次,看耗时。 Inspector 的界面在这台机器上打不开,但界面背后的报文全是真的。

# 一、裸手调:不用工具也能问明白
c = Stdio('.../notes-mcp/src/server.py')
c.send(jr('initialize', {'protocolVersion': '2024-11-05',
                          'capabilities': {}}, 1))
print(c.p.stdout.readline())        # 一行回来,就这么简单

# 二、Inspector 那三步,其实就这三行
c.init()                            # 连接 + 握手
tools = c.tools()                   # 工具表,也就是第二块屏
r = c.call('note.add', {'text': 'Inspector 就是三块屏', 'tags': ['mcp']})

# 三、参数树:第二块屏点开就是这些
for k, p in tools[0]['inputSchema']['properties'].items():
    print(k, p['type'], p.get('description', ''))

实跑输出:

--------------------------------------------------------------------
把 Inspector 拆开看
--------------------------------------------------------------------


  ① 裸手调是什么样
  --------------------------------------------------------------------
不用任何工具,直接往管道里写一行 JSON,也能把 Server 问明白:
  >> {"jsonrpc":"2.0","method":"initialize","params":{},"id":1}
  << {"jsonrpc": "2.0", "id": 1, "result": {"protocolVersion": "2024-11-05", "…

这三步(握手、列表、调用)每次都要手打,参数还要自己拼 JSON。
Inspector 干的就是【把这三步做成按钮】。它不多做任何协议上的事。

  ② 四块屏幕
  --------------------------------------------------------------------

| 块 | 显示什么 | 对应协议里的什么 |
|---|---|---|
| 连接 | 传输方式、命令、状态灯 | 起进程还是连地址 |
| 工具 | 名字、描述、参数树 | tools/list 的结果 |
| 请求 | 一个表单,按 schema 生成输入框 | tools/call 的 arguments |
| 响应 | 结果正文、原始 JSON、耗时 | result 或 error |

  四块一一对应,没有第五块。【所以 Inspector 不需要学,会协议就会用它。】

  ③ 一步步走一遍
  --------------------------------------------------------------------
先把连接建起来:

| 工具 | 参数个数 | 必填 |
|---|---:|---:|
| note.add | 2 | text |
| note.list | 1 | 无 |
| note.search | 1 | keyword |


再看一个工具的参数树,Inspector 会按 schema 画成输入框:
  text     string   笔记正文
  tags     array    标签,可空
  这一屏最重要的用法是:【看描述写得够不够清楚】。
  自己读一遍都含糊,模型更读不懂。

  ④ 调一次,看原始报文
  --------------------------------------------------------------------
  结果:{"id": 1, "total": 1}
  耗时:1.68 毫秒
  这一个数含【写一行、子进程执行、读回一行】的全过程,单次测量,不取平均。

Inspector 的价值在于它同时给你两个视角:

| 视角 | 看到什么 | 什么时候看 |
|---|---|---|
| 表单 | 输入框、下拉、必填标记 | 准备参数时 |
| 原文 | 一整行 JSON-RPC | 怀疑协议出问题时 |

  【两个视角对着看,才能分清「我填错了」还是「它算错了」】。

  ⑤ 调试时最常做的三件事
  --------------------------------------------------------------------

| 现象 | 在 Inspector 里怎么看 | 多半是什么 |
|---|---|---|
| 工具列表是空的 | 看连接状态灯 | 进程没起来,或握手失败 |
| 调用报 -32602 | 对照参数树看你填的类型 | 类型或必填不对 |
| 调用卡住不回 | 看响应的耗时 | 工具函数自己死循环了 |

  第三行尤其要分清:是【协议没回】,还是【工具没算完】。
  Inspector 显示「已发出、未收到」,就是后者——去看工具函数里那个循环。
  ! Inspector 只是把三行命令变成按钮。协议本身一行都没变。

①第一步是最反直觉的:真不需要工具。一行 JSON 写进去,一行 JSON 读回来。 Inspector 只是把这一步变成按钮。 ②四块屏的对应关系是本节的主干。 连接对应起进程,工具对应 tools/list,请求对应 arguments,响应对应 result。 ③参数树那一屏最该看的是描述。 自己读一遍都含糊,模型更读不懂——这句话在第 6 章讲过,在这里能亲手验证。 ④那个一点几毫秒的耗时是真测的,单次测量不取平均。它含写一行、子进程执行、读回一行。 ⑤最后一个提醒:Inspector 不模拟模型。工具能调通,不代表模型会调。 这两件事分别靠 Inspector 和描述质量。

30 秒实验

  1. 不用 Inspector,只用三行报文把任意一个 Server 问明白:initialize、tools/list、tools/call。
  2. 给自己写的一个工具填一个错类型的参数,看它回哪个码。
  3. 想想「调用卡住不回」的两种可能,各该怎么查。

常见误区

  1. 「调 Server 必须装 Inspector。」裸手三行报文一样能调。Inspector 是方便,不是前提。
  2. 「工具能调通就说明写对了。」调通只说明报文通。模型会不会调,看描述写得清不清楚。
  3. 「报 -32602 就是 Server 有 bug。」多半是参数填错了。对照参数树看一眼再改代码。
自测三问(点开对答案) 1. Inspector 到底做了什么? —— 把「握手、列表、调用」三步做成按钮,另外把报文原文和耗时显示出来。协议上的事它一件没多做。 2. 四块屏分别对应哪个协议动作? —— 连接对应起进程,工具对应 tools/list,请求对应 tools/call 的参数,响应对应 result 或 error。 3. 调用卡住不回,怎么分清是协议还是代码? —— 看响应区的耗时和状态。显示「已发出、未收到」就是工具函数自己没算完。

调试这一节讲完了。下一节把 Server 从本机搬到线上:换一种传输,再补五件事。

相关笔记