MCP (Model Context Protocol) — 为什么它改变了一切

MCP (Model Context Protocol) — 为什么它改变了一切
开场
2025 年之前,我给每个 AI Agent 接外部工具都要写一套自定义的集成代码。接一个 Slack 写 200 行,接一个 Google Calendar 写 300 行,接一个数据库写 400 行。每换一个 LLM 提供商,集成层全部重写。MCP 出来之后,我把 8-Agent 社群管理系统的工具集成代码从 3,200 行砍到了 600 行——因为不用再为每个工具写适配器了。MCP 做的事情很简单:给 AI 和工具之间定义了一个标准接口。但这件简单的事,正在重新定义 Agent 的开发方式。
问题背景
在 MCP 之前,AI Agent 接工具的方式是这样的:
Agent ←→ 自定义适配器 A ←→ Slack API
Agent ←→ 自定义适配器 B ←→ Google Calendar API
Agent ←→ 自定义适配器 C ←→ Database
Agent ←→ 自定义适配器 D ←→ GitHub API
每个适配器都要处理:认证、数据格式转换、错误处理、重试逻辑。四个工具就是四套完全不同的代码。换一个 LLM(从 OpenAI 切到 Claude),所有适配器的 function calling 格式都要改。
这就是 N x M 问题:N 个 LLM 提供商 x M 个工具 = N x M 套集成代码。
MCP 把它变成了 N + M:每个 LLM 实现一次 MCP client,每个工具实现一次 MCP server,中间用标准协议通信。
核心架构
MCP 是什么
Model Context Protocol 是 Anthropic 在 2024 年底开源的协议标准。2026 年 2 月,Anthropic 将 MCP 捐赠给了 Agentic AI Foundation (AAIF)——一个在 Linux Foundation 下由 Anthropic、Block、OpenAI 联合创立的基金会,Google、Microsoft、AWS、Cloudflare、Bloomberg 均参与支持。
用一句话概括:MCP 是 AI Agent 调用外部工具的 USB 接口。
架构组件
┌─────────────┐ MCP Protocol ┌─────────────┐
│ MCP Client │ ←──────────────────→ │ MCP Server │
│ (LLM 侧) │ JSON-RPC 2.0 │ (工具侧) │
│ │ stdio / HTTP SSE │ │
│ Claude │ │ Slack │
│ ChatGPT │ │ GitHub │
│ Gemini │ │ Database │
│ VS Code │ │ Calendar │
└─────────────┘ └─────────────┘
MCP 定义了三种核心能力:
| 能力 | 说明 | 示例 |
|---|---|---|
| Tools | 可调用的函数 | 发送 Slack 消息、创建 GitHub Issue |
| Resources | 可读取的数据源 | 读取文件内容、获取数据库 schema |
| Prompts | 可复用的 prompt 模板 | 代码审查模板、翻译模板 |
MCP 的最新进展(2026 年 3 月)
- SDK 月下载量达到 9,700 万次(Python + TypeScript)
- 生态内活跃 MCP Server 超过 10,000 个
- Claude、ChatGPT、Gemini、Copilot、VS Code 全部原生支持
- 新增 MCP Apps 扩展:工具可以返回交互式 UI 组件(仪表盘、表单、可视化)
- 新增异步操作、无状态模式、Server Identity 等生产级特性
- 官方 MCP Registry 上线,可以搜索和发现可用的 MCP Server
实现细节
Step 1:搭建一个 MCP Server
以一个社群知识库工具为例:
from mcp.server import Server
from mcp.types import Tool, TextContent
from mcp.server.stdio import stdio_server
# 创建 MCP Server
server = Server("community-knowledge-base")
# 注册工具:搜索知识库
@server.tool()
async def search_knowledge(query: str, top_k: int = 3) -> list[TextContent]:
"""在社群知识库中搜索相关内容
Args:
query: 搜索关键词或问题
top_k: 返回结果数量
"""
# 实际的检索逻辑
results = await vector_db.search(query, limit=top_k)
formatted = []
for r in results:
formatted.append(TextContent(
type="text",
text=f"[相关度: {r.score:.2f}] {r.payload['content']}"
))
return formatted
# 注册工具:添加新知识
@server.tool()
async def add_knowledge(content: str, source: str, category: str) -> TextContent:
"""向知识库添加新内容
Args:
content: 要添加的知识内容
source: 来源(如:社群讨论、文档、FAQ)
category: 分类(如:技术、商业、活动)
"""
doc_id = await vector_db.upsert(content, metadata={
"source": source,
"category": category,
"added_at": datetime.now().isoformat()
})
return TextContent(type="text", text=f"已添加,文档 ID: {doc_id}")
# 注册资源:知识库统计
@server.resource("kb://stats")
async def get_kb_stats() -> str:
"""获取知识库的统计信息"""
stats = await vector_db.get_stats()
return f"文档总数: {stats['total']}, 最近更新: {stats['last_updated']}"
# 启动 Server(通过 stdio 通信)
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream)
Step 2:在 Agent 中使用 MCP Client
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def agent_with_mcp():
"""Agent 通过 MCP 调用工具"""
# 连接 MCP Server
server_params = StdioServerParameters(
command="python",
args=["community_kb_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()
print(f"可用工具: {[t.name for t in tools.tools]}")
# 输出: ['search_knowledge', 'add_knowledge']
# 调用工具
result = await session.call_tool(
name="search_knowledge",
arguments={"query": "如何申请退款", "top_k": 3}
)
print(result.content)
Step 3:多 MCP Server 组合
这是 MCP 的真正威力——一个 Agent 同时连接多个 MCP Server,每个 Server 提供不同的能力。
from mcp.client.stdio import stdio_client
# 配置多个 MCP Server
MCP_SERVERS = {
"knowledge_base": StdioServerParameters(
command="python", args=["kb_server.py"]
),
"slack": StdioServerParameters(
command="npx", args=["-y", "@anthropic/mcp-slack-server"]
),
"github": StdioServerParameters(
command="npx", args=["-y", "@anthropic/mcp-github-server"]
),
"calendar": StdioServerParameters(
command="npx", args=["-y", "@anthropic/mcp-google-calendar-server"]
),
}
class MultiToolAgent:
def __init__(self):
self.sessions: dict[str, ClientSession] = {}
self.all_tools: list = []
async def connect_all(self):
"""连接所有 MCP Server,聚合工具列表"""
for name, params in MCP_SERVERS.items():
# 每个 Server 独立连接
read, write = await stdio_client(params).__aenter__()
session = await ClientSession(read, write).__aenter__()
await session.initialize()
self.sessions[name] = session
# 聚合工具(自动发现,不需要硬编码)
tools = await session.list_tools()
for tool in tools.tools:
self.all_tools.append({
"server": name,
"tool": tool,
})
print(f"已连接 {len(self.sessions)} 个 Server,"
f"共 {len(self.all_tools)} 个工具")
async def call(self, tool_name: str, args: dict):
"""调用任意工具,自动路由到正确的 Server"""
for entry in self.all_tools:
if entry["tool"].name == tool_name:
return await self.sessions[entry["server"]].call_tool(
name=tool_name, arguments=args
)
raise ValueError(f"工具 {tool_name} 不存在")
与 Anthropic Tool Search 配合
当工具数量多(几十到上百个),把所有工具描述都塞进 prompt 太浪费 token。Anthropic 最近推出的 Tool Search 和 Programmatic Tool Calling 就是解决这个问题的:
# 概念示意:只在需要时加载相关工具
# 而非把所有工具定义都放进每次请求
relevant_tools = await tool_search.find_relevant(
query=user_message,
available_tools=all_mcp_tools,
top_k=5 # 只选最相关的 5 个工具
)
# 这样 prompt 里只有 5 个工具定义,而不是 50 个
实战经验
迁移前后的对比
我把 8-Agent 社群管理系统从自定义集成迁移到 MCP 的前后对比:
| 指标 | 迁移前 | 迁移后 |
|---|---|---|
| 工具集成代码量 | 3,200 行 | 600 行 |
| 新增一个工具的时间 | 2-4 小时 | 15-30 分钟 |
| 切换 LLM 提供商的成本 | 重写适配层 | 改一行配置 |
| 工具调用延迟 | 150-300ms | 80-200ms |
| 可用工具数量 | 6 个 | 12 个(接入了社区 Server) |
最大的变化不是代码量的减少,而是心智负担的降低。以前每接一个新工具都要想认证怎么做、错误怎么处理、格式怎么转换。现在找一个现成的 MCP Server,配置好就能用。
踩过的坑
坑 1:Server 的稳定性参差不齐。社区维护的 MCP Server 质量差异很大。有些 Server 没有做好错误处理,工具调用失败会直接崩溃。解决方案:在 MCP Client 侧加 timeout 和 retry,任何工具调用超过 10 秒自动取消。
坑 2:stdio 模式的进程管理。MCP 的 stdio 模式是通过启动子进程通信的,长时间运行后偶尔出现进程僵死。解决方案:对 Server 进程做健康检查,每小时重启一次。生产环境建议用 HTTP SSE 模式替代 stdio。
坑 3:工具描述的质量。MCP Server 暴露的工具描述是给 LLM 看的,如果描述不清楚,LLM 不知道什么时候该调用、怎么传参。解决方案:自己维护一份工具描述的覆盖配置,替换掉质量差的默认描述。
坑 4:安全考量。MCP Server 对你的数据有访问权限,恶意或有 bug 的 Server 可能泄露数据。解决方案:只使用可信来源的 Server,对 Server 的网络访问做限制(只允许访问必要的端点),敏感操作加 Human-in-the-Loop。
对比选型
| 维度 | 自定义集成 | MCP | LangChain Tools |
|---|---|---|---|
| 开发成本 | 高(每个工具单独写) | 低(用现成 Server) | 中(有些封装) |
| 灵活性 | 最高 | 高(可自定义 Server) | 中(受框架约束) |
| 生态 | 自己维护 | 10,000+ Server | 300+ 集成 |
| 跨模型支持 | 需要适配 | 原生支持 | 依赖 LangChain |
| 标准化 | 无标准 | 行业标准 | 框架标准 |
| 生产稳定性 | 自控 | 依赖 Server 质量 | 依赖框架版本 |
总结
三条 takeaway:
- MCP 已经赢了协议战——Claude、ChatGPT、Gemini、Copilot、VS Code 全部原生支持,Linux Foundation 背书,月 SDK 下载量 9700 万次。如果你还在写自定义的工具集成代码,是时候迁移了
- 先用社区 Server,再造自己的——MCP Registry 有上万个现成的 Server,覆盖了主流的 SaaS 工具。自己写 Server 之前,先看看有没有现成的
- MCP 不只是省代码,而是改变了 Agent 的设计方式——当工具接入成本降到足够低,你可以给 Agent 接更多工具,让它在更大的能力范围内工作。这是质变,不是量变
如果你在做 Agent 开发,建议花半天时间把一个现有的工具集成改成 MCP。体会一下"写 Server、连 Client、自动发现工具"这个流程,你会对 Agent 开发有新的理解。
你开始用 MCP 了吗?最好用的 MCP Server 是哪个?来一人独角兽俱乐部聊聊。