MCP 与工具协议
引言
随着 Agent 生态的发展,如何标准化工具的描述、发现和调用成为关键问题。Anthropic 推出的 Model Context Protocol(MCP)和 Google 的 Agent-to-Agent(A2A)协议代表了工具标准化的两个重要方向。
Model Context Protocol(MCP)
背景与动机
在 MCP 之前,每个 AI 应用都需要为每个数据源和工具编写定制的集成代码。这导致了"M×N 问题"——M 个应用 × N 个工具 = M×N 个集成。
MCP 提出了一个统一的协议,让任何 MCP 客户端都能连接任何 MCP 服务器,将 M×N 简化为 M+N。
架构
graph TB
subgraph "MCP 架构"
subgraph "Host(宿主应用)"
APP[AI 应用<br/>Claude Desktop / IDE]
CLIENT1[MCP Client 1]
CLIENT2[MCP Client 2]
CLIENT3[MCP Client 3]
APP --- CLIENT1
APP --- CLIENT2
APP --- CLIENT3
end
subgraph "MCP Servers"
SERVER1[文件系统服务器<br/>本地文件读写]
SERVER2[GitHub 服务器<br/>仓库/PR/Issue]
SERVER3[数据库服务器<br/>查询/写入]
end
CLIENT1 <-->|JSON-RPC| SERVER1
CLIENT2 <-->|JSON-RPC| SERVER2
CLIENT3 <-->|JSON-RPC| SERVER3
SERVER1 --> FS[(本地文件)]
SERVER2 --> GH[(GitHub API)]
SERVER3 --> DB[(数据库)]
end
核心概念
MCP 服务器可以提供三种类型的能力:
| 类型 | 说明 | 控制方 | 示例 |
|---|---|---|---|
| Resources | 数据和内容(类似 GET) | 应用程序控制 | 文件内容、数据库记录 |
| Tools | 可执行的函数(类似 POST) | 模型控制(LLM 决定调用) | 发送邮件、创建 PR |
| Prompts | 预定义的模板 | 用户控制 | 代码审查模板 |
传输层
MCP 支持两种传输方式:
# 1. Stdio 传输(本地进程间通信)
# 适用于本地工具(文件系统、本地数据库等)
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
}
}
}
# 2. SSE 传输(HTTP Server-Sent Events)
# 适用于远程服务
{
"mcpServers": {
"remote-db": {
"url": "https://mcp.example.com/sse",
"transport": "sse"
}
}
}
编写 MCP 服务器
# Python MCP 服务器示例
from mcp.server import Server
from mcp.types import Tool, TextContent
server = Server("my-tools")
@server.list_tools()
async def list_tools():
return [
Tool(
name="query_database",
description="查询 SQLite 数据库。输入 SQL 查询语句,返回结果。",
inputSchema={
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "SQL 查询语句(只支持 SELECT)"
}
},
"required": ["query"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "query_database":
query = arguments["query"]
# 安全检查
if not query.strip().upper().startswith("SELECT"):
return [TextContent(type="text", text="错误:只支持 SELECT 查询")]
results = execute_sql(query)
return [TextContent(type="text", text=format_results(results))]
# 运行服务器
if __name__ == "__main__":
import asyncio
from mcp.server.stdio import stdio_server
asyncio.run(stdio_server(server))
MCP 客户端
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def use_mcp_tool():
server_params = StdioServerParameters(
command="python",
args=["my_mcp_server.py"]
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# 列出可用工具
tools = await session.list_tools()
# 调用工具
result = await session.call_tool(
"query_database",
{"query": "SELECT * FROM users LIMIT 10"}
)
print(result)
MCP 生态
常用的官方和社区 MCP 服务器:
| 服务器 | 功能 |
|---|---|
@modelcontextprotocol/server-filesystem |
文件系统操作 |
@modelcontextprotocol/server-github |
GitHub 集成 |
@modelcontextprotocol/server-postgres |
PostgreSQL 查询 |
@modelcontextprotocol/server-slack |
Slack 消息 |
@modelcontextprotocol/server-memory |
知识图谱记忆 |
@modelcontextprotocol/server-puppeteer |
浏览器自动化 |
@modelcontextprotocol/server-brave-search |
Brave 搜索 |
Google A2A 协议
Agent-to-Agent Protocol
Google 提出的 A2A 协议关注的是 Agent 之间的通信,而非 Agent 与工具之间。
graph LR
subgraph "A2A 架构"
CA[Client Agent<br/>委托方] <-->|A2A Protocol| SA[Server Agent<br/>执行方]
CA -->|发送任务| SA
SA -->|返回结果| CA
SA -->|发送 Artifact| CA
end
核心概念
- Agent Card:Agent 的能力描述(类似简历)
- Task:Agent 之间传递的工作单元
- Artifact:任务产出物(文件、数据等)
- Message:Agent 之间的通信消息
A2A vs MCP
| 维度 | MCP | A2A |
|---|---|---|
| 关注点 | Agent ↔ 工具/数据 | Agent ↔ Agent |
| 协议类型 | 工具调用协议 | 任务委托协议 |
| 服务端 | 工具服务器 | Agent 服务器 |
| 通信模式 | 请求-响应 | 任务生命周期 |
| 提出者 | Anthropic | |
| 互补性 | 提供工具能力 | 提供协作能力 |
两个协议是互补的,可以同时使用:Agent 通过 MCP 使用工具,通过 A2A 与其他 Agent 协作。
工具描述标准
OpenAPI / Swagger
传统的 API 描述标准,可以转换为 LLM 的工具定义:
# OpenAPI 3.0 示例
openapi: 3.0.0
paths:
/weather/{city}:
get:
summary: 获取城市天气
parameters:
- name: city
in: path
required: true
schema:
type: string
responses:
'200':
description: 天气信息
# OpenAPI → Function Calling 转换
def openapi_to_tools(spec):
tools = []
for path, methods in spec["paths"].items():
for method, details in methods.items():
tool = {
"type": "function",
"function": {
"name": f"{method}_{path.replace('/', '_')}",
"description": details.get("summary", ""),
"parameters": extract_parameters(details),
}
}
tools.append(tool)
return tools
工具描述最佳实践
# 完整的工具描述模板
tool_template = {
"name": "action_verb_noun", # 动词_名词 命名
"description": (
"一句话说明工具的功能。"
"何时使用:具体的使用场景描述。"
"何时不使用:明确的排除条件。"
"注意事项:使用限制或副作用。"
),
"input_schema": {
"type": "object",
"properties": {
"param1": {
"type": "string",
"description": "参数含义和格式要求",
"examples": ["示例值1", "示例值2"] # 非标准但有用
}
},
"required": ["param1"]
}
}
互操作性挑战
当前问题
- 协议碎片化:不同平台的工具定义格式不同
- 能力发现:如何让 Agent 发现可用的工具
- 认证授权:跨服务的认证管理
- 版本兼容:工具更新后的兼容性
解决方向
- MCP 作为统一层:越来越多的工具提供 MCP 接口
- 工具注册中心:集中管理工具的发现和版本
- OAuth 集成:MCP 正在增加 OAuth 支持
实践建议
- 新项目优先考虑 MCP 作为工具集成方案
- 使用现有的 MCP 服务器生态,避免重复开发
- 对于 Agent 间协作场景,关注 A2A 协议的发展
- 保持工具描述的清晰和完整
延伸阅读
- Claude Agent SDK - 使用 MCP 的 Agent 框架
- Anthropic. "Model Context Protocol" Documentation (modelcontextprotocol.io)
- Google. "Agent-to-Agent Protocol" Specification