Skip to content

Day 8 — MCP 协议 (Model Context Protocol)

读完这章你能获得什么:理解 MCP 协议的设计思想、消息格式、客户端/服务端实现,掌握如何让 Agent 调用外部工具服务,以及如何将自己的工具暴露给外部使用。


一、前情提要

经过 Day 1-7,我们的 Agent 已经是一个功能完整的 AI 助手了。但它的工具都是自己写的——如果社区里有人已经写好了一个"数据库查询工具"或"日历管理工具",我们怎么用?

反过来,如果别人想用我们 Agent 的工具,怎么提供给他们?

这就是 MCP(Model Context Protocol,模型上下文协议) 要解决的问题——让不同的 Agent 系统之间能共享工具


二、生活类比:跨公司合作协议

想象两家公司要合作:

甲方(你的公司)                    乙方(外部公司)
     │                                  │
     │  "你们有翻译服务吗?"             │
     │────────────────────────────────→ │
     │                                  │
     │  "有,我有翻译、摘要两个服务"      │
     │←──────────────────────────────── │
     │                                  │
     │  "请帮我翻译这段话"               │
     │────────────────────────────────→ │
     │                                  │
     │  "翻译结果:..."                  │
     │←──────────────────────────────── │

要想合作顺利,需要一份标准合同格式——双方都按这个格式来沟通,不会产生歧义。

MCP 就是这份"标准合同格式"

  • 合同编号:每次请求都有唯一 ID,方便对账
  • 合同类型:请求/回复/通知三种
  • 格式规范:JSON-RPC 2.0(一种广泛使用的 RPC 标准)

角色对应

合作角色MCP 角色说明
甲方(需要服务的人)MCPClient连接外部 MCP Server,使用它的工具
乙方(提供服务的人)MCPServer把本地工具暴露出去,让别人调用
标准合同格式MCPMessage (JSON-RPC 2.0)统一的通信协议
甲方的员工使用乙方的工具RemoteTool远程工具的本地代理

三、核心概念详解

3.1 MCPMessage——标准合同

MCP 基于 JSON-RPC 2.0 协议。如果你没听过 JSON-RPC,可以这样理解:

普通的 JSON 就是"一堆数据",JSON-RPC 是"一套请求-响应的规则"——规定了"怎么问、怎么答、怎么报错"。

三种消息类型

类型说明类比
请求(Request)"请帮我做这件事"甲方发出的需求单
响应(Response)"做好了,结果是..."乙方返回的成果
通知(Notification)"告诉你一声,不用回复"信息通报

消息长什么样?

json
// 请求:询问有什么工具
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list",
    "params": {}
}

// 响应:告诉你有哪些工具
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "tools": [
            {"name": "translate", "description": "翻译文本", ...}
        ]
    }
}

// 错误响应:出问题了
{
    "jsonrpc": "2.0",
    "id": 1,
    "error": {"code": -32601, "message": "Method not found"}
}

3.2 MCPClient——甲方(使用外部工具)

MCPClient 连接到外部 MCP Server,做三件事:

  1. 发现:问对方"你有什么工具?"(tools/list
  2. 代理:为每个远程工具创建一个 RemoteTool 本地代理
  3. 调用:通过代理调用远程工具(tools/call

RemoteTool 是什么?

远程工具不在本地,但 Agent 不应该关心"这个工具是本地的还是远程的"。所以 MCPClient 为每个远程工具创建一个 RemoteTool 代理——它实现了和本地 Tool 一样的接口,Agent 像用本地工具一样用它。

Agent 的视角:
  registry.get("translate")  →  得到一个 Tool 对象
  tool.execute(text="hello") →  得到结果 "你好"

  Agent 根本不知道(也不需要知道)这个工具实际上是远程调用的!

3.3 MCPServer——乙方(暴露本地工具)

MCPServer 做的事情正好相反——把我们本地 ToolRegistry 里的工具暴露出去:

请求方法MCPServer 的处理
initialize返回服务器信息(名称、版本)
tools/list遍历 ToolRegistry,返回所有工具的定义
tools/call找到工具、执行、返回结果

3.4 通信方式:Stdio

当前实现使用 Stdio(标准输入/输出)通信——MCPClient 启动 MCPServer 作为子进程,通过 stdin/stdout 收发 JSON 消息。

为什么用 Stdio?

方式优点缺点
Stdio零配置,不需要端口;安全,不暴露网络只能本机通信
HTTP/WebSocket可以跨机器需要配置端口、网络

教学阶段用 Stdio 最简单。理解了协议后,把传输层换成 HTTP 非常容易——因为消息格式(JSON-RPC)是一样的。


四、MCP 的全景流程

Agent 的视角:ToolRegistry 里有 4 个工具(calculator、datetime、translate、summarize),其中两个是本地的、两个是远程的——但 Agent 不需要区分。


五、动手实验指南

5.1 运行示例

bash
# 启动 MCP Server(作为工具提供方)
python -m miniclaw.mcp.server

# 在另一个终端,用 MCP Client 连接并调用
python -m miniclaw.mcp.client

5.2 改一改,看看会怎样

实验 1:在 MCP Server 端注册一个新工具(比如 random_number),然后用 Client 发现并调用它。

实验 2:故意调用一个不存在的工具名,观察 JSON-RPC 的错误响应格式。

实验 3:在 MCPClient 连接后,打印 discover_tools() 返回的列表,看看远程工具的元信息(名称、描述、参数)。

5.3 运行测试

bash
pytest miniclaw/mcp/ -v

六、常见问题 FAQ

Q1:MCP 和普通的 HTTP API 有什么区别?

A:普通 API 是你自己定义的接口格式,每个服务都不一样。MCP 是一个标准化的协议——所有遵循 MCP 的工具服务都用同样的方式发现和调用。类比:普通 API 像各国的电源插头(每个不一样),MCP 像 USB-C(统一标准)。

Q2:RemoteTool 和本地 Tool 性能差异大吗?

A:远程调用必然比本地调用慢(多了进程间通信或网络延迟)。但在 AI Agent 场景中,LLM 调用本身就要 1-10 秒,工具调用多几十毫秒的延迟通常可以忽略不计。

Q3:MCP 协议是 miniOpenClaw 自己发明的吗?

A:MCP 的概念来自 Anthropic 提出的开放标准。miniOpenClaw 的实现是一个简化的教学版本,核心理念一致,但省略了一些高级特性(如资源管理、采样等)。


恭喜你!

你已经完成了 miniOpenClaw 的全部 8 个章节!现在你拥有了从零构建 AI Agent 框架的完整知识:

章节你学到了
Day 1消息协议和路由——系统的"神经系统"
Day 2多渠道适配——系统的"感官"
Day 3会话管理——系统的"短期记忆"
Day 4ReAct 推理循环——系统的"大脑"
Day 5工具系统——系统的"双手"
Day 6技能系统——系统的"知识储备"
Day 7记忆管理——系统的"笔记本"
Day 8MCP 协议——系统的"社交能力"

接下来你可以:

  • 给 Agent 写更多实用工具
  • 定义有趣的技能包
  • 接入真实的 LLM API 做测试
  • 阅读 LangChain 等框架的源码,对比我们的实现
  • 参与 MCP 社区,体验更多工具生态