MCP 协议原理:Host / Client / Server 三角架构与 JSON-RPC 2.0 消息格式
第三十四章:MCP 协议详解:架构、传输层与能力声明
34.1 MCP 的诞生背景
在 MCP(Model Context Protocol)出现之前,每一个希望给 AI 模型提供工具能力的开发者都面临同样的困境:工具集成是碎片化的、不可复用的。OpenAI 有自己的 Function Calling 格式,Anthropic 有 Tool Use 规范,LangChain 有自己的 Tool 抽象,各家格式互不兼容。一个优秀的数据库查询工具,如果想同时支持 ChatGPT 和 Claude,就需要维护两套完全不同的代码。
2024年11月,Anthropic 发布了 MCP(Model Context Protocol),这是一个开放的、供应商中立的协议标准,目标是成为 AI 模型与外部工具之间的 USB-C 接口——一个统一的连接标准,让工具的开发者只需实现一次,就能被所有支持 MCP 的 AI 客户端使用。
MCP 的设计哲学核心是关注点分离:
- MCP Server(服务端):专注于提供能力,暴露工具、资源和提示模板
- MCP Client(客户端):专注于与 AI 模型集成,代理用户调用 Server 的能力
- Host(宿主):运行 Client 的应用程序(如 Claude Desktop、Claude Code、自定义 AI 应用)
34.2 MCP 整体架构
34.2.1 三层架构模型
┌─────────────────────────────────────────┐
│ Host Application │
│ (Claude Desktop / Claude Code / 自定义) │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ MCP Client │ │ MCP Client │ │
│ │ (连接 A) │ │ (连接 B) │ │
│ └──────┬───────┘ └──────┬───────┘ │
└─────────┼─────────────────┼─────────────┘
│ │
MCP Protocol MCP Protocol
(stdio / HTTP) (stdio / HTTP)
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ MCP Server │ │ MCP Server │
│ (文件系统) │ │ (数据库) │
└─────────────┘ └─────────────┘
Host 可以同时维护多个 MCP Client 连接,每个 Client 连接一个 MCP Server。Claude 模型通过 Host 的 Client 层访问 Server 提供的能力,整个过程对模型透明——模型看到的只是抽象化的工具调用接口。
34.2.2 核心概念关系图
| 概念 | 由谁提供 | 作用 |
|---|---|---|
| Tools(工具) | MCP Server | 可执行的函数,模型可以调用 |
| Resources(资源) | MCP Server | 可读取的数据,类似文件或 URL |
| Prompts(提示) | MCP Server | 预定义的提示模板,供用户选择 |
| Roots(根路径) | MCP Client | 告知 Server 当前工作目录范围 |
| Sampling(采样) | MCP Client | Server 请求 Host 调用 LLM |
34.3 传输层详解
MCP 定义了两种标准传输层,分别适用于不同的部署场景。
34.3.1 stdio 传输(本地进程通信)
stdio 是最简单也最常用的传输方式,适用于 Server 和 Client 在同一台机器上运行的场景。
工作原理:
- Host 应用通过
subprocess启动 MCP Server 进程 - Client 通过标准输入(stdin)向 Server 发送 JSON-RPC 消息
- Server 通过标准输出(stdout)返回响应
- Server 的日志信息通过 stderr 输出(不干扰协议通信)
Host Process
│
├── stdin → [JSON-RPC Request] → MCP Server Process
│
└── stdout ← [JSON-RPC Response] ← MCP Server Process
stdio 的优势:
- 零网络配置,无需端口、无需 TLS
- 天然的进程隔离(Server 崩溃不影响 Host)
- 安全性高(无网络暴露面)
stdio 的限制:
- Server 必须与 Client 在同一台机器
- 一个 Server 实例只能被一个 Client 连接
- 不支持 Server 主动推送通知(除非使用单独管道)
Claude Desktop 的 stdio 配置示例(~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/username/Documents"],
"env": {}
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxxxxxxxxx"
}
}
}
}
34.3.2 HTTP + SSE 传输(远程服务通信)
HTTP + SSE(Server-Sent Events) 是为远程部署设计的传输层,支持 Server 和 Client 分离部署,适合多用户、云端服务场景。
通信模式:
- Client 通过 HTTP POST 向 Server 发送请求
- Server 通过 SSE(单向长连接)向 Client 推送通知和响应
MCP Client MCP Server (远程)
│ │
├─── HTTP POST /message ────────▶│ 发送请求
│ │
│◀── SSE /sse ──────────────────│ 接收响应/通知(长连接)
│ │
│ GET /sse → 建立 SSE 连接 │
HTTP+SSE 的优势:
- 支持远程 Server(跨网络访问)
- 支持多个 Client 连接同一个 Server
- Server 可以主动向 Client 推送事件
- 支持标准的 HTTP 认证(Bearer Token、OAuth)
HTTP+SSE 的限制:
- 需要网络连接和正确的 TLS 配置
- 需要处理连接断开重连逻辑
- 相比 stdio 延迟略高
2025年新增的 Streamable HTTP 传输:Anthropic 在 2025年3月更新的规范中,引入了 Streamable HTTP 作为更灵活的 HTTP 传输变体,允许在单个 HTTP 请求中以流式方式返回多个响应消息,同时保持对 SSE 的向后兼容。
34.4 MCP 消息格式:JSON-RPC 2.0
MCP 基于 JSON-RPC 2.0 规范定义消息格式。所有消息都是 JSON 对象,分为三种类型:
34.4.1 请求(Request)
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "read_file",
"arguments": {
"path": "/home/user/document.txt"
}
}
}
34.4.2 响应(Response)
成功响应:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "文件内容..."
}
],
"isError": false
}
}
错误响应:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid Request",
"data": "文件路径不存在"
}
}
34.4.3 通知(Notification)
通知是无需响应的单向消息(无 id 字段):
{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed",
"params": {}
}
34.5 能力声明:初始化握手
MCP 连接建立时,Client 和 Server 通过能力协商(Capability Negotiation)互相声明自己支持的功能。
34.5.1 初始化流程
Client Server
│ │
├──── initialize ──────────────▶│
│ (clientCapabilities) │
│ │
│◀─── initialize response ──────│
│ (serverCapabilities) │
│ │
├──── initialized ─────────────▶│
│ (通知:初始化完成) │
│ │
│ [正常工作] │
34.5.2 完整的初始化消息
Client 发送的 initialize 请求:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": {
"listChanged": true
},
"sampling": {}
},
"clientInfo": {
"name": "claude-code",
"version": "1.0.0"
}
}
}
Server 返回的初始化响应:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {
"listChanged": true
},
"resources": {
"subscribe": true,
"listChanged": true
},
"prompts": {
"listChanged": false
},
"logging": {}
},
"serverInfo": {
"name": "my-filesystem-server",
"version": "2.1.0"
}
}
}
34.6 工具能力(Tools)详解
34.6.1 工具列表查询
Client 通过 tools/list 方法获取 Server 提供的所有工具:
// 请求
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}
// 响应
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "read_file",
"description": "读取指定路径的文件内容",
"inputSchema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "文件的绝对或相对路径"
},
"encoding": {
"type": "string",
"enum": ["utf-8", "base64"],
"default": "utf-8",
"description": "文件编码格式"
}
},
"required": ["path"]
}
},
{
"name": "write_file",
"description": "将内容写入指定路径的文件",
"inputSchema": {
"type": "object",
"properties": {
"path": {"type": "string"},
"content": {"type": "string"},
"create_dirs": {
"type": "boolean",
"default": false,
"description": "是否自动创建不存在的父目录"
}
},
"required": ["path", "content"]
}
}
]
}
}
34.6.2 工具调用
// 调用请求
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "read_file",
"arguments": {
"path": "/Users/alice/notes.md",
"encoding": "utf-8"
}
}
}
// 成功响应
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "# 我的笔记\n\n今天学习了 MCP 协议..."
}
],
"isError": false
}
}
工具响应的 content 数组支持多种内容类型:
| 类型 | 用途 | 示例 |
|---|---|---|
text |
纯文本内容 | 文件内容、执行结果 |
image |
图像数据(base64) | 截图、图表 |
resource |
资源引用 | 嵌入的资源 URI |
34.7 资源能力(Resources)详解
Resources 是 MCP 中用于暴露数据的机制,类似于"虚拟文件系统"。每个 Resource 有一个 URI 标识符,Client 可以读取其内容。
34.7.1 资源列表查询
// 请求
{
"jsonrpc": "2.0",
"id": 4,
"method": "resources/list",
"params": {}
}
// 响应
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"resources": [
{
"uri": "file:///home/user/project/README.md",
"name": "项目 README",
"description": "项目说明文档",
"mimeType": "text/markdown"
},
{
"uri": "db://myapp/users/schema",
"name": "用户表结构",
"description": "users 表的完整 DDL",
"mimeType": "application/sql"
}
]
}
}
34.7.2 资源内容读取
// 请求
{
"jsonrpc": "2.0",
"id": 5,
"method": "resources/read",
"params": {
"uri": "file:///home/user/project/README.md"
}
}
// 响应
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"contents": [
{
"uri": "file:///home/user/project/README.md",
"mimeType": "text/markdown",
"text": "# 项目名称\n\n..."
}
]
}
}
34.7.3 资源订阅与变更通知
如果 Server 声明了 resources.subscribe 能力,Client 可以订阅资源变更:
// 订阅请求
{
"jsonrpc": "2.0",
"id": 6,
"method": "resources/subscribe",
"params": {
"uri": "file:///home/user/project/config.json"
}
}
// Server 主动推送的变更通知
{
"jsonrpc": "2.0",
"method": "notifications/resources/updated",
"params": {
"uri": "file:///home/user/project/config.json"
}
}
34.8 提示能力(Prompts)详解
Prompts 是 Server 预定义的提示模板,允许用户在 Host 中直接选择并使用。这是 MCP 中一个容易被忽略但非常实用的能力。
34.8.1 提示列表
// 响应示例
{
"result": {
"prompts": [
{
"name": "code_review",
"description": "对选中的代码进行全面的代码审查",
"arguments": [
{
"name": "code",
"description": "需要审查的代码",
"required": true
},
{
"name": "language",
"description": "编程语言",
"required": false
}
]
}
]
}
}
34.8.2 获取提示内容
// 请求
{
"jsonrpc": "2.0",
"id": 7,
"method": "prompts/get",
"params": {
"name": "code_review",
"arguments": {
"code": "def fibonacci(n):\n if n <= 1: return n\n return fibonacci(n-1) + fibonacci(n-2)",
"language": "Python"
}
}
}
// 响应:返回完整的消息列表
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"description": "Python 代码审查",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "请对以下 Python 代码进行全面的代码审查,关注性能、可读性和潜在 bug:\n\n```python\ndef fibonacci(n):\n if n <= 1: return n\n return fibonacci(n-1) + fibonacci(n-2)\n```"
}
}
]
}
}
34.9 Sampling(采样):Server 调用 LLM
Sampling 是 MCP 中最高级的能力,它允许 MCP Server 请求 Host 去调用 LLM。这实现了一种反向调用——原本是 Client 调 Server,现在 Server 也可以反向发起 LLM 推理请求。
// Server 发送的 sampling/createMessage 请求
{
"jsonrpc": "2.0",
"id": 10,
"method": "sampling/createMessage",
"params": {
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "请总结这段日志中的错误模式:ERROR: connection timeout..."
}
}
],
"modelPreferences": {
"hints": [{"name": "claude-sonnet-4-5"}],
"intelligencePriority": 0.8,
"speedPriority": 0.5
},
"maxTokens": 500
}
}
Sampling 的典型应用场景:一个文件系统 Server 在发现代码错误时,可以请求 Host 的 LLM 生成修复建议,然后作为工具调用结果的一部分返回给用户。
34.10 协议版本与向后兼容
MCP 协议使用日期版本号(如 2024-11-05)进行版本管理。当前稳定版本为 2024-11-05,2025年3月发布了包含 Streamable HTTP 支持的更新规范。
版本协商规则:
- Client 在
initialize请求中声明支持的最高协议版本 - Server 在响应中返回其使用的协议版本(不高于 Client 声明的版本)
- 如果版本不兼容,连接失败
实现 MCP Server 或 Client 时,建议使用官方 SDK 而非手动实现协议,以获得自动版本协商和未来兼容性保障。
小结
MCP 协议通过清晰的三层架构(Host/Client/Server)和两种传输层(stdio/HTTP+SSE),为 AI 工具生态提供了一个统一的标准接口。其核心设计理念——关注点分离、能力声明与协议中立性——使得工具开发者只需实现一次,即可在所有支持 MCP 的 AI 应用中使用。
关键要点:
- stdio 适合本地工具,HTTP+SSE 适合远程服务
- 初始化握手时双方声明各自的能力集合
- Tools(工具)、Resources(资源)、Prompts(提示)三种核心能力
- JSON-RPC 2.0 是协议的消息基础
- Sampling 允许 Server 反向请求 LLM 推理
下一章将进入实战,完整地构建一个自定义 MCP Server。