MCP 架构图解:三参与者、双层、原语

MCP 官方架构文档把协议拆成三件事:谁在连(Host / Client / Server)、怎么连(Data / Transport 两层)、连了能交换什么(原语)。这篇用图把这三件事一次讲透——是所有 MCP 衍生话题(无状态核心、Code Mode、vs CLI)的基础层。

Model Context Protocol 定位:协议只管 context 交换,不管 AI 应用如何用 LLM

一、三个参与者:1 个 Host 管 N 个 Client

MCP 是 client-server 架构,但「server」这个词最唬人——它不等于「远程服务器」,而是「提供上下文的程序」,本地远程都算。真正的配对关系是 Host : Client = 1 : NClient : Server = 1 : 1

MCP Host(AI 应用) VS Code · Claude Code · Claude Desktop MCP Client 1 MCP Client 2 MCP Client 3 MCP Client 4 1 Host : N Clients(Host 为每个 server new 一个 client) Server A · Filesystem(本地) STDIO · 服务单一 client Server B · Database(本地) STDIO · 零网络开销 Server C · Sentry(远程) Streamable HTTP · 服务多 client 1 : 1 dedicated 连接是 1:1 专用,但 server 在哪无所谓
VS Code 作 Host:连 Sentry(remote)时实例化 client 1,连 filesystem(local)时再实例化 client 2——每接一个 server 就 new 一个 client。
最易踩的坑

「MCP server」指提供上下文的程序,与它跑在哪无关。本地 server(STDIO)和远程 server(Streamable HTTP)都叫 server。区分本地/远程的是传输,不是「server」这个词。

二、两层架构:内层数据,外层传输

MCP 概念上分内外两层。关键价值:同一套 JSON-RPC 2.0 消息可以跑在任意传输上——换传输不换协议,这就是 STDIO 和 HTTP 能共存的原因。

Transport Layer(外层) 通信通道 · 认证 · 连接建立 · 消息成帧 · 安全通信 Data Layer(内层) JSON-RPC 2.0 · 原语 · 能力/版本协商 tools / resources / prompts / notifications server/discover · subscriptions/listen STDIO(本地) 同一套消息 → Streamable HTTP(远程) 传输层把通信细节从协议层抽象掉
内层定义「说什么」,外层定义「怎么传」。传输可插拔,是 STDIO(零网络、最高性能)和 HTTP(可远程、可认证)共存的设计前提。

三、原语:动词、名词、模板(最核心)

原语(primitive)定义 client 和 server 能互相提供什么——这是开发者最该理解的部分。Server 暴露三类,Client 也暴露三类(其中两个 2026-07-28 起已弃用)。

Server 暴露 → → Client 暴露 Tools(动词 · 动作) 可执行函数,LLM 调用 文件操作 · API 调用 · 数据库查询 Resources(名词 · 数据) 提供上下文/数据源 文件内容 · DB 记录 · schema · API 响应 Prompts(模板 · 结构) 可复用交互模板 system prompt · few-shot 示例 Elicitation ✅ 活跃 server 反向向用户要输入/确认 「这次操作会删数据,确认?」· 经 MRTR Sampling ❌ 已弃用 server 请求 client 侧的 LLM 补全 新实现应直接对接 LLM provider API Logging ❌ 已弃用 server 发日志给 client 改用 stderr(stdio)或 OpenTelemetry tools/list · tools/call elicitation/create
动词 / 名词 / 模板是理解 MCP 的钥匙:Tools 做事、Resources 给料、Prompts 定型。一个 DB server 可同时暴露查询工具(动词)+ schema 资源(名词)+ few-shot 模板(结构),三者互补。右侧两个弃用项是 2026-07-28 的协议瘦身——砍掉「server 反向用 client 的 LLM」这类耦合。

四、无状态:每个请求自带一切

2026-07-28 规范把 MCP 定为无状态协议。落地形态:每个请求在 _meta 里自带协议版本、client 身份、client 能力——server 无需依赖连接状态。想预知 server 能力可发可选的 server/discover(响应可缓存),但不发也行

POST /mcp(一个请求) MCP-Protocol-Version: 2026-07-28 Mcp-Method: tools/call · Mcp-Name: search body.params._meta = io.modelcontextprotocol/protocolVersion io.modelcontextprotocol/clientInfo io.modelcontextprotocol/clientCapabilities 版本 · 身份 · 能力——全在这,不靠连接状态 后果 任意实例 可服务任意请求 无需 sticky session 无需共享存储 → 可上 serverless / edge server/discover 可选(响应带 ttlMs 可缓存);不发 discover 直接发请求,版本不匹配 server 报错 client 重试即可
自描述请求是无状态化的落地——这也是 MCP server 能跑在 serverless/edge 上的根本原因。机制拆解(废除 initialize / Mcp-Session-Id、MRTR、header 路由)见「为什么改成无状态」篇。

五、一次完整交互:4 步时序

把上面所有部件串起来,一次 client-server 对话长这样。注意第 4 步的通知是 opt-in 的独立长连接流——它绑架不了主请求路径。

Client Server 1 server/discover(可选 · 响应可缓存) 拿回 server 支持的版本 + 能力 + 身份 2 tools/list → 工具数组 每个工具含 name / title / description / inputSchema 3 tools/call(name + arguments) ← content[](text / image / resource 多格式) 4 subscriptions/listen(opt-in 开流) acknowledged → 之后推 notifications/tools/list_changed(best-effort) client 收到后重新 tools/list 刷新工具目录
第 4 步是关键:通知流是「可选附加能力」,独立于前 3 步的主请求路径。client 收到变更通知后会重新拉工具列表,刷新 LLM 可见的能力。
架构没坑,使用习惯有坑

规范的 tools/listtools/call 流程在实战中有个著名陷阱:会话一开始就把所有 server 的工具 schema 预载进上下文——Playwright MCP 13.7K tokens、5-server 配置 55K tokens,没干活先烧半个上下文窗口。这不是协议要求(规范支持渐进式发现),而是一种使用习惯。解法是 Code Mode:让模型写代码调工具,而非把工具塞进上下文。

六、MCP 知识的三层分工

把这次讲的内容和 KB 里其它 MCP 页面摆到一起,三层各司其职:

问题页面
基础层(本页)MCP 是什么、由什么部件拼起来?三参与者 / 双层 / 原语 / 4 步交互
演进层2026-07-28 为何把核心改成无状态?无状态核心(MRTR / header 路由 / 显式 handle)
实践层怎么用才不爆上下文?MCP 还是 CLI?Code Mode · MCP vs CLI vs Code Mode

三层合起来:先懂结构(本页),再懂演进(为何无状态化),最后懂实战(如何不被上下文成本反噬)。