一、三个参与者:1 个 Host 管 N 个 Client
MCP 是 client-server 架构,但「server」这个词最唬人——它不等于「远程服务器」,而是「提供上下文的程序」,本地远程都算。真正的配对关系是 Host : Client = 1 : N,Client : Server = 1 : 1。
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 能共存的原因。
内层定义「说什么」,外层定义「怎么传」。传输可插拔,是 STDIO(零网络、最高性能)和 HTTP(可远程、可认证)共存的设计前提。
三、原语:动词、名词、模板(最核心)
原语(primitive)定义 client 和 server 能互相提供什么——这是开发者最该理解的部分。Server 暴露三类,Client 也暴露三类(其中两个 2026-07-28 起已弃用)。
动词 / 名词 / 模板是理解 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(响应可缓存),但不发也行。
自描述请求是无状态化的落地——这也是 MCP server 能跑在 serverless/edge 上的根本原因。机制拆解(废除 initialize / Mcp-Session-Id、MRTR、header 路由)见「为什么改成无状态」篇。
五、一次完整交互:4 步时序
把上面所有部件串起来,一次 client-server 对话长这样。注意第 4 步的通知是 opt-in 的独立长连接流——它绑架不了主请求路径。
第 4 步是关键:通知流是「可选附加能力」,独立于前 3 步的主请求路径。client 收到变更通知后会重新拉工具列表,刷新 LLM 可见的能力。
架构没坑,使用习惯有坑
规范的 tools/list → tools/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 |
三层合起来:先懂结构(本页),再懂演进(为何无状态化),最后懂实战(如何不被上下文成本反噬)。