24 讲路线 · 与 S07 配对
D07: MCP Protocol 深挖 · MCP 协议
本讲在 S07 主线之上,聚焦实现细节、边界条件与自测;导图与主线相同模块,便于对照。
建议:先读完 S07,再按下方顺序走读源码与练习。
🔬 深挖目标
MCP 是进程/会话级协议:握手、能力公告、工具发现、调用、崩溃恢复。本讲把每个 JSON-RPC 形状与宿主状态机对齐。
🔌 生命周期(概念)
- 启动传输:
stdiospawn 子进程 /sse建连。 - initialize / initialized:交换协议版本与 capability。
- tools/list → 缓存工具 schema → 与内置工具合并名空间。
- tools/call:参数校验 → 等待响应 → 映射为统一 ToolResult。
⚠️ 工程坑
| 问题 | 现象 | 排查 |
|---|---|---|
| 僵尸子进程 | 端口占用 / CPU 空转 | 宿主退出时是否 SIGTERM 子进程? |
| 握手超时 | 工具列表空 | stderr 是否被吞?日志级别? |
| 工具重名 | 调用打到错误 server | 前缀策略或注册顺序 |
🔒 安全边界
MCP 工具在权限模型里通常等价于「外部 bash」:应继承 D03 的最严策略或单独白名单;任何「自动信任 MCP」都是红旗。
📖 走读顺序
- 定位 MCP client 实现文件,画「连接 → list → call」时序。
- 找一个官方示例 server,故意让 tools/call 抛错,观察宿主如何展示给模型。
- 列出所有 transport 分支,比较重连策略差异。
✏️ 自测 1 · 参考答案:为何不宜每次 tool call 都 handshake?
题干
解释为何 MCP 不宜在每次 tool call 时重新 handshake。
结论
- 延迟:每次
initialize+ 传输建连会把工具调用变成「秒级」操作,批量调用时不可接受。 - 状态与配额:连接上往往有会话状态、流控、订阅;反复握手易触发 server 侧资源泄漏或对端限流。
- 正确模型:长生命周期的 client 连接,在进程/会话级维护;仅在断线、版本不匹配或配置变更时重连。
✏️ 自测 2 · 参考答案:同名 tool — 前缀还是 UUID?
题干
两个 server 提供同名 tool,选前缀还是 UUID?利弊?
结论
对人类与模型可读性优先选稳定前缀(如 serverSlug_toolName);UUID 适合机器内部主键,**不适合**作为模型可见的主名称(难推理、难 diff)。
- 前缀:可读、可教用户;需处理 slug 冲突与字符集。
- UUID:全局唯一无歧义;但对 prompt 噪声大,除非只做内部映射、对外仍展示前缀。