第2章 MCP协议深度解析
前言
理解MCP协议是掌握整个生态的基础。本章将从通信原理、核心概念、消息格式、安全机制等多个维度深入解析MCP协议的设计哲学和实现细节。
2.1 MCP架构与设计原理
2.1.1 客户端-服务器模型
MCP采用经典的客户端-服务器(Client-Server)架构,但与传统Web API不同,它实现了双向异步通信。
传统CS模型 vs MCP模型
graph TB
subgraph "传统API模型"
Client1["客户端"] -->|请求| Server1["服务器"]
Server1 -->|响应| Client1
Client1 -->|新请求| Server1
end
subgraph "MCP双向模型"
Client2["客户端"] -->|调用工具| Server2["MCP服务器"]
Server2 -->|结果| Client2
Server2 -.->|资源更新通知| Client2
Client2 -.->|订阅资源| Server2
end
style Client1 fill:#e3f2fd
style Server1 fill:#c8e6c9
style Client2 fill:#e3f2fd
style Server2 fill:#c8e6c9
MCP模型的核心特点:
-
双向通信
- 客户端可以主动调用工具、访问资源
- 服务器可以主动推送资源变化通知
- 形成一个真正的对话通道,而不只是请求-响应
-
异步处理
- 消息不需要立即响应
- 支持长时间运行的操作
- 请求可以被取消
-
多路复用
- 单个连接上支持多个并发请求
- 每个请求有唯一的ID来追踪
- 避免了连接阻塞
2.1.2 通信机制与消息格式
MCP基于JSON-RPC 2.0规范构建,选择这个标准是因为:
- 轻量级、易于解析
- 平台无关、语言无关
- 已有成熟的实现库
- 广泛被业界接受
MCP通信的三个层级
graph LR
A["应用层"] -->|MCP消息| B["传输层"]
B -->|JSON-RPC 2.0| C["通信层"]
C -->|HTTP/WebSocket/stdio| D["物理层"]
A -->|定义| A1["工具、资源、提示"]
B -->|定义| B1["请求、响应、通知"]
C -->|定义| C1["JSON-RPC结构"]
D -->|支持| D1["多种传输方式"]
JSON-RPC 2.0基础
一个标准的JSON-RPC请求:
{
"jsonrpc": "2.0",
"id": "req_123",
"method": "tools/call",
"params": {
"name": "query_sales",
"arguments": {
"start_date": "2025-01-01",
"end_date": "2025-12-31"
}
}
}
响应格式:
{
"jsonrpc": "2.0",
"id": "req_123",
"result": {
"content": [
{
"type": "text",
"text": "销售总额:$5,000,000"
}
]
}
}
或者错误响应:
{
"jsonrpc": "2.0",
"id": "req_123",
"error": {
"code": -32602,
"message": "Invalid params",
"data": {
"details": "start_date format must be YYYY-MM-DD"
}
}
}
关键概念:
| 字段 | 说明 | 示例 |
|---|---|---|
jsonrpc | 协议版本 | "2.0" |
id | 请求唯一标识 | "req_123"(字符串或数字) |
method | 调用的方法 | "tools/call"、"resources/read" |
params | 方法参数 | 对象或数组 |
result | 成功时的结果 | 任意JSON值 |
error | 失败时的错误 | {code, message, data} |
2.1.3 MCP消息类型完整体系
graph TB
A["MCP消息"] --> B["请求 Request"]
A --> C["响应 Response"]
A --> D["通知 Notification"]
A --> E["资源更新 ResourceUpdated"]
B --> B1["initialize"]
B --> B2["tools/call"]
B --> B3["resources/read"]
B --> B4["resources/subscribe"]
C --> C1["result"]
C --> C2["error"]
D --> D1["客户端发起"]
D --> D2["服务器不期望响应"]
E --> E1["资源内容变化"]
E --> E2["资源列表变化"]
style A fill:#ff6b6b
style B fill:#4ecdc4
style C fill:#4ecdc4
style D fill:#95e1d3
style E fill:#95e1d3
2.1.4 协议的演进与版本管理
timeline
title MCP协议版本演进
2024-03 : MCP 1.0 : 初始版本发布
2024-06 : MCP 1.0.1 : 修复、澄清
2024-09 : MCP 1.1 : 资源订阅、改进的错误处理
2024-12 : MCP 1.2 : 性能优化、新的传输方式
2025-03 : MCP 2.0 (规划) : 可能的重大更新
版本兼容性策略:
- 主版本号变更:不保证向后兼容
- 次版本号变更:向后兼容
- 修订号变更:bug修复和澄清
客户端和服务器应该在初始化时协商协议版本。
2.2 MCP的核心概念
2.2.1 工具(Tools)的定义与作用
定义:工具是LLM可以调用的功能,用于执行具体的操作或计算任务。
本质:工具 = 元数据 + 实现
{
"name": "transfer_funds",
"description": "转账资金到指定账户",
"inputSchema": {
"type": "object",
"properties": {
"from_account": {
"type": "string",
"description": "源账户ID"
},
"to_account": {
"type": "string",
"description": "目标账户ID"
},
"amount": {
"type": "number",
"description": "转账金额"
},
"reason": {
"type": "string",
"description": "转账原因"
}
},
"required": ["from_account", "to_account", "amount"]
}
}
工具的生命周期:
sequenceDiagram
participant LLM
participant Client
participant Server
participant Backend
LLM->>Client: 需要调用工具
Client->>Server: 列出可用工具
Server-->>Client: 工具元数据列表
LLM->>Client: 调用具体工具
Client->>Server: tools/call请求
Server->>Backend: 执行业务逻辑
Backend-->>Server: 返回结果
Server-->>Client: 返回结果
Client-->>LLM: 工具执行结果
工具的分类:
| 类型 | 特点 | 示例 |
|---|---|---|
| 查询类 | 只读,返回信息 | 查询账户余额、搜索文档 |
| 操作类 | 修改状态,有副作用 | 创建订单、发送邮件 |
| 计算类 | 数学运算、数据处理 | 分析数据、生成报告 |
| 转换类 | 格式转换、数据映射 | 导出Excel、格式化文本 |
2.2.2 资源(Resources)的含义
定义:资源是LLM可以访问的数据源或信息,代表持久化的内容。
本质:资源 = 标识 + 内容 + 元数据
资源 vs 工具的区别:
graph TB
A["MCP组件"] --> B["工具 Tools"]
A --> C["资源 Resources"]
B --> B1["动态行为"]
B --> B2["每次调用可能返回不同结果"]
B --> B3["可能有副作用"]
B --> B4["例:生成报告"]
C --> C1["静态数据"]
C --> C2["持久化内容"]
C --> C3["通常是只读的"]
C --> C4["例:报告文件"]
style B fill:#ffcccc
style C fill:#ccccff
资源URI方案:
resources://authority/path?query=value
示例:
- resources://salesdb/reports/q1_2025.xlsx
- resources://docs/product_manual.pdf
- resources://config/system_settings.json
- resources://employees/dept_001/team_list.csv
资源的三种访问模式:
graph TB
A["资源访问"] --> B["列表模式"]
A --> C["读取模式"]
A --> D["订阅模式"]
B --> B1["列出资源列表"]
B --> B2["支持过滤和搜索"]
B --> B3["返回资源元数据"]
C --> C1["一次性读取"]
C --> C2["完整内容"]
C --> C3["无状态操作"]
D --> D1["持续监听更新"]
D --> D2["资源变化推送"]
D --> D3["维持长连接"]
2.2.3 提示模板(Prompts)的角色
定义:提示模板是预定义的、参数化的提示词,用于指导LLM的行为。
作用:
- 标准化:确保相同的任务获得一致的处理
- 参数化:支持动态参数注入
- 知识编码:将专家知识编码到提示中
- 复用:跨项目、跨团队共享
提示模板示例:
{
"name": "analyze_sales_trends",
"description": "分析销售趋势的专家级提示",
"arguments": [
{
"name": "time_period",
"description": "分析的时间周期",
"required": true
},
{
"name": "product_category",
"description": "产品类别(可选)",
"required": false
}
]
}
模板内容示例:
请作为销售分析专家,分析{time_period}的销售数据。
关注点:
1. 销售额趋势
2. 产品结构变化
3. 区域表现差异
{#if product_category}
4. 特别关注{product_category}类别的表现
{/if}
请提供具体的建议和预测。
2.2.4 取样(Sampling)机制
定义:取样是让服务器能够请求LLM进行推理的机制。这形成了一个循环。
应用场景:
- 服务器需要LLM帮助做决策
- 数据验证或复杂的业务逻辑判断
- 需要LLM的自然语言理解能力
取样流程:
sequenceDiagram
participant Client as 客户端LLM
participant Server as MCP服务器
participant App as 业务系统
Client->>Server: 调用工具处理数据
Server->>App: 获取数据
App-->>Server: 返回数据
Note over Server: 需要LLM判断数据有效性
Server->>Client: sampling/createMessage请求
Client->>Client: 调用LLM推理
Client-->>Server: 推理结果
Server->>Server: 根据LLM结果做决策
Server-->>Client: 工具执行结果
这创造了一个自反馈循环,让MCP系统具有更高的智能性。
2.3 MCP的通信协议
2.3.1 JSON-RPC 2.0详细解析
请求类型
1. 标准请求(期望响应)
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": {},
"sampling": {}
},
"clientInfo": {
"name": "Claude Desktop",
"version": "1.0.0"
}
}
}
2. 通知(不期望响应)
{
"jsonrpc": "2.0",
"method": "notifications/resources/list_changed"
}
通知用于单向通信,不需要响应。
响应类型
1. 成功响应
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"resources": {},
"tools": {}
},
"serverInfo": {
"name": "Sales Database",
"version": "2.1.0"
}
}
}
2. 错误响应
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32601,
"message": "Method not found",
"data": {
"method": "unknown_method"
}
}
}
JSON-RPC 2.0错误码标准:
| 错误码 | 含义 | 说明 |
|---|---|---|
| -32700 | Parse error | JSON解析失败 |
| -32600 | Invalid Request | 请求格式不正确 |
| -32601 | Method not found | 方法不存在 |
| -32602 | Invalid params | 参数不合法 |
| -32603 | Internal error | 服务器内部错误 |
| -32000到-32099 | Server error | 服务器自定义错误 |
2.3.2 请求-响应模式详解
请求ID的重要性
在异步环境中,请求ID用于匹配请求和响应:
sequenceDiagram
participant Client
participant Server
Client->>Server: 请求1 (id=req1)
Client->>Server: 请求2 (id=req2)
Client->>Server: 请求3 (id=req3)
Note over Server: 异步处理,顺序不定
Server-->>Client: 响应2 (id=req2)
Server-->>Client: 响应1 (id=req1)
Server-->>Client: 响应3 (id=req3)
Note over Client: 按ID匹配,顺序无关
多路复用示例
# 伪代码:客户端同时发起多个请求
async def call_multiple_tools():
# 发起三个并发请求
task1 = client.call_tool("query_sales", id="req1")
task2 = client.call_tool("calculate_average", id="req2")
task3 = client.call_tool("fetch_report", id="req3")
# 等待所有响应(无需按顺序)
results = await asyncio.gather(task1, task2, task3)
return results
2.3.3 流式与实时通信
MCP支持多种传输方式,适应不同场景:
graph TB
A["MCP传输方式"] --> B["标准输入输出"]
A --> C["HTTP"]
A --> D["WebSocket"]
A --> E["自定义"]
B --> B1["本地进程通信"]
B --> B2["低延迟"]
B --> B3["例:Claude Desktop"]
C --> C1["REST over HTTP"]
C --> C2["无状态"]
C --> C3["轻量级部署"]
D --> D1["双向长连接"]
D --> D2["实时推送"]
D --> D3["高效复用"]
E --> E1["gRPC"]
E --> E2["自定义协议"]
各传输方式对比:
| 方式 | 延迟 | 连接管理 | 实时性 | 适用场景 |
|---|---|---|---|---|
| stdio | 极低 | 简单 | 同步 | 本地工具、桌面应用 |
| HTTP | 中 | 无状态 | 低 | REST API、无状态服务 |
| WebSocket | 低 | 持久连接 | 高 | 实时推送、长连接 |
2.4 MCP的安全性与权限控制
2.4.1 身份验证机制
多层验证体系
graph TB
A["安全认证体系"] --> B["传输层"]
A --> C["应用层"]
A --> D["资源层"]
B --> B1["TLS加密"]
B --> B2["证书验证"]
B --> B3["mTLS"]
C --> C1["API Key"]
C --> C2["OAuth 2.0"]
C --> C3["JWT Token"]
D --> D1["资源访问控制"]
D --> D2["时间限制"]
D --> D3["操作限制"]
API Key验证
最简单的验证方式:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"clientInfo": {
"name": "Claude",
"version": "1.0"
},
"authentication": {
"type": "api_key",
"key": "sk-1234567890abcdef"
}
}
}
OAuth 2.0集成
对于复杂的企业场景:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"authentication": {
"type": "oauth2",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"scope": ["tools:read", "resources:read"]
}
}
}
2.4.2 权限模型
细粒度权限控制
graph TB
A["权限模型"] --> B["工具权限"]
A --> C["资源权限"]
A --> D["操作权限"]
B --> B1["工具可见性"]
B --> B2["工具调用权限"]
B --> B3["工具参数限制"]
C --> C1["资源读"]
C --> C2["资源写"]
C --> C3["资源删除"]
D --> D1["创建"]
D --> D2["查询"]
D --> D3["更新"]
D --> D4["删除"]
权限定义示例:
{
"version": "2024-11-05",
"permissions": {
"tools": {
"query_sales": {
"allowed": true,
"timeRange": {
"startDate": "2025-01-01",
"endDate": "2025-12-31"
}
},
"transfer_funds": {
"allowed": true,
"maxAmount": 100000,
"requiresApproval": true
}
},
"resources": {
"resources://finance/*": {
"read": true,
"write": false
}
}
}
}
2.4.3 数据隐私保护
数据敏感化策略
graph TB
A["数据隐私保护"] --> B["数据分类"]
A --> C["访问控制"]
A --> D["审计日志"]
A --> E["加密"]
B --> B1["公开数据"]
B --> B2["内部数据"]
B --> B3["机密数据"]
B --> B4["个人数据"]
C --> C1["基于角色"]
C --> C2["基于时间"]
C --> C3["基于位置"]
D --> D1["操作日志"]
D --> D2["访问日志"]
D --> D3["变更日志"]
E --> E1["传输加密TLS"]
E --> E2["存储加密"]
E --> E3["字段加密"]
个人数据脱敏示例:
# 返回客户信息前进行脱敏
def anonymize_customer_data(customer):
return {
"id": customer["id"],
"email": mask_email(customer["email"]), # 隐藏部分邮箱
"phone": mask_phone(customer["phone"]), # 隐藏部分电话
"name": customer["name"], # 完整名字
# 注意:不返回敏感字段如密码、SSN等
}
def mask_email(email):
# example@domain.com -> exa***@domain.com
parts = email.split("@")
return parts[0][:3] + "***@" + parts[1]
def mask_phone(phone):
# 13812345678 -> 1381****5678
return phone[:4] + "****" + phone[-4:]
HIPAA/GDPR合规
对于医疗和欧洲客户:
{
"security": {
"encryption": {
"transport": "TLS 1.3",
"storage": "AES-256"
},
"compliance": ["HIPAA", "GDPR"],
"dataRetention": {
"logs": "30 days",
"personalData": "user configurable"
},
"audit": {
"enabled": true,
"retention": "90 days",
"immutable": true
}
}
}
2.5 MCP协议在实践中的应用
2.5.1 完整的工具调用流程
sequenceDiagram
participant User
participant LLM
participant Client
participant Server
participant DB
User->>LLM: "查询2025年销售数据"
LLM->>Client: 需要调用query_sales工具
Client->>Server: 请求 {method: "tools/call", name: "query_sales"}
Server->>DB: 查询数据
DB-->>Server: 返回销售记录
Server-->>Client: 响应 {result: 销售数据}
Client-->>LLM: 工具执行结果
LLM->>LLM: 分析数据
LLM-->>User: "2025年销售总额$5M,同比增长15%..."
2.5.2 错误处理最佳实践
# 客户端侧的完善错误处理
class MCPClient:
async def call_tool(self, tool_name, arguments):
try:
request = {
"jsonrpc": "2.0",
"id": self.generate_request_id(),
"method": "tools/call",
"params": {
"name": tool_name,
"arguments": arguments
}
}
# 发送请求并设置超时
response = await self.send_request(request, timeout=30)
# 检查是否有错误
if "error" in response:
error = response["error"]
if error["code"] == -32602:
raise InvalidParamsError(error["message"])
elif error["code"] == -32601:
raise MethodNotFoundError(error["message"])
else:
raise MCPError(error["message"])
return response.get("result")
except asyncio.TimeoutError:
raise TimeoutError(f"Tool {tool_name} execution timeout")
except ConnectionError:
raise ConnectionError("Lost connection to MCP server")
本章总结
| 核心概念 | 关键点 |
|---|---|
| 架构模型 | 客户端-服务器,双向异步通信 |
| 通信基础 | JSON-RPC 2.0,轻量级、标准化 |
| 核心概念 | 工具、资源、提示、取样 |
| 消息类型 | 请求、响应、通知、资源更新 |
| 多路复用 | 单连接并发多个请求,按ID匹配 |
| 传输方式 | stdio、HTTP、WebSocket等 |
| 安全认证 | API Key、OAuth 2.0、JWT |
| 权限控制 | 细粒度的工具、资源、操作权限 |
| 数据隐私 | 脱敏、加密、审计、合规 |
常见问题
Q1: 为什么MCP选择JSON-RPC而不是gRPC或REST? A: JSON-RPC相比gRPC更轻量级,更易于跨语言实现;相比REST更适合双向通信。这是在简洁性和功能性之间的最优平衡。
Q2: 单个连接如何支持并发请求?
A: 通过为每个请求分配唯一的id,响应时返回相同的id,客户端据此匹配。这样即使响应顺序打乱也能正确处理。
Q3: 通知(notification)和请求有什么区别?
A: 通知没有id字段,发送端不期望响应,用于单向消息。请求有id,发送端期望收到响应。
Q4: 资源和工具如何选择使用? A: 规则是:如果内容是持久的、不变的数据用资源;如果是动态计算、有副作用的操作用工具。
Q5: MCP如何保证消息安全? A: 多层防护:传输层TLS加密、应用层身份验证和授权、资源层细粒度权限控制、审计日志记录。
关键代码片段
TypeScript中的请求处理
interface MCPRequest {
jsonrpc: "2.0";
id: string | number;
method: string;
params?: Record<string, any>;
}
interface MCPResponse {
jsonrpc: "2.0";
id: string | number;
result?: any;
error?: {
code: number;
message: string;
data?: any;
};
}
async function sendRequest(request: MCPRequest): Promise<MCPResponse> {
const response = await fetch("http://mcp-server/rpc", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(request)
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
延伸阅读
- JSON-RPC 2.0规范:www.jsonrpc.org/specificati…
- MCP协议规范:spec.modelcontextprotocol.io
- 安全认证最佳实践:参见第23章
下一章预告:第3章将讲述MCP与LLM的协同机制,包括工具调用、上下文注入、循环推理等核心互动方式。