Solo Unicorn Club logoSolo Unicorn
2,750

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

MCPModel Context ProtocolAnthropicTool UseAI Agent协议标准
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:

  1. MCP 已经赢了协议战——Claude、ChatGPT、Gemini、Copilot、VS Code 全部原生支持,Linux Foundation 背书,月 SDK 下载量 9700 万次。如果你还在写自定义的工具集成代码,是时候迁移了
  2. 先用社区 Server,再造自己的——MCP Registry 有上万个现成的 Server,覆盖了主流的 SaaS 工具。自己写 Server 之前,先看看有没有现成的
  3. MCP 不只是省代码,而是改变了 Agent 的设计方式——当工具接入成本降到足够低,你可以给 Agent 接更多工具,让它在更大的能力范围内工作。这是质变,不是量变

如果你在做 Agent 开发,建议花半天时间把一个现有的工具集成改成 MCP。体会一下"写 Server、连 Client、自动发现工具"这个流程,你会对 Agent 开发有新的理解。

你开始用 MCP 了吗?最好用的 MCP Server 是哪个?来一人独角兽俱乐部聊聊。