背景
从上一篇文章 Agent工具调用:从正则解析到Function Calling 中可以看出,Function Calling 功能已经很了,但 Agent 需要调用更多的工具,最好像 App Store 中那么丰富,以便满足所有的用户。如何编写如此丰富的函数呢?Agent 的开发人员肯定没有这么多的精力,于是打算开发一个扩展系统,让其他开发人员来帮忙编写。
巧了,Sam Altman 也是这么想的。OpenAI 试图打造一个 AI 应用商店,让第三方开发者为 ChatGPT 开发插件,于是 ChatGPT Plugins 登场了。
用户可以在 ChatGPT 中安装各种插件:
- Wolfram Alpha:数学计算
- Zapier:自动化工作流
- Expedia:订机票酒店
听起来很美好,但 Plugins 失败了。 2024 年,OpenAI 正式关闭了 ChatGPT Plugins。
为什么?因为它有几个致命问题:
- 闭源生态:只能在 ChatGPT 中使用,Claude、Gemini 用不了
- 中心化审核:插件要经过 OpenAI 审核才能上架
- 复杂的开发流程:需要部署服务器、配置 OAuth、编写 OpenAPI 规范
Plugins 的失败,为 MCP 的诞生埋下了伏笔。
MCP:工具界的 USB 协议
2024 年 11 月,Anthropic 开源了 MCP(Model Context Protocol)。
MCP 的架构如下图所示:

一句话解释 MCP:让 AI 工具像 USB 设备一样即插即用。
USB 出现之前,键盘、鼠标、打印机各有各的接口。USB 出现后,所有设备都用同一个接口——这就是标准化的力量。
MCP 做的是同样的事:
| USB 协议 | MCP 协议 |
|---|---|
| 定义设备如何连接电脑 | 定义工具如何连接 Agent |
| 键盘、鼠标、U盘都能用 | 任何 Agent 都能用同一套工具 |
| 即插即用 | 即插即用 |
MCP 架构解析
MCP 采用客户端-服务端架构:
┌─────────────────────┐
│ LLM (Cloud) │
└──────────┬──────────┘
│
┌────────────────────────────────────┼────────────────────────────────┐
│ Agent │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ MCP Client │ │
│ └────────┬────────┘ │
│ │ │
└───────────────────────────────────┼─────────────────────────────────┘
│
┌─────────┴─────────┐
│ │
stdio HTTP
(local) (remote)
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ MCP Server │ │ MCP Server │
│ (local .py) │ │ (remote API) │
└──────────────────┘ └──────────────────┘
核心概念:
-
MCP Server:提供工具的服务端,用
@mcp.tool()装饰器注册工具 - MCP Client:Agent 中负责连接 Server、调用工具的组件
- MCP 协议:JSON-RPC 格式,通过 stdio 或 HTTP/SSE 传输
| 传输方式 | 说明 | 适用场景 |
|---|---|---|
| stdio | 本地进程,通过标准输入/输出通信 | 本地工具、IDE 插件 |
| HTTP/SSE | 远程服务,HTTP 请求 + SSE (Server-Sent Events) 响应 | 远端服务、共享工具 |
动手实现:MCP Server
让我们用 FastMCP 框架写一个 MCP Server,提供三个实用工具:
# mcp_server.py
from fastmcp import FastMCP
import hashlib
import base64
import uuid
# 创建 MCP 服务器实例
mcp = FastMCP(name="DevToolsServer")
# 工具 1:生成 UUID
@mcp.tool()
def generate_uuid(version: int = 4) -> str:
"""
生成 UUID
Args:
version: UUID 版本 (1 或 4),默认 4
"""
if version == 1:
result = uuid.uuid1()
else:
result = uuid.uuid4()
return f"🆔 UUID v{version}: {result}"
# 工具 2:生成哈希
@mcp.tool()
def generate_hash(text: str, algorithm: str = "md5") -> str:
"""
生成哈希值
Args:
text: 要哈希的文本
algorithm: 算法 (md5, sha1, sha256, sha512)
"""
algorithms = {
'md5': hashlib.md5,
'sha1': hashlib.sha1,
'sha256': hashlib.sha256,
'sha512': hashlib.sha512
}
hash_obj = algorithms[algorithm](text.encode('utf-8'))
return f"🔑 {algorithm.upper()} 哈希值:\n{hash_obj.hexdigest()}"
# 工具 3:Base64 编码
@mcp.tool()
def base64_encode(text: str) -> str:
"""
Base64 编码
Args:
text: 要编码的文本
"""
encoded = base64.b64encode(text.encode('utf-8')).decode('utf-8')
return f"🔐 Base64 编码结果:\n{encoded}"
if __name__ == "__main__":
mcp.run()
注意看这段代码的简洁之处:
- 用
@mcp.tool()装饰器注册工具 - 函数签名自动转成 JSON Schema
- docstring 自动成为工具描述
对比 Function Calling 版本:
| Function Calling | MCP |
|---|---|
| 手写 JSON Schema | 自动从函数签名生成 |
| 工具定义和实现分离 |
@mcp.tool() 一步到位 |
| 和 Agent 强耦合 | 完全解耦,独立服务 |
动手实现:Agent 调用 MCP
现在写一个 Agent,通过 MCP 协议调用上面的工具:
# dev_agent.py
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
class MCPClient:
"""MCP 客户端"""
async def connect(self, server_script: str):
"""连接到 MCP Server"""
import sys
server_params = StdioServerParameters(
command=sys.executable,
args=[server_script]
)
# 启动 Server 子进程,建立 stdio 通信
self._stdio_transport = stdio_client(server_params)
self._read, self._write = await self._stdio_transport.__aenter__()
# MCP 协议握手
self.session = ClientSession(self._read, self._write)
await self.session.__aenter__()
await self.session.initialize()
# 获取工具列表
response = await self.session.list_tools()
self.tools = response.tools
print(f"✅ 已连接,发现 {len(self.tools)} 个工具")
async def call_tool(self, name: str, arguments: dict) -> str:
"""调用工具"""
result = await self.session.call_tool(name, arguments)
return result.content[0].text
关键代码解析(stdio 模式):
-
启动 MCP Server:MCP Client 用
subprocess启动 MCP Server 作为子进程 - 建立通信:MCP Client 与 MCP Server 通过标准输入/输出管道传递 JSON-RPC 消息
-
协议握手:MCP Client 调用
initialize()等待 MCP Server 就绪 -
获取工具:MCP Client 调用
list_tools()获取 MCP Server 提供的工具列表 -
调用工具:MCP Client 调用
call_tool()请求 MCP Server 执行具体工具
两种模式对比:
| 维度 | stdio(本地服务) | HTTP/SSE(远端服务) |
|---|---|---|
| 启动顺序 | MCP Client 拉起 MCP Server 子进程 | MCP Server 先启动,MCP Client 再连接 |
| 就绪机制 | MCP Client 调用 initialize() 等待 MCP Server |
MCP Client 连接 MCP Server 监听的端口 |
| 退出顺序 | MCP Client 退出,MCP Server 随之结束 | MCP Server 独立运行,不依赖 MCP Client |
| 连接数 | MCP Client 与 MCP Server 一一对应 | 多个 MCP Client 可连接同一个 MCP Server |
运行效果
$ python3 dev_agent.py
🤖 程序员助手(MCP 版)
============================================================
✅ 已连接到 MCP Server,发现 3 个工具
📦 可用工具列表:
• generate_uuid: 生成 UUID
• generate_hash: 生成哈希值
• base64_encode: Base64 编码
👤 用户: 帮我生成一个 UUID
============================================================
第 1 轮对话
============================================================
🔧 Action: generate_uuid(version=4)
📋 Observation:
🆔 UUID v4: f47ac10b-58cc-4372-a567-0e02b2c3d479
Answer: 已为您生成 UUID: f47ac10b-58cc-4372-a567-0e02b2c3d479
✅ 任务完成!
👤 用户: 计算 password123 的 MD5
🔧 Action: generate_hash(text='password123', algorithm='md5')
📋 Observation:
🔑 MD5 哈希值:
482c811da5d5b4bc6d497ffa98491e38
Answer: "password123" 的 MD5 值是 482c811da5d5b4bc6d497ffa98491e38
MCP 的真正威力
MCP 的真正威力在于:写一次工具,到处能用。
对于 AI IDE,内置了 MCP Client,可以直接连接我们写的 MCP Server。
以 Cursor 为例,配置我们的 MCP Server:
1. 打开设置: Cursor Settings → Tools & MCP → Add Custom MCP
2. 编辑配置文件 ~/.cursor/mcp.json:
{
"mcpServers": {
"dev-tools": {
"command": "python3",
"args": ["/绝对路径/mcp_server.py"]
}
}
}
3. 保存后自动生效(无需重启 Cursor)
Cursor 会监听 mcp.json 文件变化,检测到更新后自动重新加载配置。
MCP Server 加载流程(stdio 模式):
- Cursor 检测到
mcp.json变化,解析新增的 MCP Server 配置 - Cursor 为该 MCP Server 创建独立的 MCP Client 实例
- MCP Client 拉起对应的 MCP Server 子进程(一对一)
- MCP Client 与 MCP Server 完成
initialize()握手 - MCP Client 调用
list_tools()获取 MCP Server 的工具列表 - Cursor 将工具列表合并到 Agent 的可用工具中,用户在交互区对话时即可调用
注:可配置多个 MCP Server,每个对应独立的 MCP Client 实例,互不影响。HTTP/SSE 模式同样会创建 MCP Client 实例,区别是 MCP Server 需提前独立启动。
我们在交互区验证一下:

同一套工具,既能在自己的 Agent 中用,也能在 Cursor 中用,这就是 MCP 的价值。
总结
对比一下三种方案的演进:
| 维度 | 正则解析 | Function Calling | MCP |
|---|---|---|---|
| 工具定义 | 写在 Prompt 里 | JSON Schema | @mcp.tool() |
| 工具调用 | 正则解析文本 | LLM 返回结构化 JSON | 标准化协议 |
| 工具复用 | ❌ 和 Prompt 耦合 | ❌ 和 Agent 耦合 | ✅ 即插即用 |
| 跨 Agent | ❌ | ❌ | ✅ |
| 生态 | 无 | 各家有各家的格式 | 统一标准 |
MCP 解决了 Agent 生态的一个核心问题:工具的标准化和复用。
- 对开发者:写一次工具,Cursor、Claude Desktop、自己的 Agent 都能用
- 对用户:工具生态繁荣,选择更多
- 对行业:有了统一标准,才能规模化
MCP 不是要取代 Function Calling,而是在它之上建立了一层标准。就像 TCP/IP 不取代电缆,而是定义了数据如何在电缆上传输。
MCP = Agent 世界的 USB 协议。
完整代码
本文代码已开源:GitHub - agent/03_mcp_practice
03_mcp_practice/
├── mcp_server.py # MCP Server(3 个工具)
├── dev_agent.py # Agent 示例
└── README.md # 使用说明
运行方式:
# 安装依赖
pip install fastmcp mcp requests
# 运行 Agent
python3 dev_agent.py