核心摘要

MCP 是协议边界,不是授权系统,也不是自主 Agent 框架。Host 使用一个或多个 Client 连接 Server;Server 声明能力、接收 JSON-RPC 消息并返回结果。应用仍然负责:

  • 认证调用者;
  • 针对精确的 Tool、Resource、Tenant 和对象执行授权;
  • 校验参数和结果大小;
  • 限制成本、并发和副作用;
  • 审计并删除敏感数据。

本文解释基础词汇和生命周期。生产安全可阅读 MCP 生产实践,远程 OAuth 边界可阅读 企业 OAuth 集成指南

为什么需要协议边界

没有共享协议时,每个 Host 都要用不同 Adapter 接入每个外部能力。MCP 不能消除应用工作,但提供了共同的生命周期和消息模型:

关注点 MCP 提供 应用仍负责
Connection 生命周期与 Transport Profile TLS、Proxy、进程和网络策略
Message JSON-RPC framing 与 Method 形状 校验、限制和错误映射
Discovery Capability 和列表方法 信任、审批和清单治理
Tool 名称、描述、输入 Schema 身份、授权和副作用
Resource URI 形式的数据引用 所有权、新鲜度、分类和删除
Prompt 可复用消息模板 内容审查、注入控制和策略

互操作性不等于权限可迁移。一个 Server 可以被多个 Host 使用,但每个部署仍需要自己的授权模型。

四种角色

Host

Host 是面向用户的应用或 Agent Runtime,通常负责:

  • 接收用户请求;
  • 选择或路由模型;
  • 管理一个或多个 Client;
  • 把发现到的能力呈现给模型;
  • 执行 Host 侧审批和展示策略。

Host 不应把 Server 的描述当成可信指令。描述、Resource 和 Result 都是跨信任边界的数据。

Client

MCP Client 是由 Host 管理的协议连接。常见拓扑是一个 Client 对应一个 Server,以隔离 Session、Capability 和故障状态。Host 也可以使用 Router 或 Gateway,但这会增加新的状态和策略边界。

Server

Server 暴露能力并在自己的策略下执行。它可以访问文件系统、数据库、API 或进程内服务。“Server”描述的是协议角色,不保证一定是独立 OS 进程、沙箱或安全边界。

External System

数据库、文件存储、SaaS API 或本地操作系统才是业务数据的权威。MCP Server 是 Adapter 和策略执行点,不能替代外部系统的访问控制。

生命周期与 Capability 协商

具体 Method 取决于固定的规范版本,但连接通常包含:

sequenceDiagram participant H as "Host" participant C as "MCP Client" participant S as "MCP Server" H->>C: 创建连接 C->>S: initialize + Client Capabilities S-->>C: Server Capabilities + Protocol Version C->>S: initialized notification C->>S: 按需列出能力 C->>S: 调用已授权 Method S-->>C: 关联 Result 或 Error C-->>H: 有界 Observation

Capability 协商不是权限授予,只说明对端支持哪些协议功能。Server 仍需在执行时检查已认证 Principal 和具体操作。

可靠 Client 还应处理:

  • Protocol Version 不匹配;
  • 初始化超时;
  • 畸形或超大消息;
  • 取消和断连;
  • Capability 变化;
  • Server 关闭和重连;
  • 重复请求和幂等。

JSON-RPC 边界

MCP 使用 JSON-RPC 的请求、响应、通知和错误概念。Request ID 用于关联响应,不负责认证请求。

typescript
type RequestId = string | number;

type JsonRpcRequest = {
  jsonrpc: "2.0";
  id: RequestId;
  method: string;
  params?: Record<string, unknown> | unknown[];
};

type JsonRpcError = {
  code: number;
  message: string;
  data?: unknown;
};

function requireRequest(value: unknown): JsonRpcRequest {
  if (!value || typeof value !== "object") throw new Error("invalid_request");
  const request = value as Record<string, unknown>;
  if (request.jsonrpc !== "2.0" ||
      (typeof request.id !== "string" && typeof request.id !== "number") ||
      typeof request.method !== "string") {
    throw new Error("invalid_request");
  }
  if (request.params !== undefined &&
      (!request.params || typeof request.params !== "object")) {
    throw new Error("invalid_params");
  }
  return request as unknown as JsonRpcRequest;
}

片段只校验 framing。Method Schema、请求大小、授权、取消和业务规则仍由 Server 负责。JSON-RPC 错误中不要返回 Stack Trace 或凭证。

三类核心能力

Tools

Tools 是 Client 可以请求 Server 执行的操作。Tool 定义通常包含名称、描述、输入 Schema 和 Annotation。模型发出的调用应视为提议:

text
模型提出 Tool Call
    -> Host/Client 执行审批和预算策略
    -> Server 认证并授权
    -> Server 校验参数
    -> Server 执行操作
    -> Server 返回有界 Result

好的 Tool 应明确:

  • 做什么以及不做什么;
  • 输入限制和默认值;
  • 读写行为;
  • Resource 与 Tenant 范围;
  • 超时、重试、幂等和输出限制。

除非整个能力已被有意沙箱化并授权,否则不要暴露通用 run_command、任意 SQL、无限制 HTTP Client 或“管理一切”的 Tool。严格 Schema 不能让危险能力自动安全。

Resources

Resources 提供 Client 可以读取的数据引用。URI 是标识符,不是读取权限证明。Server 必须通过允许的 Scheme、Tenant 策略、对象授权、新鲜度规则和大小限制解析它。

Resource Link 可以避免把大 Artifact 嵌入 Tool Result,但后续读取必须重新鉴权。不要假定可信 Server 返回的 Resource 适合直接放入 Prompt,它可能包含指令或敏感数据。

Prompts

Prompts 是 Server 暴露的可复用消息模板,可以提升一致性,但不是安全角色,不能覆盖系统策略。Prompt 内容、参数和插入的 Resource 都应视为不可信数据。

Transport 选择

stdio

Host 启动本地进程时可使用 stdio。仍需审查继承的环境变量、文件系统、网络外发、Shell、OS 用户和进程生命周期。本地进程并不天然沙箱化。

Streamable HTTP

新的远程部署应评估固定规范和 SDK 支持的当前 Streamable HTTP Profile。要审查 TLS、认证、请求限制、Session、重连、取消、Proxy Buffering、Origin 策略和优雅关闭。

旧式 SSE 兼容

部分旧 Client 和 SDK 使用 SSE 事件流加独立 POST 消息端点。如果必须支持:

  • 隔离并标记兼容路由;
  • 生成并绑定 Server 侧 Session;
  • 对 SSE 和每个消息请求执行认证;
  • 限制事件队列和结果大小;
  • 明确顺序、取消、重连和重复行为;
  • 通过真实 Proxy 路径测试。

不要把旧式 SSE 称为“MCP 的流式协议”,也不要推断所有远程 Server 都使用同样的端点名称。

安全模型:MCP 不保证什么

MCP 标准化通信,但不保证:

  • 用户认证;
  • 租户隔离;
  • 对象所有权;
  • Tool 行为安全;
  • Prompt Injection 抵抗能力;
  • Transport 或 Telemetry 机密性;
  • 缓存和日志中复制数据的删除。

远程 Server 至少需要:

  1. 可信 Token 或 Workload 认证;
  2. Issuer、Audience/Resource、Expiry、Algorithm 和 Key Rotation 校验;
  3. 逐调用 Scope 和对象级授权;
  4. 请求、结果、并发、超时和成本限制;
  5. 副作用的幂等与取消;
  6. 脱敏审计事件和 Trace Context;
  7. 跨租户、Tool Result Injection 和重放测试。

Read-only 或 Destructive 等 Annotation 可以帮助 Host 展示风险,但 Server 必须独立验证真实行为并执行策略。

最小 Server 设计

把协议适配、Policy 和业务逻辑分开:

text
Transport Adapter
  -> JSON-RPC 与 Method 校验
  -> Principal 与 Tenant Context
  -> Tool/Resource Policy
  -> Domain Service
  -> 有界 Result 与 Audit Event

Domain Service 应接收可信 Context,而不是从模型参数推断身份:

typescript
type ExecutionContext = {
  requestId: string;
  principalId: string;
  tenantId: string;
  scopes: ReadonlySet<string>;
};

type ReportRequest = {
  reportId: string;
};

async function getReport(
  context: ExecutionContext,
  request: ReportRequest,
  authorize: (context: ExecutionContext, reportId: string) => Promise<boolean>,
  repository: { read: (tenantId: string, reportId: string) => Promise<unknown> },
) {
  if (!context.scopes.has("reports.read")) throw new Error("insufficient_scope");
  if (!(await authorize(context, request.reportId))) throw new Error("access_denied");
  const report = await repository.read(context.tenantId, request.reportId);
  return { status: "ok", report };
}

这是核心片段,不是完整 SDK 接入。实际应用还要增加 Repository 级 Tenant 约束、结果脱敏、大小限制、Trace、错误映射和取消。

测试与运维

从四层测试契约:

层级 示例
Protocol initialize、版本不匹配、畸形 JSON-RPC、Capability 变化
Policy 缺少 Scope、错误 Tenant、对象所有权、过期 Token
Reliability 超时、取消、重连、队列溢出、重复请求
Abuse Result 注入、超大 Payload、SSRF、路径穿越、数据外泄

观测低基数事件:

  • Protocol 和 SDK 版本;
  • Run、Request 和 Trace 标识;
  • Method/Tool 名称和版本;
  • 参数摘要、结果类别和字节数;
  • Policy 结果和错误类别;
  • 延迟、重试、取消和预算。

默认不要保存原始 Token、私有 Prompt、完整 Tool Result 或隐藏推理。

如何选择 SDK

选择覆盖目标版本、Transport、取消、Capability 协商、授权 Hook 和安全更新的维护中 SDK。手写 Adapter 可以用于学习或狭窄的兼容边界,但会产生长期一致性和事故响应责任。

评估 SDK 时检查:

  • Protocol 一致性测试;
  • 依赖和发布历史;
  • Transport 与 Proxy 行为;
  • 错误和取消语义;
  • 授权和脱敏扩展点;
  • 观测和删除支持;
  • 升级和回滚策略。

生产检查清单

  • [ ] 固定 MCP 版本和 SDK。
  • [ ] 记录 Host、Client、Server、外部系统和信任边界。
  • [ ] 选择 Transport Profile,并标记旧式 SSE 为兼容行为。
  • [ ] 校验 JSON-RPC framing 和 Method Schema。
  • [ ] 对每个操作执行认证和授权。
  • [ ] 将 Resource 和 Tool 绑定到 Tenant 与对象策略。
  • [ ] 限制请求、结果、队列、并发、超时和成本。
  • [ ] 定义取消、重连、重复和关闭行为。
  • [ ] 将描述、Prompt、Resource 和 Result 视为不可信数据。
  • [ ] 脱敏 Telemetry,并测试删除传播。

常见问题

MCP 是什么?

它是 Host 连接面向模型的 Client 与暴露能力的 Server 的开放协议。它标准化生命周期和消息,但不标准化业务授权。

Host、Client、Server 有什么区别?

Host 协调用户和模型,Client 管理协议连接,Server 在自己的策略下声明并执行能力。

MCP Tool 是 Function Calling 吗?

两者在结构化调用边界上有交集,但 MCP 还定义跨进程发现、生命周期、Transport 和结果交换。Server 仍要校验和授权每次调用。

新的远程 Server 应该使用什么 Transport?

固定规范并使用其当前支持的 Profile。只有存在明确兼容需求时才使用旧式 SSE。

Schema 能让 Tool 安全吗?

不能。Schema 只校验形状,身份、Tenant、对象、Purpose、副作用和输出策略必须由 Server 执行。

总结

MCP 的价值在于保持边界诚实:它标准化 Host 与 Server 如何发现能力、交换消息,却把身份、业务权威、数据治理和运行安全留给应用。先理解生命周期,固定 Transport Profile,保持 Tool 窄化,并把所有描述、Resource 和 Result 当作不可信输入,才能正确进入 OAuth、Gateway、Tool 设计和评估等生产主题。

一手来源