Skip to Content

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)轻量级、专注单一职责;不直接访问 LLMGitHub MCP Server、PostgreSQL MCP Server

1.2 通信方向与消息流

MCP 的通信是双向的——不仅 Client 可以向 Server 发请求,Server 也可以向 Client 发请求(如 Sampling 采样请求)。

关键设计原则

  1. 1:1 会话隔离:每个 Client-Server 对维持独立会话,一个 Server 的故障不会影响其他连接
  2. 能力按需协商:Client 和 Server 在初始化时声明各自支持的能力,只使用双方都支持的功能
  3. Server 无状态感知 LLM:Server 不知道也不需要知道 Host 使用的是哪个 LLM 模型
  4. 安全边界清晰: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 + /messages1 个(如 /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-ef1234567890

3. 可恢复流(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 必须是字符串或整数,不得null
  • id 在同一会话中不得重复使用
  • 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" } } }

标准错误码

错误码含义说明
-32700Parse errorJSON 解析失败
-32600Invalid Request不是有效的 JSON-RPC 请求
-32601Method not found方法不存在
-32602Invalid params参数无效
-32603Internal error服务器内部错误

3.4 Notification(通知)

通知是单向消息,接收方不得返回响应。

{ "jsonrpc": "2.0", "method": "notifications/initialized" }
{ "jsonrpc": "2.0", "method": "notifications/tools/list_changed" }

规则

  • 通知不得包含 id 字段
  • 接收方不得发送响应
  • 常用于状态变更通知(如工具列表变化、进度更新)

3.5 MCP 核心方法一览

方向方法类型说明
Client → ServerinitializeRequest初始化连接,协商能力
Client → Servernotifications/initializedNotification确认初始化完成
Client → Servertools/listRequest列出可用工具
Client → Servertools/callRequest调用指定工具
Client → Serverresources/listRequest列出可用资源
Client → Serverresources/readRequest读取指定资源
Client → Serverresources/subscribeRequest订阅资源变更
Client → Serverprompts/listRequest列出提示词模板
Client → Serverprompts/getRequest获取指定模板
Client → Servercompletion/completeRequest请求参数自动补全
Client → ServerpingRequest心跳检测
Client → Servernotifications/cancelledNotification取消正在执行的请求
Client → Servernotifications/roots/list_changedNotification根目录列表变更
Server → Clientsampling/createMessageRequest请求 LLM 生成内容
Server → Clientelicitation/createRequest向用户征询信息
Server → Clientnotifications/tools/list_changedNotification工具列表变更
Server → Clientnotifications/resources/list_changedNotification资源列表变更
Server → Clientnotifications/resources/updatedNotification资源内容更新
Server → Clientnotifications/prompts/list_changedNotification模板列表变更
Server → Clientnotifications/progressNotification操作进度更新
Server → Clientlogging/messageNotification日志消息

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 使用兼容的协议版本:

  1. Client 在 initialize 请求中发送它支持的协议版本(应为最新版本)
  2. 如果 Server 支持该版本,返回相同版本号
  3. 如果 Server 不支持,返回它支持的最新版本
  4. 如果 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 你可以:

  1. 验证能力协商:确认 Server 声明了预期的能力
  2. 检查消息格式:确保 JSON-RPC 消息符合规范
  3. 排查连接问题:观察初始化阶段是否有错误响应
  4. 测试工具调用:手动发送 tools/call 请求,验证 Server 行为

避坑指南

❌ 常见错误

  1. 在 stdout 中混入非 MCP 消息

    • 问题:Server 在 stdout 中输出日志或调试信息,导致 Client 解析失败
    • 正确做法:日志输出到 stderr,stdout 仅限 JSON-RPC 消息
  2. 跳过 initialized 通知直接发请求

    • 问题:Server 可能拒绝未完成初始化的请求
    • 正确做法:严格遵循 initializeinitialized → 正常操作的顺序
  3. 仍在使用已废弃的 HTTP+SSE 传输

    • 问题:HTTP+SSE 双端点方案已在 2025-03-26 版本废弃
    • 正确做法:新项目使用 Streamable HTTP;需要向后兼容时实现双模式降级
  4. 忽略 MCP-Session-Id 头部

    • 问题:Streamable HTTP 模式下,缺少会话 ID 会导致 Server 返回 400 错误
    • 正确做法:初始化后保存 MCP-Session-Id,后续所有请求都携带
  5. 在 Notification 中包含 id 字段

    • 问题:违反 JSON-RPC 2.0 规范,通知不应有 id
    • 正确做法:通知消息只包含 jsonrpcmethod 和可选的 params
  6. 未验证 Origin 头部(Streamable HTTP)

    • 问题:容易遭受 DNS 重绑定攻击
    • 正确做法:Server 必须验证 Origin 头部,本地运行绑定 127.0.0.1

✅ 最佳实践

  1. 开发阶段优先使用 stdio 传输——零网络配置,最简单的调试体验
  2. 使用 MCP Inspector 观察完整的消息流,理解协议交互细节
  3. 实现超时机制——为所有请求设置超时,防止挂起连接和资源耗尽
  4. 利用 listChanged 能力——当工具/资源列表动态变化时,通过通知让 Client 及时刷新
  5. 生产环境务必实现会话管理和 OAuth 2.1 认证
  6. 使用官方 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 连接选项技术深度解析 技术博客不同传输方式的对比和选择指南

参考来源


📖 返回 总览与导航 | 上一节:08a-MCP概念入门 | 下一节:08c-自定义MCP-Server开发

Last updated on