08b - MCP 深度架构解析
本文是《AI Agent 实战手册》第 8 章第 2 节。 上一节:08a-MCP概念入门 | 下一节:08c-自定义MCP-Server开发
概述
上一节介绍了 MCP 的核心概念和”USB 接口”类比。本节将深入协议内部,逐层拆解 MCP 的架构设计:从客户端-服务器通信模型,到传输层的演进(stdio → HTTP+SSE → Streamable HTTP),再到 JSON-RPC 2.0 消息格式和能力协商机制。理解这些底层细节,是你构建自定义 MCP Server、排查连接问题、以及做出正确架构决策的基础。
1. 客户端-服务器通信模型
1.1 三层角色深度解析
MCP 的通信模型由三个角色构成:Host、Client、Server。它们之间的关系不是简单的”请求-响应”,而是一个精心设计的分层架构。
角色职责详解
| 角色 | 核心职责 | 关键约束 | 实例 |
|---|---|---|---|
| Host | 管理 LLM 交互、维护 Client 连接池、执行安全策略 | 一个 Host 可管理多个 Client;负责用户授权决策 | Claude Desktop、Cursor、Kiro、自定义 Agent 应用 |
| Client | 维护与单个 Server 的 1:1 有状态会话 | 每个 Client 实例只连接一个 Server;负责协议协商 | Host 内部自动管理,开发者通常不直接操作 |
| Server | 暴露工具(Tools)、资源(Resources)、提示词模板(Prompts) | 轻量级、专注单一职责;不直接访问 LLM | GitHub MCP Server、PostgreSQL MCP Server |
1.2 通信方向与消息流
MCP 的通信是双向的——不仅 Client 可以向 Server 发请求,Server 也可以向 Client 发请求(如 Sampling 采样请求)。
关键设计原则
- 1:1 会话隔离:每个 Client-Server 对维持独立会话,一个 Server 的故障不会影响其他连接
- 能力按需协商:Client 和 Server 在初始化时声明各自支持的能力,只使用双方都支持的功能
- Server 无状态感知 LLM:Server 不知道也不需要知道 Host 使用的是哪个 LLM 模型
- 安全边界清晰:Host 控制所有安全决策(如工具调用审批),Server 只负责执行
2. 传输层深度解析
MCP 协议是传输无关的——它定义的是消息格式和交互模式,不绑定特定的网络协议。当前规范定义了两种标准传输方式,并支持自定义传输。
2.1 传输层演进时间线
2.2 stdio 传输
适用场景:本地进程通信(最常用的开发模式)
stdio 是最简单的传输方式——Host 将 MCP Server 作为子进程启动,通过标准输入/输出通信。
stdio 技术规格
| 特性 | 说明 |
|---|---|
| 消息编码 | UTF-8 编码的 JSON-RPC 消息 |
| 消息分隔 | 换行符(\n),消息内部不得包含换行符 |
| stdout 用途 | 仅限有效的 MCP 消息,不得输出其他内容 |
| stderr 用途 | 日志输出(信息、调试、错误),Client 可选择捕获或忽略 |
| 进程管理 | Host 负责启动和终止 Server 子进程 |
| 网络需求 | 无(纯本地进程间通信) |
stdio 配置示例
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxxxxxx"
}
}
}
}2.3 Streamable HTTP 传输
适用场景:远程/云端通信、多客户端连接、生产环境部署
Streamable HTTP 是 2025-03-26 版本引入的新传输方式,取代了已废弃的 HTTP+SSE 双端点方案。它通过单一 HTTP 端点实现双向通信。
旧版 HTTP+SSE vs 新版 Streamable HTTP
| 对比维度 | HTTP+SSE(已废弃) | Streamable HTTP |
|---|---|---|
| 端点数量 | 2 个(/sse + /messages) | 1 个(如 /mcp) |
| 连接模型 | 持久 SSE 连接 + 独立 POST | 按需升级:普通 HTTP 或 SSE 流 |
| 双向通信 | 需要两个通道协调 | 单端点原生支持 |
| 会话管理 | 无标准化方案 | MCP-Session-Id 头部 |
| 可恢复性 | 连接断开 = 数据丢失 | Last-Event-ID 支持断点续传 |
| 扩展性 | 长连接消耗资源 | 短连接 + 按需流式,更易扩展 |
| HTTP/2 兼容 | 部分兼容问题 | 完全兼容 |
Streamable HTTP 核心机制
1. 动态响应模式
Server 根据操作复杂度自动选择响应方式:
- 简单操作:返回
Content-Type: application/json,标准 HTTP 响应 - 长时间操作:返回
Content-Type: text/event-stream,SSE 流式响应 - 通知/响应消息:返回
202 Accepted,无响应体
2. 会话管理
# 初始化时,Server 返回会话 ID
HTTP/1.1 200 OK
MCP-Session-Id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
# 后续请求必须携带会话 ID
POST /mcp HTTP/1.1
MCP-Session-Id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
MCP-Protocol-Version: 2025-11-25
# 终止会话
DELETE /mcp HTTP/1.1
MCP-Session-Id: a1b2c3d4-e5f6-7890-abcd-ef12345678903. 可恢复流(Resumability)
当连接意外断开时,Client 可以通过 Last-Event-ID 头部恢复:
# Server 在 SSE 事件中附带 ID
data: {"jsonrpc":"2.0","id":3,"result":{...}}
id: stream-abc-evt-42
# Client 断线重连时
GET /mcp HTTP/1.1
Last-Event-ID: stream-abc-evt-42⚠️ 安全提示:Streamable HTTP Server 必须验证
Origin头部以防止 DNS 重绑定攻击。本地运行时应绑定127.0.0.1而非0.0.0.0。
2.4 传输方式选择决策树
工具推荐
| 工具 | 用途 | 价格 | 适用场景 |
|---|---|---|---|
| MCP Inspector | 交互式调试 MCP Server | 免费开源 | 开发调试、传输层排查 |
| mcp-remote | 将远程 Streamable HTTP Server 桥接为本地 stdio | 免费开源 | 在仅支持 stdio 的 Host 中使用远程 Server |
| MCP TypeScript SDK | 官方 TS SDK,内置两种传输 | 免费开源 | TypeScript/Node.js Server 开发 |
| MCP Python SDK | 官方 Python SDK | 免费开源 | Python Server 开发 |
| Postman | HTTP 请求调试 | 免费 / Pro $14/月 | 手动测试 Streamable HTTP 端点 |
3. JSON-RPC 2.0 消息格式
MCP 的所有通信都基于 JSON-RPC 2.0 规范。理解消息格式是调试 MCP 连接问题的关键。
3.1 三种消息类型
3.2 Request(请求)
请求由 Client 或 Server 发起,用于启动一个操作。接收方必须返回 Response。
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "query_database",
"arguments": {
"sql": "SELECT * FROM users LIMIT 10"
}
}
}规则:
id必须是字符串或整数,不得为nullid在同一会话中不得重复使用method指定要调用的操作params是可选的参数对象
3.3 Response(响应)
成功响应
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "查询返回 10 条用户记录..."
}
]
}
}错误响应
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Invalid params: SQL query is required",
"data": {
"field": "sql",
"reason": "missing required parameter"
}
}
}标准错误码:
| 错误码 | 含义 | 说明 |
|---|---|---|
-32700 | Parse error | JSON 解析失败 |
-32600 | Invalid Request | 不是有效的 JSON-RPC 请求 |
-32601 | Method not found | 方法不存在 |
-32602 | Invalid params | 参数无效 |
-32603 | Internal error | 服务器内部错误 |
3.4 Notification(通知)
通知是单向消息,接收方不得返回响应。
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}{
"jsonrpc": "2.0",
"method": "notifications/tools/list_changed"
}规则:
- 通知不得包含
id字段 - 接收方不得发送响应
- 常用于状态变更通知(如工具列表变化、进度更新)
3.5 MCP 核心方法一览
| 方向 | 方法 | 类型 | 说明 |
|---|---|---|---|
| Client → Server | initialize | Request | 初始化连接,协商能力 |
| Client → Server | notifications/initialized | Notification | 确认初始化完成 |
| Client → Server | tools/list | Request | 列出可用工具 |
| Client → Server | tools/call | Request | 调用指定工具 |
| Client → Server | resources/list | Request | 列出可用资源 |
| Client → Server | resources/read | Request | 读取指定资源 |
| Client → Server | resources/subscribe | Request | 订阅资源变更 |
| Client → Server | prompts/list | Request | 列出提示词模板 |
| Client → Server | prompts/get | Request | 获取指定模板 |
| Client → Server | completion/complete | Request | 请求参数自动补全 |
| Client → Server | ping | Request | 心跳检测 |
| Client → Server | notifications/cancelled | Notification | 取消正在执行的请求 |
| Client → Server | notifications/roots/list_changed | Notification | 根目录列表变更 |
| Server → Client | sampling/createMessage | Request | 请求 LLM 生成内容 |
| Server → Client | elicitation/create | Request | 向用户征询信息 |
| Server → Client | notifications/tools/list_changed | Notification | 工具列表变更 |
| Server → Client | notifications/resources/list_changed | Notification | 资源列表变更 |
| Server → Client | notifications/resources/updated | Notification | 资源内容更新 |
| Server → Client | notifications/prompts/list_changed | Notification | 模板列表变更 |
| Server → Client | notifications/progress | Notification | 操作进度更新 |
| Server → Client | logging/message | Notification | 日志消息 |
4. 能力协商机制
能力协商是 MCP 最重要的设计之一——它确保 Client 和 Server 只使用双方都支持的功能,避免运行时错误。
4.1 协商流程
4.2 完整的初始化消息示例
Client → Server:initialize 请求
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {
"roots": {
"listChanged": true
},
"sampling": {},
"elicitation": {
"form": {},
"url": {}
}
},
"clientInfo": {
"name": "MyAIApp",
"title": "My AI Application",
"version": "2.0.0",
"description": "一个自定义的 AI 助手应用"
}
}
}Server → Client:initialize 响应
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-11-25",
"capabilities": {
"logging": {},
"prompts": {
"listChanged": true
},
"resources": {
"subscribe": true,
"listChanged": true
},
"tools": {
"listChanged": true
}
},
"serverInfo": {
"name": "DatabaseServer",
"title": "Database MCP Server",
"version": "1.5.0",
"description": "提供 PostgreSQL 数据库查询和管理能力"
},
"instructions": "本 Server 提供数据库查询工具,请确保 SQL 语句安全"
}
}Client → Server:initialized 通知
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}4.3 能力矩阵
Client 端能力
| 能力 | 说明 | 子能力 |
|---|---|---|
roots | 提供文件系统根目录信息 | listChanged:支持根目录变更通知 |
sampling | 支持 Server 请求 LLM 生成内容 | — |
elicitation | 支持 Server 向用户征询信息 | form:表单式交互;url:URL 式交互 |
experimental | 非标准实验性功能 | 自定义 |
Server 端能力
| 能力 | 说明 | 子能力 |
|---|---|---|
tools | 暴露可调用的工具 | listChanged:工具列表变更通知 |
resources | 提供可读取的资源 | subscribe:支持资源订阅;listChanged:资源列表变更通知 |
prompts | 提供提示词模板 | listChanged:模板列表变更通知 |
logging | 发送结构化日志消息 | — |
completions | 支持参数自动补全 | — |
experimental | 非标准实验性功能 | 自定义 |
4.4 版本协商
版本协商确保 Client 和 Server 使用兼容的协议版本:
- Client 在
initialize请求中发送它支持的协议版本(应为最新版本) - 如果 Server 支持该版本,返回相同版本号
- 如果 Server 不支持,返回它支持的最新版本
- 如果 Client 不支持 Server 返回的版本,应断开连接
// 版本不匹配时的错误响应
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Unsupported protocol version",
"data": {
"supported": ["2025-03-26", "2025-06-18"],
"requested": "2025-11-25"
}
}
}5. 完整生命周期实战
操作步骤:从连接到关闭的完整流程
以下是一个完整的 MCP 会话生命周期,展示了从初始化到工具调用再到关闭的全过程。
步骤 1:初始化连接
// Client → Server
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": { "roots": { "listChanged": true }, "sampling": {} },
"clientInfo": { "name": "DemoClient", "version": "1.0.0" }
}
}
// Server → Client
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-11-25",
"capabilities": { "tools": { "listChanged": true }, "logging": {} },
"serverInfo": { "name": "WeatherServer", "version": "1.0.0" }
}
}
// Client → Server
{ "jsonrpc": "2.0", "method": "notifications/initialized" }步骤 2:发现可用工具
// Client → Server
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }
// Server → Client
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "get_weather",
"description": "获取指定城市的当前天气信息",
"inputSchema": {
"type": "object",
"properties": {
"city": { "type": "string", "description": "城市名称" },
"unit": { "type": "string", "enum": ["celsius", "fahrenheit"], "default": "celsius" }
},
"required": ["city"]
}
}
]
}
}步骤 3:调用工具
// Client → Server
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": { "city": "北京", "unit": "celsius" }
}
}
// Server → Client(可选:进度通知)
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": {
"progressToken": 3,
"progress": 50,
"total": 100,
"message": "正在查询天气 API..."
}
}
// Server → Client(最终结果)
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "北京当前天气:晴,温度 28°C,湿度 45%,风速 12km/h"
}
]
}
}步骤 4:关闭连接
# stdio 方式
1. Client 关闭 Server 的 stdin
2. 等待 Server 退出
3. 如未退出,发送 SIGTERM
4. 如仍未退出,发送 SIGKILL
# Streamable HTTP 方式
DELETE /mcp HTTP/1.1
MCP-Session-Id: abc123
→ Server 返回 200 OK 或 405 Method Not Allowed实战案例:用 MCP Inspector 调试传输层
MCP Inspector 是官方提供的交互式调试工具,可以直观地查看 JSON-RPC 消息流。
操作步骤
步骤 1:安装并启动 Inspector
npx @modelcontextprotocol/inspector步骤 2:连接到 MCP Server
在 Inspector 界面中:
- 选择传输方式(stdio 或 Streamable HTTP)
- 对于 stdio:输入 Server 启动命令(如
npx -y @modelcontextprotocol/server-filesystem /tmp) - 对于 Streamable HTTP:输入 Server URL(如
http://localhost:3000/mcp)
步骤 3:观察消息流
Inspector 会实时显示所有 JSON-RPC 消息,包括:
initialize请求和响应(查看能力协商结果)tools/list返回的工具定义tools/call的参数和返回值- 所有通知消息
案例分析
通过 Inspector 你可以:
- 验证能力协商:确认 Server 声明了预期的能力
- 检查消息格式:确保 JSON-RPC 消息符合规范
- 排查连接问题:观察初始化阶段是否有错误响应
- 测试工具调用:手动发送
tools/call请求,验证 Server 行为
避坑指南
❌ 常见错误
-
在 stdout 中混入非 MCP 消息
- 问题:Server 在 stdout 中输出日志或调试信息,导致 Client 解析失败
- 正确做法:日志输出到 stderr,stdout 仅限 JSON-RPC 消息
-
跳过
initialized通知直接发请求- 问题:Server 可能拒绝未完成初始化的请求
- 正确做法:严格遵循
initialize→initialized→ 正常操作的顺序
-
仍在使用已废弃的 HTTP+SSE 传输
- 问题:HTTP+SSE 双端点方案已在 2025-03-26 版本废弃
- 正确做法:新项目使用 Streamable HTTP;需要向后兼容时实现双模式降级
-
忽略
MCP-Session-Id头部- 问题:Streamable HTTP 模式下,缺少会话 ID 会导致 Server 返回 400 错误
- 正确做法:初始化后保存
MCP-Session-Id,后续所有请求都携带
-
在 Notification 中包含
id字段- 问题:违反 JSON-RPC 2.0 规范,通知不应有
id - 正确做法:通知消息只包含
jsonrpc、method和可选的params
- 问题:违反 JSON-RPC 2.0 规范,通知不应有
-
未验证 Origin 头部(Streamable HTTP)
- 问题:容易遭受 DNS 重绑定攻击
- 正确做法:Server 必须验证
Origin头部,本地运行绑定127.0.0.1
✅ 最佳实践
- 开发阶段优先使用 stdio 传输——零网络配置,最简单的调试体验
- 使用 MCP Inspector 观察完整的消息流,理解协议交互细节
- 实现超时机制——为所有请求设置超时,防止挂起连接和资源耗尽
- 利用
listChanged能力——当工具/资源列表动态变化时,通过通知让 Client 及时刷新 - 生产环境务必实现会话管理和 OAuth 2.1 认证
- 使用官方 SDK(TypeScript 或 Python)而非手动实现协议——SDK 已处理了大量边界情况
提示词模板
调试 MCP 连接问题
我的 MCP Server 连接出现问题。请帮我排查:
环境信息:
- Host 应用:[Claude Desktop / Cursor / Kiro / 自定义]
- 传输方式:[stdio / Streamable HTTP]
- Server 类型:[官方 Server / 自定义 Server]
- 错误现象:[具体错误信息]
请按以下步骤排查:
1. 检查 initialize 阶段是否成功
2. 检查能力协商结果
3. 检查传输层配置
4. 检查消息格式是否符合 JSON-RPC 2.0分析 MCP 消息日志
以下是我的 MCP Server 的 JSON-RPC 消息日志。请分析:
1. 能力协商是否正确
2. 是否有异常的错误响应
3. 消息顺序是否符合协议规范
4. 是否有性能瓶颈(如超时、重试)
消息日志:
[粘贴 JSON-RPC 消息]相关资源与延伸阅读
| 资源 | 类型 | 说明 |
|---|---|---|
| MCP 官方规范 - 基础协议 | 协议规范 | JSON-RPC 消息格式、Schema 验证的权威定义 |
| MCP 官方规范 - 传输层 | 协议规范 | stdio 和 Streamable HTTP 传输的完整规范 |
| MCP 官方规范 - 生命周期 | 协议规范 | 初始化、能力协商、关闭的完整流程定义 |
| MCP Inspector | 调试工具 | 官方交互式 MCP Server 调试工具 |
| Why MCP Deprecated SSE | 技术博客 | 深入分析 SSE 废弃原因和 Streamable HTTP 优势 |
| MCP JSON-RPC 完整参考 | 教程 | 所有 JSON-RPC 消息类型的详细参考 |
| MCP 协议规范深度解析 | 技术博客 | 从 JSON-RPC 层面深入分析 MCP 协议 |
| How MCP Works - 消息类型 | 交互式教程 | 可视化理解 MCP 消息类型和交互流程 |
| Streamable HTTP MCP 标准 | 教程 | Streamable HTTP 传输的详细技术解析 |
| MCP 连接选项技术深度解析 | 技术博客 | 不同传输方式的对比和选择指南 |
参考来源
- MCP 官方规范 2025-11-25 - 基础协议 (2025-11-25)
- MCP 官方规范 2025-11-25 - 传输层 (2025-11-25)
- MCP 官方规范 2025-11-25 - 生命周期 (2025-11-25)
- MCP 官方规范 2025-03-26 (2025-03-26)
- Why MCP Deprecated SSE and Went with Streamable HTTP - fka.dev (2025-06)
- MCP Protocol Specification Deep Dive - Grizzly Peak Software (2026-02)
- Complete MCP JSON-RPC Reference Guide - Portkey (2026-01)
- Developer’s Guide to the Model Context Protocol 2026 - NerdLevelTech (2026-02)
- Understanding MCP Connection Options - Harry Laou (2025-09)
- Streamable HTTP: The MCP Standard - Panaversity (2026-02)
📖 返回 总览与导航 | 上一节:08a-MCP概念入门 | 下一节:08c-自定义MCP-Server开发