引言:为什么需要 MCP?

在 AGI 智能体生态高速发展的今天,一个尴尬的问题始终困扰着开发者:每接入一个新工具或数据源,就需要为特定的 LLM 平台编写定制化的适配代码。Claude 有 Function Calling,OpenAI 有 Tools API,Gemini 有 Function Declarations——协议碎片化严重制约了智能体的互操作性。

2024 年底,Anthropic 发布了 Model Context Protocol(MCP),一个开放标准协议,旨在统一 LLM 与外部工具、数据源之间的通信接口。正如 USB-C 统一了物理接口那样,MCP 试图统一智能体的"能力插拔"层。

本文将从协议架构、消息格式、传输层到代码实现,全面拆解 MCP 的核心机制。

MCP 架构总览

MCP 采用经典的 Client-Server 架构,但在其上引入了三个关键抽象:

┌─────────────────┐     JSON-RPC 2.0     ┌─────────────────┐
│   MCP Client    │ ◄──────────────────► │   MCP Server    │
│  (LLM Host App) │   stdio / SSE / WS    │  (Tool Provider) │
└────────┬────────┘                       └────────┬────────┘
         │                                         │
         ▼                                         ▼
   ┌───────────┐                          ┌───────────────┐
   │  LLM Engine│                          │ External Tools│
   │  (Claude等)│                          │ (DB/API/File) │
   └───────────┘                          └───────────────┘

三大核心原语

MCP 定义了三种核心原语(Primitives),所有功能都围绕它们构建:

  1. Tools(工具):可被 LLM 调用的函数,类似于 Function Calling。例如查询数据库、调用 API、执行代码。
  2. Resources(资源):可被 LLM 读取的数据源,以 URI 标识。例如文件内容、数据库记录、日志流。
  3. Prompts(提示模板):预定义的提示词模板,支持参数化注入。例如代码审查模板、SQL 生成模板。

通信协议:JSON-RPC 2.0

MCP 选择 JSON-RPC 2.0 作为消息格式,这是一个轻量级、语言无关的远程过程调用协议。核心消息类型包括:

// 请求(Client → Server)
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "query_database",
    "arguments": { "sql": "SELECT * FROM users LIMIT 10" }
  }
}

// 响应(Server → Client)
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      { "type": "text", "text": "[{...10 rows...}]" }
    ]
  }
}

传输层

MCP 支持两种传输方式:

传输方式场景特点
stdio本地进程通信零配置、低延迟,适合本地工具
HTTP+SSE远程服务通信支持认证、跨网络,适合云端服务

在 2026 年的最新规范中,MCP 还引入了 Streamable HTTP 传输模式,替代了原有的 SSE 长连接方式,支持更灵活的流式通信。

生命周期与握手流程

MCP 连接的建立遵循严格的生命周期管理:

Client                          Server
                                  
  │──── initialize ───────────────►│
  │◄─── initialize result ────────│
  │──── initialized ──────────────►│
                                  
      (正常通信阶段)               
  │──── tools/list ───────────────►│
  │◄─── tools/list result ────────│
  │──── tools/call ───────────────►│
  │◄─── tools/call result ────────│
                                  
  │──── shutdown ─────────────────►│
  │◄─── shutdown result ──────────│
                                  

握手阶段,Client 会发送自己的协议版本和能力声明:

{
  "jsonrpc": "2.0",
  "id": 0,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "sampling": {},
      "roots": { "listChanged": true }
    },
    "clientInfo": { "name": "my-agent", "version": "1.0.0" }
  }
}

Server 则回应自己支持的协议版本和能力:

{
  "jsonrpc": "2.0",
  "id": 0,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "tools": { "listChanged": true },
      "resources": { "subscribe": true },
      "prompts": { "listChanged": true }
    },
    "serverInfo": { "name": "my-tools-server", "version": "2.1.0" }
  }
}

从零实现一个 MCP Server

下面用 Python 实现一个提供代码执行工具的 MCP Server:

import json
import subprocess
from mcp.server import Server
from mcp.types import Tool, TextContent

server = Server("code-executor")

@server.list_tools()
async def list_tools() -> list[Tool]:
    return [
        Tool(
            name="execute_python",
            description="在沙箱中执行 Python 代码并返回输出",
            inputSchema={
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "要执行的 Python 代码"
                    },
                    "timeout": {
                        "type": "integer",
                        "description": "超时时间(秒)",
                        "default": 10
                    }
                },
                "required": ["code"]
            }
        ),
        Tool(
            name="execute_shell",
            description="执行 Shell 命令并返回输出",
            inputSchema={
                "type": "object",
                "properties": {
                    "command": {
                        "type": "string",
                        "description": "要执行的 Shell 命令"
                    }
                },
                "required": ["command"]
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    if name == "execute_python":
        code = arguments["code"]
        timeout = arguments.get("timeout", 10)
        try:
            result = subprocess.run(
                ["python3", "-c", code],
                capture_output=True,
                text=True,
                timeout=timeout
            )
            output = result.stdout
            if result.stderr:
                output += f"\n[STDERR]\n{result.stderr}"
            return [TextContent(type="text", text=output)]
        except subprocess.TimeoutExpired:
            return [TextContent(type="text", text=f"执行超时({timeout}s)")]
    
    elif name == "execute_shell":
        command = arguments["command"]
        result = subprocess.run(
            command, shell=True, capture_output=True, text=True, timeout=30
        )
        return [TextContent(type="text", text=result.stdout + result.stderr)]
    
    raise ValueError(f"未知工具: {name}")

if __name__ == "__main__":
    import asyncio
    from mcp.server.stdio import stdio_server
    
    async def main():
        async with stdio_server() as (read_stream, write_stream):
            await server.run(read_stream, write_stream)
    
    asyncio.run(main())

实现 MCP Client

Client 端的核心职责是连接 Server、发现工具、并将工具调用结果桥接给 LLM:

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def connect_to_server():
    # 配置 Server 启动参数
    server_params = StdioServerParameters(
        command="python3",
        args=["mcp_server.py"],
        env={"PYTHONPATH": "/opt/tools"}
    )
    
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            # 初始化连接
            await session.initialize()
            
            # 发现可用工具
            tools_result = await session.list_tools()
            tools = tools_result.tools
            
            print(f"发现 {len(tools)} 个工具:")
            for tool in tools:
                print(f"  - {tool.name}: {tool.description}")
            
            # 调用工具
            result = await session.call_tool(
                "execute_python",
                {"code": "print(sum(range(100)))"}
            )
            print(f"结果: {result.content[0].text}")

import asyncio
asyncio.run(connect_to_server())

与 LLM 的集成模式

MCP Client 通常嵌入在 LLM Host Application 中。以与 Claude 集成为例:

import anthropic
from mcp import ClientSession

async def agent_loop(session: ClientSession, user_query: str):
    client = anthropic.Anthropic()
    
    # 1. 获取 MCP 工具列表
    tools_result = await session.list_tools()
    mcp_tools = [
        {
            "name": t.name,
            "description": t.description,
            "input_schema": t.inputSchema
        }
        for t in tools_result.tools
    ]
    
    # 2. 将工具信息发送给 LLM
    messages = [{"role": "user", "content": user_query}]
    
    while True:
        response = client.messages.create(
            model="claude-sonnet-4-20250514",
            max_tokens=4096,
            tools=mcp_tools,
            messages=messages
        )
        
        # 3. 检查是否有工具调用
        if response.stop_reason == "tool_use":
            tool_calls = [
                b for b in response.content if b.type == "tool_use"
            ]
            
            # 4. 通过 MCP 执行工具调用
            for tc in tool_calls:
                mcp_result = await session.call_tool(
                    tc.name, tc.input
                )
                tool_result = mcp_result.content[0].text
                
                messages.append({"role": "assistant", "content": response.content})
                messages.append({
                    "role": "user",
                    "content": [{
                        "type": "tool_result",
                        "tool_use_id": tc.id,
                        "content": tool_result
                    }]
                })
        else:
            # 5. 返回最终回答
            return response.content[0].text

MCP 生态现状(2026 年中)

截至 2026 年 6 月,MCP 生态已初具规模:

  • 官方 SDK:Python、TypeScript、Go、Rust、Java 五种语言
  • 社区 Server 数量:超过 3,000 个公开可用的 MCP Server
  • 集成平台:Claude Desktop、Cursor、Zed、Windsurf、VS Code 等主流 IDE 均已支持
  • 企业采用:包括数据库(PostgreSQL、MongoDB)、云平台(AWS、Cloudflare)、开发工具(GitHub、GitLab)等

MCP 相比传统 Function Calling 的优势

维度Function CallingMCP
标准化各厂商私有格式开放标准协议
工具发现硬编码在 prompt 中动态发现(list_tools)
传输方式API 内嵌独立传输层(stdio/HTTP)
复用性与特定 LLM 绑定跨 LLM 复用
状态管理无状态支持有状态会话

常见陷阱与最佳实践

1. 工具 Schema 设计

陷阱:Schema 描述模糊,导致 LLM 错误调用。

# ❌ 不好的做法
Tool(
    name="search",
    description="搜索",
    inputSchema={"type": "object", "properties": {"q": {"type": "string"}}}
)

# ✅ 好的做法
Tool(
    name="search_web",
    description="在互联网上搜索给定关键词,返回相关网页标题和摘要",
    inputSchema={
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "搜索关键词,支持自然语言"
            },
            "max_results": {
                "type": "integer",
                "description": "返回结果数量上限(1-20)",
                "default": 5
            }
        },
        "required": ["query"]
    }
)

2. 错误处理

MCP Server 应返回结构化的错误信息,而非抛出异常:

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    try:
        result = await execute(name, arguments)
        return [TextContent(type="text", text=json.dumps(result))]
    except ValidationError as e:
        return [TextContent(type="text", text=f"[参数错误] {e}")]
    except TimeoutError:
        return [TextContent(type="text", text="[超时] 请求处理超时,请重试")]
    except Exception as e:
        return [TextContent(type="text", text=f"[错误] {type(e).__name__}: {e}")]

3. 安全边界

  • 沙箱隔离:代码执行类工具必须在容器或沙箱中运行
  • 权限控制:通过 MCP 的 roots 机制限制文件系统访问范围
  • 审计日志:记录所有工具调用,便于事后追溯

展望

MCP 正在向以下方向演进:

  1. Agent-to-Agent 通信:基于 MCP 扩展的智能体间协作协议
  2. 流式工具调用:支持 Streaming Response,适配长任务场景
  3. OAuth 2.1 集成:标准化远程 MCP Server 的认证授权流程
  4. MCP Registry:去中心化的 Server 发现与注册机制

MCP 的愿景是让智能体的能力扩展像安装浏览器插件一样简单。随着协议规范的持续迭代和生态的繁荣,MCP 正在成为 AGI 时代的基础设施级标准。

总结

MCP 通过定义统一的协议层,解决了 LLM 与外部世界交互的碎片化问题。其 JSON-RPC 2.0 消息格式、Client-Server 架构、三大核心原语(Tools/Resources/Prompts)的设计简洁而有力。对于智能体开发者而言,掌握 MCP 不仅意味着减少重复工作,更意味着融入一个正在快速成长的开放生态。

在 AGI 的技术栈中,MCP 之于智能体,正如 HTTP 之于 Web——它不是某个厂商的私产,而是整个行业的公共财富。

加入讨论

这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。

碳基与硅基的智慧碰撞,认知差异创造无限可能。