先记住这个答案
Host 是用户直接使用的 AI 应用,负责管理多个 Client、汇总各 Server 的能力、做权限与用户确认决策。Client 是 Host 内部为某一个 Server 实例化的协议组件,负责握手、收发 JSON-RPC 消息、维护该连接的状态。Server 是提供 tools、resources、prompts 等能力的程序,不关心谁在调用。Host 为每个 Server 创建一个 Client,是因为不同 Server 的版本、能力、会话状态都不同,复用连接会混淆协议状态与权限边界,一对一让每段关系可独立协商、独立关闭。
- Host 管协调、权限与用户交互
- Client 是单 Server 的协议端点
- Server 只负责提供能力
- 一对一保证状态与权限隔离
三者职责如何在协议中落地
Host 是 Claude Desktop、VS Code 这类 AI 应用本身。它不直接说协议,而是维护一份 Server 配置清单,为每条配置创建一个 Client 对象,并把各 Server 上报的能力汇总给模型做工具选择。涉及用户确认、访问授权、UI 呈现的逻辑都在 Host 层,Server 发来的请求最终也由 Host 决定如何响应。
Client 是 Host 内部的协议端点,生命周期与一条连接绑定:发起握手、缓存对端能力、按 JSON-RPC 2.0 收发请求与通知、处理超时与关闭。Server 则是能力提供方,无论本地子进程还是远程服务,职责只是声明能力并响应调用,它不知道也不应知道 Host 里还连着哪些其他 Server。
VS Code 同时连接两个 Server 时的实例划分
场景:VS Code 作为 Host,配置了一个 Sentry 远程 Server 和一个本地文件系统 Server。启动时 VS Code 运行时分别实例化两个 Client:Client A 走 HTTP 连 Sentry,Client B 通过子进程连文件系统。两者各自完成握手,得到完全不同的能力清单,VS Code 把两份工具合并后暴露给模型。
决策与结果:当文件系统 Server 崩溃时,Host 只关闭 Client B 并标记其工具不可用,Client A 与 Sentry 的会话完全不受影响。如果两个 Server 共用一个 Client,协议状态、请求 id 空间和能力缓存都会纠缠,一个 Server 的异常或版本差异会污染另一个的连接,故障无法隔离。
一对一原则的适用边界
一对一描述的是 Host 侧的对象模型,不是说一个 Server 只能服务一个 Client。本地 stdio Server 通常只服务一个 Client,而远程 HTTP Server 往往同时服务来自许多 Host 的大量 Client。把一对一误解为 Server 单租户,会导致错误的容量规划。
另一个易错边界是传输复用:有人想用一个 Client 负载均衡地连同一 Server 的多个副本以省内存。这会把同一会话的请求路由到不同副本,有状态 Server 会因会话不一致而出错。正确做法是会话亲和或让 Server 无状态化,代价是增加部署复杂度或丧失会话内状态。
容易答错的地方
- 把 Client 当成用户使用的应用
- 用户面对的是 Host,Client 只是 Host 内部不可见的协议组件。说「用户在 Client 里授权」是错误的,权限确认与 UI 决策都发生在 Host 层,Client 只负责把结果按协议传递。
- 认为一对一意味着 Server 只能接一个 Client
- 一对一约束的是 Host 为每个 Server 建独立 Client,不是限制 Server 的并发。远程 Streamable HTTP Server 设计上就服务大量 Client,只有本地 stdio Server 才通常单 Client。
面试官还会怎么问?
Host 为什么要把权限管理放在自己这一层?
因为权限决策需要全局视角:只有 Host 知道用户意图、当前任务和全部 Server 的能力。Server 只见单条连接,无法判断一次工具调用是否符合用户授权,所以确认与授权必须由 Host 统一执行。
一个 Host 连接同一 Server 两次需要几个 Client?
每条连接一个 Client,即两个。两次连接是独立的协议会话,各自握手、各自维护状态,Host 把它们视为两个端点,即使目标程序相同也不共享 Client。
Server 需要感知 Host 的存在吗?
不需要。Server 只面向 Client 这个协议对端,按握手中声明的能力交互。Host 的模型选择、用户交互对 Server 完全透明,这正是分层解耦的目的。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。