MCP:在宿主与外部能力之间建立协议边界
核验日期:2026-07-16。本文以 MCP 2025-06-18 规范为明确观察点。MCP 按日期版本演进,客户端和服务端必须在初始化时协商,不能把本文日期当作永久最新版。
Model Context Protocol(MCP,模型上下文协议)让一个 AI 宿主用统一的数据层连接多个 server。Server 可以公开 Tools、Resources 与 Prompts;Client 在 Host 内维护一条 server 连接;Host 负责用户体验、模型、权限、同意、上下文和跨 server 编排。MCP 规范互操作消息,不替应用完成授权或 Agent 规划。
参与者与层次
Host 不能把多个 server 当成同一信任域。每个 client 连接有独立 capability、认证、session 和失败状态;server A 的文本不能授权调用 server B。Server 描述能力,Host 决定哪些暴露给模型以及是否执行。
数据层基于 JSON-RPC 2.0 request/response/notification,定义生命周期与核心 primitives;传输层负责 framing、连接、认证和恢复。自定义传输仍要保留 JSON-RPC 格式与生命周期语义。
初始化、运行与关闭
Client 先发送 initialize,声明支持的协议版本、capabilities 和实现信息;Server 选择支持版本并返回自身 capabilities;Client 发 notifications/initialized 后进入运行期。运行期只能使用协商过的能力。关闭方式取决于传输:stdio 关注进程/流,HTTP 关注 session 和请求生命周期。
若没有共同版本,应明确失败,不猜测字段。HTTP 后续请求携带协商的 MCP-Protocol-Version;session 丢失或 server 返回对应状态时,client 按规范重新初始化,不能继续沿用旧 capability/授权假设。
Tools、Resources 与 Prompts
Tool 是模型可建议调用的操作,具有名称、描述、输入 Schema,可返回文本、图片、resource link 或结构化内容。Tool 可能有副作用,所以 Host 应展示调用、校验参数并按风险审批。Server 端仍需认证、授权、限流、输入验证和审计,不能相信“Host 已检查”。
Resource 是由 URI 标识、由应用选择读取的上下文数据,可通过 list/read 或模板发现;它更像可寻址内容,不等于模型动作。Prompt 是 server 提供的可复用消息模板,通常由用户显式选择。三者不要混用:把读取文档做成高权限 Tool 会扩大代理权,把写操作伪装成 Resource 会隐藏副作用。
Server 可通过 list-changed 等通知提示能力变化(需协商支持)。Host 更新注册表时要处理正在执行的 call 与缓存,不让同名工具在一次 run 中悄然换 Schema。能力描述和结果都受大小、数量与上下文预算约束。
stdio 与 Streamable HTTP
stdio 由 Client 启动本地进程,以 stdin/stdout 交换 JSON-RPC;stderr 可用于日志。stdout 不能混入普通日志,否则破坏 framing。进程继承环境变量和文件权限,Host 应使用最小环境、固定 executable/参数、受控工作目录与资源限制,Server 包升级视为供应链变更。
Streamable HTTP 使用单一 MCP endpoint 支持请求/响应、可选 SSE 流、server-to-client 通知和 session。生产要求 HTTPS、Origin/Host 验证、认证、请求大小、连接数、空闲/总超时、重连与 backpressure。远程连接失败时区分 DNS/TLS/auth/version/session/rate limit/server error,不把所有错误变成“工具不可用”。
| 维度 | stdio | Streamable HTTP |
|---|---|---|
| 典型边界 | 同机子进程 | 跨网络服务 |
| 身份 | 进程启动与本地权限 | OAuth/服务身份与 HTTP 策略 |
| 生命周期 | 子进程与管道 | 请求、session、SSE/重连 |
| 风险 | 环境/文件/命令与供应链 | SSRF、token、Origin、网络多租户 |
| 运维 | Host 管进程和日志 | Server 独立扩缩、SLO 与版本 |
Authorization 不是把 token 传过去
2025-06-18 HTTP 授权框架建立在 OAuth 2.1 相关机制上,包括受保护资源元数据、授权服务器发现、PKCE 和安全通信。Client 只把 access token 发给其 audience 对应的 MCP resource server;MCP server 调上游 API 时使用独立上游 token,禁止 token passthrough。否则 server 会变成混淆代理,泄露权限边界。
stdio 通常不使用这套 HTTP 授权流程,但仍必须按本地 OS/沙箱权限控制。Host 不应把用户全量环境变量交给未知 server。多租户 server 根据已认证主体在每个 tool/resource 操作上授权,不能信任参数里的 tenant id。
Server-to-client 能力与信任
规范允许 server 在协商后发起某些请求,例如 sampling、elicitation 或 roots 相关交互。它们不是 server 获得宿主模型、用户输入或文件系统的无限权限。Host 应展示来源、限制可用模型/工具、验证 elicitation Schema、禁止索取 secret,并对 roots 使用规范化路径与最小范围。
任何 server 返回的 Prompt、resource 或 tool result 都是不可信内容。它可以影响模型输出,却不能更改 Host 策略、自动批准调用或读取其他 server 的数据。跨 server 数据流要有明确用户目标与策略,trace 记录来源。
一个最小 Server 的工程约束
实际 TypeScript SDK API 会变化,设计先固定端口:
type ToolContext = {
principal: { subject: string; tenant: string };
signal: AbortSignal;
requestId: string;
};
type ToolHandler = (input: unknown, context: ToolContext) => Promise<unknown>;
const handlers = new Map<string, ToolHandler>([
["search_technologies", async (input, context) => {
context.signal.throwIfAborted();
return technologyService.search(validateSearch(input), context.principal);
}],
]);SDK adapter 把 MCP request 转成这条端口;业务服务不依赖 transport 对象。这样同一授权/验证可由 HTTP API、原生工具和 MCP 复用,也能用纯函数/本地 transport 测试。错误对模型返回稳定安全 code,对 server 日志保留受控 cause。
Schema、结果与错误
输入 Schema 尽量严格,启动时检测 server 声明是否可解析;结果有 output schema 时二次验证。JSON-RPC protocol error、MCP operation error 和 tool execution error 分层处理。可预期业务失败作为结构化结果/错误内容,传输或内部 bug 不伪装成成功文本。
Tool 结果要限制字节、item 数和嵌套;大资源返回 URI/分页而不是一次塞进上下文。二进制声明 MIME type。日志、stack、数据库 DSN 和 token 不进结果。Client 对未知 content type 按协商策略拒绝或安全忽略,不能直接渲染任意 HTML。
安全威胁清单
- 恶意 server 通过描述/结果做间接注入:最小工具集、内容标记、调用授权与审批。
- 本地 server 包被替换:锁版本、校验来源/签名、最小进程权限、升级审查。
- HTTP server 被 DNS rebinding/SSRF 利用:固定 allowlist、TLS、Origin/Host 与网络策略。
- token 泄漏或混淆:audience 校验、安全存储、短时 token、禁止 passthrough。
- 工具名/Schema 改变:能力版本/哈希、运行内冻结、变更重新同意。
- session 劫持或重放:TLS、安全 session id、过期、绑定身份、幂等写操作。
- 资源 URI 穿越:规范化、root/tenant 限制,不拼接任意路径。
测试与可观测性
协议测试覆盖初始化成功/无共同版本、capability 缺失、list/call、notification、取消、超时、malformed JSON-RPC、断连、session 失效和重连。契约测试对每个工具跑 Schema 正反例、授权测试、结果大小和敏感信息。stdio 测 stdout 污染与子进程退出;HTTP 测 Origin、auth、并发、SSE 中断和版本 header。
trace 关联 Host run、MCP client、server request 与下游 API;记录 server identity、协议/实现版本、transport、tool/resource 名、延迟、结果类别和字节,不默认记录敏感正文。Server SLO 独立于模型 SLO,Host 有 per-server bulkhead 与熔断/降级。
MCP 与普通 API 的取舍
只有一个应用调用一个稳定服务时,类型化 HTTP/SDK 可能更直接。需要多个 Host 发现同一工具/资源集合、动态列举能力或生态互操作时,MCP 降低适配重复。采用 MCP 不意味着删掉领域 API;Server 通常是受控 adapter。协议层的固定成本包括生命周期、Schema、认证、同意、兼容和测试。
验收时必须能回答:Host/Client/Server 各负责什么;Tools/Resources/Prompts 如何分工;两种 transport 的信任边界;版本如何协商;为何 token passthrough 危险;Server 内容为何不能授权其他工具;断连后如何恢复且不重复副作用。