📖 Day 8 学习页:工具系统设计与 MCP 协议

Day 8:工具系统设计与 MCP 协议

🎯 今日目标:掌握"好工具"的设计标准,理解 MCP(Model Context Protocol)—— 让 Agent 和工具之间有了 USB 接口式的行业标准。用 Mock Server 完整走一遍 MCP 的工具发现与调用流程。

📚 本日资源:📝 练习模板 | 📋 手动验收清单

⏱ 今日安排(约 2 小时)

时间内容方式
30min理论学习:工具设计四原则 + MCP 架构阅读
40minMCP 原理:协议流程 + SDK 对照阅读
50min动手实操:MockMCPServer + 客户端 + Agent 集成编码

📖 第一步:好工具的四条标准

原则为什么怎么做
单一职责一个工具干一件事,LLM 选择正确率高read_file 和 write_file 分开,不要一个 file_ops
描述精确docstring/description 直接决定 LLM 选不选它写清做什么、参数含义、给个例子
有超时一个工具卡死会拖死整个 Agent所有工具包 asyncio.wait_for(..., 30)
结构化返回LLM 要能读懂结果并继续推理返回 JSON/明确文本;出错时返回可读的错误信息而非 traceback

📖 第二步:MCP 是什么

没有 MCP 的世界:M 个 Agent × N 个工具 = M×N 套私有对接代码。MCP 把它变成 M+N: 工具方实现一次 MCP Server,任何支持 MCP 的 Agent(Claude Desktop、Cursor、你的 Agent)都能即插即用。

┌──────────────┐   stdio / HTTP    ┌──────────────────┐
│  MCP Host     │                  │  MCP Server       │
│ (你的 Agent)  │ ◄──────────────► │ (文件/计算/搜索…) │
│  MCP Client   │   JSON-RPC 2.0   │  tools + 资源     │
└──────────────┘                  └──────────────────┘

一次完整会话:
① initialize          客户端连接服务器,协商能力
② tools/list          发现:服务器上报"我有哪些工具、参数 Schema 是什么"
③ tools/call          调用:客户端发 name + arguments,服务器执行并返回结果

对应到本练习:MCPClient.list_tools() 就是 ②,MCPClient.call_tool() 就是 ③, MockMCPServer 用装饰器注册工具(和 Day 2 的模式一模一样,只是"注册"从进程内字典变成了可发现的协议接口)。 模板注释里附了 mcp 官方 SDK 的等价写法,跑通 mock 后对照看一眼即可。

🛠 第三步:动手实操

  1. 打开模板:day08_practice_template.py:
    • TODO 2.1:get_tool_list() —— 把注册的工具转成 Function Calling 格式(含超时包装)
    • TODO 2.2:call_tool() —— 查表、调用、错误兜底
    • TODO 3.1-3.3:MCPClient 的 connect / list_tools / call_tool
    • TODO 4.1-4.2:agent_with_mcp() —— 获取工具列表 → 走一遍简化 ReAct(Day 6 功底)
  2. 运行自测:python day08_practice_template.py(TODO 未完成时会有友好提示,不会裸崩)。
  3. 验收:python day08_practice_validator.py —— 验收会真的调用你的 MCP Server(列工具/算数/读文件)、你的客户端,并端到端跑一遍 Agent 集成。
  4. 进阶(可选):pip install mcp,用官方 SDK 把 calculator + read_note 实现成真 MCP Server, 用 mcp dev 起服务后接进 Claude Desktop / Cursor 玩一圈。

⚠️ 避坑

  • ❌ 工具描述写成 def calc(e): ... 一个词——LLM 选工具全靠描述,描述差 = 工具白写
  • ❌ 工具抛出原始 traceback 就返回——LLM 看不懂也纠不了错,要返回 {'错误': '表达式不合法'} 这种
  • ✅ 每个工具都该有超时(模板的 wrapper 已示范),防止一个慢工具卡死整个 Agent

🔗 延伸资源