MCP 的架构是怎样的?Host、Client、Server 分别是什么?

进阶原理新技术约 8 分钟读完

一句话回答

MCP 是客户端-服务端架构。Host 是用户直接使用的 AI 应用(如 IDE、桌面 AI 客户端),负责调用模型、管理权限和用户确认;Host 为每个要连接的 Server 创建一个 Client,两者一对一通信;Server 对外提供工具、资源和提示模板。消息格式是 JSON-RPC 2.0,传输方式有本地的 stdio 和远程的 Streamable HTTP。双方要对齐协议版本和各自支持的能力:2025-11-25 及更早的版本靠连接时的 initialize 握手协商;2026-07-28 版规范取消了握手,每个请求自带协议版本和客户端能力,Server 的能力通过它必须实现的 server/discover 查询。

详细解析

三个角色

文本
Host(IDE、桌面 AI 客户端、自研 Agent)
 │ 管理对话、调用大模型、权限确认、汇总各 Server 的能力
 ├─ Client A ── stdio ─────────── Server:本地文件系统
 ├─ Client B ── stdio ─────────── Server:本地 Git
 └─ Client C ── Streamable HTTP ── Server:远程工单系统 → 工单系统 API
角色 职责
Host 创建和管理多个 Client,决定连接哪些 Server;执行安全策略,向用户请求授权和确认;把各 Server 的工具交给模型,再把模型发起的调用转给对应的 Server
Client Host 内部的协议组件,只和一个 Server 通信:收发消息,在请求里带上协议版本和能力信息,处理订阅和通知
Server 通过 Tools、Resources、Prompts 对外提供能力,可以是本地进程,也可以是远程服务

规范里有一条关键的设计原则:Server 看不到完整的对话,也看不到其他 Server。对话历史留在 Host,Server 只收到完成请求所需的信息,跨 Server 的协作由 Host 控制。这样来源不同、可信度不同的 Server 被互相隔离。另外,MCP 只规定上下文和能力怎么交换,不规定 AI 应用怎么使用大模型。基础概念见 MCP 是什么。

数据层和传输层

  • 数据层:基于 JSON-RPC 2.0,定义消息结构和语义。消息分三种:请求(带 id,要求响应)、响应(结果或错误)、通知(不带 id,不需要响应)。各种能力对应具体的方法,如 tools/list、tools/call
  • 传输层:负责建立连接、消息分帧和认证,同一套 JSON-RPC 消息可以跑在不同的传输方式上
stdio Streamable HTTP
运行位置 Host 把 Server 作为子进程启动,在同一台机器上 Server 独立运行,通常部署在远程
通信方式 通过标准输入输出收发,每行一条 JSON-RPC 消息 每条消息一个 HTTP POST;Server 返回一个 JSON,或者针对这个请求的 SSE 流
服务对象 通常只服务一个 Client 通常同时服务很多 Client
认证 凭证从环境变量等本地配置获取 支持标准的 HTTP 认证,推荐用 OAuth 获取令牌
典型场景 访问本地文件、本地开发工具 SaaS 服务、团队共享的工具

stdio 模式下 Server 的 stdout 只能输出协议消息,日志要写到 stderr,见 怎么开发一个 MCP Server。远程传输早期用的是 HTTP + SSE(两个端点加一条长连接),已被 Streamable HTTP 取代并标记为弃用。

版本和能力协商

双方要对齐两件事:用哪个协议版本;各自支持哪些能力,比如 Server 是否提供工具、工具列表变化时会不会通知,Client 是否支持向用户索取信息。

2025-11-25 及更早的版本:连接建立后先握手,握手完成前一般不发送其他请求。

文本
Client → Server  initialize(客户端支持的协议版本、clientInfo、客户端能力)
Server → Client  响应(选定的协议版本、serverInfo、服务端能力)
Client → Server  notifications/initialized
之后才开始 tools/list、tools/call 等正常请求

2026-07-28 版规范:取消了握手和协议层的会话,协议变成无状态的。

  • 每个请求在 _meta 里携带协议版本和客户端能力(Streamable HTTP 下还要在 MCP-Protocol-Version 请求头里带上同一个版本号),Server 独立处理每个请求,不依赖之前的请求
  • Server 必须实现 server/discover,Client 可以先调用它,一次拿到 Server 支持的版本、能力和身份信息
  • 版本不支持时,Server 返回 UnsupportedProtocolVersionError 并列出支持的版本,Client 换一个版本重试
  • 需要跨请求保存的状态(如购物车),由 Server 生成一个显式的句柄,作为普通的工具参数在后续调用中传入
JSON
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "search_tickets",
    "arguments": { "keyword": "退款" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "my-ide", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": { "elicitation": {} }
    }
  }
}

无状态的好处是远程 Server 更容易水平扩展:任何一个实例都能处理任何请求,不需要粘性会话,也不需要在实例之间共享会话数据。

面试官可能追问

为什么要为每个 Server 单独创建一个 Client?

一是隔离:每个连接各自独立,Server 之间互相看不到,一个 Server 出问题不影响其他连接,Host 还可以对不同的 Server 采用不同的权限策略。二是职责单一:每个 Client 只负责和一个 Server 的通信、订阅和通知,Host 在上层汇总所有 Server 的能力。

MCP Server 会直接调用大模型吗?

一般不会,调用模型的是 Host。规范里有一个 Sampling 能力,让 Server 通过 Client 请 Host 代为调用模型;2026-07-28 版规范已经把它标记为弃用(弃用期内仍然可用),建议需要模型能力的 Server 直接对接模型厂商的 API。

stdio 和 Streamable HTTP 怎么选?

只在用户本机使用、需要访问本地文件或本地工具时用 stdio,由 Host 负责启动和关闭进程,部署最简单。要给多个用户或多个应用共享、对接 SaaS 服务时用 Streamable HTTP,这时要做好认证和授权,还要校验 Origin 请求头;HTTP Server 在本机运行时只绑定 127.0.0.1,防止 DNS 重绑定攻击。

Server 的工具列表变了,Client 怎么知道?

Server 在能力里声明 listChanged 后,可以在工具列表变化时发送 notifications/tools/list_changed 通知,Client 收到后重新调用 tools/list。2026-07-28 版规范中,Client 要先用 subscriptions/listen 订阅这类通知,Server 在这个请求的响应流上持续推送。通知是尽力送达的,不保证不丢;列表结果还带有 ttlMs 缓存提示,Client 用到列表时发现已经过期,就重新获取。

易错点

  • 把 Client 理解成"用户用的客户端软件"。用户用的是 Host,Client 是 Host 内部和某个 Server 一对一连接的组件
  • 认为 MCP Server 都在远程。本地 stdio 是很常见的用法,这时 Server 以用户的权限运行在本机上
  • 认为只有 Client 能发起交互。Server 可以发通知,也能在处理请求时要求 Client 补充用户输入,见 MCP 的 Tools、Resources 和 Prompts 有什么区别

AI 模拟面试官

用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮

登录后就可以和 AI 面试官对练,面试记录也会保存下来。登录

这道题你掌握了吗?

选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。

学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。