MCP:给 Agent 装上标准化的工具接口
目录
- MCP是什么
- 为什么需要MCP
- MCP的架构
- MCP的三大能力
- MCP的两种传输方式
- [MCP和Tool Use的区别](#MCP和Tool Use的区别)
- Agent侧怎么接入MCP
- 小结
MCP是什么
MCP(Model Context Protocol,模型上下文协议)是 Anthropic 在 2024 年底发布的一个开放协议。它给 LLM 连接外部工具和数据定义一套标准接口。
为什么需要一套标准?在 USB-C 出现之前,充电口五花八门,有USB、Lightning、各种厂商自己的私有接口。每换一个设备可能就得换一根线。后来出现了USB-C 统一了这个接口,一根线就能充电、能传数据、能接显示器,统一一种线之后消除了差异所带来的不便。MCP 在做的事情也是这样,它就是AI 领域的 USB-C:不管你是 Claude、GPT 还是其他模型,不管你是查数据库、调 API 还是读文件,都通过同一套协议来连接。
为什么需要MCP
回到我们已经讲过的 Tool Use 机制。在那篇文章里我们说过,Agent 调用工具的核心是一个注册表:工具名映射到执行函数。这个机制本身没问题,但有一个实际的痛点:每个 Agent 项目都要从零开始定义自己的工具。
假设我们想给 Agent 加一个"查询天气"的能力:
python
# 项目 A 的写法
weather_tool = {
"name": "get_weather",
"input_schema": {
"properties": {
"city": {"type": "string"}
}
}
}
# 项目 B 的写法
weather_tool = {
"name": "query_weather",
"input_schema": {
"properties": {
"location": {"type": "string"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
}
}
}
同样的功能,工具名、参数名、参数数量都不同。如果你想把项目 A 的天气工具搬到项目 B 里用,不能直接拿来就跑,需要改代码适配。
那如果有一个标准:所有天气类的 MCP Server 都叫 get_weather,参数都用 city,返回值格式都一样,那么任何支持 MCP 的 Agent 都能直接用,不用改一行代码。这就是 MCP 的核心价值:一次实现,到处可用。
MCP的架构
MCP 采用 Client-Server 架构,涉及三个角色:
用户
│
▼
Host(宿主应用)
│
├── Client A ──── Server 1(文件系统)
├── Client B ──── Server 2(数据库)
└── Client C ──── Server 3(GitHub API)
Host 是用户直接交互的应用,比如 Claude Desktop、Cursor、或者开发者自己写的 Agent 程序。它负责管理整个生命周期:创建 Client、协调通信、控制权限。
Client 是 Host 内部的协议代理,由 Host 创建。每个 Client 和一个 Server 之间是一对一的有状态连接。它负责和 Server 做协议协商、消息路由。
Server 是提供具体能力的服务端。它把自己能做的事情(查数据库、读文件、调 API)通过 MCP 协议暴露出来,任何 Client 都能连接并使用。
为什么要分 Client 和 Server 两层?因为一个 Host 可能同时需要多种能力。查数据库是一个 Server,读文件是另一个 Server,调 GitHub API 是第三个 Server。每个 Client 只管和自己对应的 Server 通信,Host 负责统筹调度。
MCP的三大能力
MCP Server 可以向 Client 暴露三种类型的能力:
Tools(工具)
工具是 Server 提供的可执行操作。Agent 可以调用工具来完成具体任务,比如执行 SQL 查询、发送消息、创建文件。
python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
@mcp.tool()
def get_weather(city: str) -> str:
"""查询指定城市的天气"""
# 实际实现:调用天气 API
return f"{city}:晴,25°C"
这部分和我们之前讲的 Tool Use 最像,区别在于工具的定义格式是 MCP 统一规定的,不是各项目自己定的。
Resources(资源)
资源是 Server 提供的可读取数据。和工具不同,资源是"只读"的,Agent 可以获取资源的内容,但不能通过资源去执行操作。
python
@mcp.resource("config://database")
def get_db_config() -> str:
"""返回数据库连接配置"""
return "host=localhost port=5432 dbname=myapp"
资源用 URI 来标识(比如 config://database),Client 可以通过 URI 列出可用资源、读取资源内容。
Prompts(提示模板)
提示模板是 Server 预定义的交互模板,告诉 Agent"在这种场景下你应该怎么组织 prompt"。
python
@mcp.prompt()
def review_code(code: str) -> str:
"""生成代码审查的 prompt"""
return f"请审查以下代码,关注安全性和性能:\n\n{code}"
三种能力的定位不同:
| 能力 | 方向 | 作用 | 类比 |
|---|---|---|---|
| Tools | Agent → Server | 执行操作 | 调用函数 |
| Resources | Server → Agent | 提供数据 | 读取文件 |
| Prompts | Server → Agent | 引导交互 | 提供模板 |
MCP的两种传输方式
Client 和 Server 之间怎么通信?MCP 支持两种方式:
stdio(标准输入输出):Client 启动 Server 进程,通过 stdin/stdout 交换 JSON-RPC 消息。这种方式适合本地场景,比如 Agent 在你电脑上运行一个本地的文件系统 Server。
Client
│
├── 启动 Server 子进程
├── 通过 stdin 发送请求
├── 通过 stdout 接收响应
└── 进程退出时断开连接
Streamable HTTP:Client 通过 HTTP 请求和远程 Server 通信。这种方式适合远程场景,比如连接一个部署在服务器上的数据库 MCP Server。
对于 Agent 初学者来说,先理解 stdio 就够了。你写一个本地 MCP Server,Agent 启动它、调用它的工具、拿到结果,整个过程都在本机完成。
MCP 和 Tool Use 的区别
这是一个比较容易混淆的点:MCP 和我们之前讲的 Tool Use 是什么关系?
Tool Use 是 LLM 调用工具的底层机制,模型输出一个结构化的工具调用请求,代码端执行并返回结果。MCP 是在此之上的一层标准化协议,它解决的不是"Agent 怎么调工具",而是"工具怎么定义、怎么发现、怎么复用"。
| 维度 | Tool Use | MCP |
|---|---|---|
| 层级 | 底层机制 | 上层协议 |
| 解决的问题 | Agent 怎么调工具 | 工具怎么标准化 |
| 工具定义 | 各项目自己定 | 协议统一规定 |
| 复用性 | 需要手动适配 | 一次实现到处可用 |
| 能力范围 | 只有工具 | 工具 + 资源 + 提示模板 |
Agent 侧怎么接入MCP
Host 应用(比如 Claude Desktop)内置了 MCP Client。用户在配置文件里声明要用哪些 MCP Server:
json
{
"mcpServers": {
"filesystem": {
"command": "python",
"args": ["filesystem_server.py"]
}
}
}
Host 启动时会为每个 Server 创建一个 Client,通过 stdio 启动 Server 进程,完成协议握手和能力协商。之后 Agent 在推理过程中如果需要文件操作,就会通过 Client 调用 Server 的工具,拿到结果后继续推理。
小结
MCP 给 Agent 连接外部世界定义了一套标准接口。Server 把自己的能力(工具、资源、提示模板)按照协议暴露出来,Client 按照协议去连接和调用。一次实现,任何支持 MCP 的 Agent 都能直接用。