MCP 协议流与会话治理机制¶
模型上下文协议(MCP, Model Context Protocol)是连接大模型大脑与本地/外部系统的标准化桥梁。在工业级智能体落地中,理解 MCP 不能停留在“工具调用”层面,而必须将其视为三层网络拓扑下的标准 RPC 治理框架:宿主应用(Host Runtime)、MCP 客户端(MCP Client)与 MCP 服务端(MCP Server)。
1. 三层拓扑架构与边界划分¶
模型本身不具备直接连接操作系统的物理能力,它仅扮演意图生成器。一切副作用的执行与数据流转均受控于 Host 运行时的隔离层:
+------------------------------------------------------------------------+
| 宿主应用运行时 (Host Runtime - 审计安全、会话隔离、人工确认拦截器) |
| |
| +------------------------------------+ |
| | 智能体决策层 (Agent Loop / LLM) | |
| +-----------------+------------------+ |
| | 生成工具调用意图 |
| v |
| +-----------------+------------------+ |
| | MCP 客户端 (MCP Client) | |
| +-----------------+------------------+ |
| | 建立 transport (JSON-RPC 2.0 over stdio / |
| | Streamable HTTP) |
| v |
+---------------------+--------------------------------------------------+
|
| 跨物理/进程边界
v
+---------------------+--------------------------------------------------+
| MCP 服务端运行时 (MCP Server - 沙箱进程 / 网络隔离 / 本地工具集) |
| |
| +-----------------+------------------+ |
| | 工具执行器 (Tools / Resources) | |
| +------------------------------------+ |
+------------------------------------------------------------------------+
- Host Runtime:宿主应用的本地运行时,MCP 只是它众多工具来源之一。
- MCP Client(协议适配层):负责底层 Transport(进程 stdio 管道或 Streamable HTTP)生命周期管理、协议序列化/反序列化、能力发现交互及错误标准化。这是本文关注的核心。MCP 官方传输方式经历过一次演进:2024-11 版规范使用的是 HTTP+SSE,自 2025-03 版起已被 Streamable HTTP 取代;WebSocket 从来都不是 MCP 官方传输方式。
- MCP Server(执行面):暴露具体的 Tools、Resources 或 Prompts 规范,提供无状态执行原子。
MCP 工具被发现之后如何并入宿主运行时统一的工具池、如何参与模型可见性裁剪、如何走同一套权限与审批流程,属于运行时集成问题,不是协议问题,详见 claude-code-source/07-tools-skills-mcp.md 与 codex-agent-source/07-tools-skills.md。本文只讲 Client 与 Server 之间协议层的握手、传输和故障排查。
2. 标准会话生命周期与 JSON-RPC 2.0 Payload¶
MCP 协议完全基于 JSON-RPC 2.0 规范建立。客户端与服务端的初始化、能力协商及调用序列如下:
2.1 初始化握手时序 (Handshake Sequence)¶
2.2 核心协议 Payload 详解¶
① 初始化请求 (initialize Request)¶
客户端向服务端宣告其所支持的协议版本与自身能力声明(下面示例中的 protocolVersion: "2024-11-05" 是 2024-11 版协议的取值,仅用于展示报文结构;后续版本的字段结构基本沿用,但协议版本号与传输层已经演进,不代表当前最新版本):
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": { "listChanged": true },
"sampling": {}
},
"clientInfo": {
"name": "AntigravityHost",
"version": "1.2.0"
}
}
}
② 初始化响应 (initialize Response)¶
服务端返回其协议兼容版本,并输出其能够提供的核心能力列表(如是否具备 Prompts 模板、Resources 静态数据源或 Tools 执行器):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": { "listChanged": true },
"resources": { "subscribe": true }
},
"serverInfo": {
"name": "LocalFilesystemServer",
"version": "0.9.4"
}
}
}
③ 工具执行请求 (tools/call Request)¶
当智能体决策需要执行动作时,Client 向 Server 发起具体调用:
{
"jsonrpc": "2.0",
"id": 42,
"method": "tools/call",
"params": {
"name": "read_secure_file",
"arguments": {
"path": "/workspace/config.json"
}
}
}
④ 工具执行响应 (tools/call Response)¶
Server 返回执行结果封装,需指出返回内容类型及是否存在逻辑错误(isError):
{
"jsonrpc": "2.0",
"id": 42,
"result": {
"content": [
{
"type": "text",
"text": "{\"port\": 8080, \"db\": \"postgresql\"}"
}
],
"isError": false
}
}
3. 协议层与运行时权限层的边界¶
MCP 协议本身只定义 tools/list 怎么返回能力清单、tools/call 怎么携带参数和返回结果、isError 怎么标记失败——它不定义谁能看到哪些工具、谁的调用需要人工确认。这些是宿主运行时(Host Runtime)的职责,不是协议规范的一部分,完整设计见 claude-code-source/08-permissions-safety.md 与 codex-agent-source/08-permissions-safety.md(工具白名单裁剪、Schema 校验、Human-in-the-Loop 审批的通用机制都在这两章展开,对 MCP 工具和内置工具一视同仁)。
协议层能提供、也应该提供的只有两件事:一是 initialize 握手中的 capabilities 字段,让 Host 在建立连接阶段就知道 Server 支持哪些能力面(tools/resources/prompts),从而决定是否需要针对该 Server 启用额外的运行时管控;二是 tools/call 返回结构里的 isError,保证执行失败以协议约定的方式传回,而不是让 Host 靠猜测解析自由格式的错误文本。
4. 故障演进与排查诊断树¶
| 故障阶段 | 现象与错误描述 | 根因定位 | 排查与修复手段 |
|---|---|---|---|
| Transport 阶段 | broken pipe 或 EOF |
Server 进程崩溃,或标准输出被第三方日志打印污染破坏了 JSON 帧 | 1. 拦截 Server 的 stderr 写入独立日志文件,严禁污染 stdout。2. 检查 Server 的启动路径与环境变量。 |
| 握手协商阶段 | Unsupported protocol version |
客户端与服务端的主版本号不兼容 | 检查两端依赖的 MCP SDK 版本,强制在配置项中回退或升级。 |
| 工具发现阶段 | 模型找不到指定工具 | 能力变更通知丢失,或动态白名单裁剪过滤逻辑存在 Bug | 调用 tools/list 打印原始 JSON 响应,核对白名单过滤器函数(Filter Callback)执行状态。 |
| 执行阶段 | 频繁触发 isError: true |
目标文件不存在、无访问权限或下游网络超时 | 1. Host 侧增加超时机制限制(建议单次调用 \(< 10\text{s}\))。 2. 对返回的堆栈轨迹执行脱敏,防止向模型泄露内部机密目录结构。 |
5. 小结:协议层 vs 运行时层怎么分工¶
回答“MCP 是怎么保证安全的”这类问题时,最容易踩的坑是把协议层和运行时层的职责混在一起讲。分开讲会更站得住脚:
| 层次 | 负责什么 | 不负责什么 |
|---|---|---|
| MCP 协议(本文重点) | JSON-RPC 2.0 握手、能力声明与协商、工具调用的请求/响应格式、isError 错误标记、Transport 生命周期 |
谁能看到哪些工具、要不要人工确认、参数里的 Shell 元字符怎么处理 |
| 宿主运行时(详见 07/08 章) | 工具可见性裁剪、Schema 参数校验、权限规则、Human-in-the-Loop 审批、沙箱 | 协议帧怎么序列化、Transport 怎么建立连接 |
大模型不直接连接 MCP Server——它只输出工具调用意图,真正的连接、鉴权和执行都在 Host 的运行时里完成。协议层的价值是把“意图之后发生了什么”标准化成可预测的请求/响应格式,让运行时层可以在这之上叠加权限、审批和沙箱,而不用为每个外部工具重新发明一套通信约定。回答这类问题时,先说清楚“协议解决的是互操作性,运行时解决的是安全性”,再展开具体机制,会比直接堆机制名词更有说服力。