02 - MCP 授权四版演进:官方在防什么
前置:01 - 威胁模型 里的混淆代理问题。
本篇回答:MCP 官方规范这两年里,安全模型改了什么?为什么改?
会用到的词:
- OAuth 2.1:MCP 授权所遵循的授权框架
- 授权服务器(Authorization Server):发令 牌的那个
- 资源服务器(Resource Server):验令牌、提供资源的那个 —— 在 MCP 里就是 MCP Server
- scope(作用域):令牌上写着"能干什么"的那部分
- DCR(Dynamic Client Registration):客户端在运行时自动向授权服务器注册、拿到 client_id 的机制
一、规范正文的位置
网上常说"MCP 规范有五个版本,可以逐版对比"。实测下来这句话对了一半。
仓库里确实有五个版本目录,但放在 docs/docs/<版本>/tutorials/ 下的是教程,不是规范。我把相邻版本的教程 diff 了一遍:
2024-11-05 -> 2025-03-26 : 10 行不同
2025-03-26 -> 2025-06-18 : 14 行不同
2025-06-18 -> 2025-11-25 : 14 行不同
2025-11-25 -> 2026-07-28 : 228 行不同
前三组那十几行差异全部是链接里的版本号替换,正文一字未改:
- ...see the [Authorization specification](/specification/2025-06-18/basic/authorization).
+ ...see the [Authorization specification](/specification/2025-11-25/basic/authorization).
真正的规范正文在 docs/specification/<版本>/basic/authorization。 本篇拆的是后者。
💡 这也是一个通用的教训:拆开源项目时,先确认自 己读的是规范还是文档。 两者的更新节奏完全不同。
二、四版规范的体量变化
| 版本 | 授权规范 | 体量 |
|---|---|---|
| 2024-11-05 | 不存在 | — |
| 2025-03-26 | 单文件 | 406 行 |
| 2025-06-18 | 单文件 | 373 行(变短了) |
| 2025-11-25 | 单文件 | 708 行 |
| 2026-07-28 | 拆成目录,4 个文件 | 901 行 |
四个转折点,每一个都对应一次认知升级:
第一版没有授权,因为最初的 MCP 是本地 stdio 工具 —— 进程在你自己机器上,用你自己的身份跑,不存在授权问题。授权是远程 MCP Server 带来的。
三、2025-03-26:授权首次出现
第一版的章节结构(## / ### 层级实测):
## Introduction
## Authorization Flow
### OAuth Grant Types
### Example: authorization code grant
### Server Metadata Discovery
### Dynamic Client Registration
### Authorization Flow Steps
### Access Token Usage
### Security Considerations ← 注意这里
### Third-Party Authorization Flow
## Best Practices
两个特征暴露了这一版的成熟度:
1. Security Considerations 只是 Authorization Flow 底下的一个三级小节。 安全在这一版还是流程的附属品。
2. 有 Third-Party Authorization Flow。 这一节描述 MCP Server 去代理第三方(比如 GitHub)授权的流程 —— 听起来很实用,但它下一版就被删了。
四、2025-06-18:删减与收敛
这一版比上一版短了 33 行,但结构变化很大:
| 变化 | 内容 |
|---|---|
| ➕ 新增 | Roles —— 明确区分授权服务器和资源服务器 |
| ✏️ 改名 | Server Metadata Discovery → Authorization Server Discovery |
| ⬆️ 升格 | Security Considerations 从 ### 提到 ##,并展开成 7 个子节 |
| ➖ 删除 | Third-Party Authorization Flow、Example: authorization code grant、OAuth Grant Types |
升格后的安全考量七条:
## Security Considerations
### Token Audience Binding and Validation
### Token Theft
### Communication Security
### Authorization Code Protection
### Open Redirection
### Confused Deputy Problem ← 第一次出现
### Access Token Privilege Restriction
Roles 和 Confused Deputy Problem 同时出现,不是巧合。
上一版把 MCP Server 既当资源服务器又当授权代理(那个被删掉的 Third-Party Flow),这正是混淆代理问题的温床 —— 一个高权限的中间人替低权限的调用者去拿了它不该拿的东西(见 01 篇)。
这一版的做法是:明确角色边界(MCP Server 就是资源服务器,别兼职发令牌),然后把混淆代理写进安全考量。 删掉的那一节不是能力退化,是把一个危险的设计从规范里拿掉。
Token Audience Binding 的出现同样关键 —— 它要求令牌必须绑定到特定的受众(audience),防止发给 A 服务的令牌被拿去用在 B 服务上。
五、2025-11-25:企业落地,体量翻倍
从 373 行涨到 708 行。新增的章节几乎全部指向同一件事:真正的企业身份系统怎么接进来。
## Client Registration Approaches ← 新增,独立成章
### Client ID Metadata Documents ← 新概念 CIMD
### Preregistration
### Dynamic Client Registration
## Scope Selection Strategy ← 新增
## Resource Parameter Implementation ← 新增
### Canonical Server URI
## Error Handling
### Scope Challenge Handling ← 新增
## Security Considerations
### Client ID Metadata Document Security ← 新增
## MCP Authorization Extensions ← 新增
为什么需要 CIMD
先说 DCR 的问题。动态客户端注册的逻辑是:客户端启动时向授权服务器说"我是个新客户端,给我个 client_id"。
这在 MCP 的部署形态下会出事:一个 MCP 客户端要连几十个不同的 MCP Server,每个 Server 背后可能是不同的授权服务器。 于是客户端要在几十个地方注册几十次,拿到几十个 client_id 存着 —— 而企业的 IdP(Entra、Okta)通常根本不开放动态注册,因为那等于允许任何人自助创建 OAuth 客户端。
CIMD(Client ID Metadata Documents)换了个思路:客户端的 client_id 就是一个它自己托管的 HTTPS URL,授权服务器去这个 URL 拉取客户端的元数据。
好处是可移植 —— 规范原文说得很清楚:
Client IDs based on Client ID Metadata Documents are portable across authorization servers, since they are self-hosted HTTPS URLs
一个 client_id 走遍所有授权服务器,不用注册几十次。
Scope Challenge Handling
新增的这一节解决的是:客户端一开始不知道该要哪些 scope。
流程变成:先拿一个基础令牌去试 → 服务端返回 403 并在 WWW-Authenticate 头里告诉你"这个操作需要 mcp:tools:write" → 客户端再去申请这个 scope。
我们在 Agent 网关 · 05 篇 里读 Envoy AI Gateway 的代码时,正好见过它的实现:
if !allowed {
// Specify the minimum required scopes in the WWW-Authenticate header.
// Reference: .../basic/authorization#runtime-insufficient-scope-errors
if len(requiredScopes) > 0 {
规范里的一句话,在网关代码里是一个真实的分支。
scope 长什么样?官方教程里给了 Keycloak 的配置截图:

图片来自 modelcontextprotocol/modelcontextprotocol 官方教程 docs/images/tutorial-authorization/keycloak-scopes.png
一个叫 mcp:tools 的 client scope,Include in token scope 打开 —— 这就是"令牌上写着能干什么"的物理形态。
六、2026-07-28:授权从一章变成一个目录
这一版最直观的变化是文件结构:
basic/authorization/
├── index.mdx 总纲、流程、令牌使用
├── authorization-server-discovery.mdx 授权服务器怎么发现
├── client-registration.mdx 三种注册方式
└── security-considerations.mdx 安全考量独立成文件
新增的实质内容有四块。
变化 1:动态客户端注册被正式废弃
client-registration.mdx 里,DCR 那一节顶着一个警告框:
Warning Dynamic Client Registration is deprecated. New implementations should use Client ID Metadata Documents instead. This option remains available for backwards compatibility with authorization servers that do not support Client ID Metadata Documents.
而且章节顺序本身就是优先级:CIMD 排第一,Pre-registration 第二,DCR 最后。
上一版三者还是并列的备选方案,这一版明确排了序并废弃了其中一个。从"引入新方案"到"淘汰旧方案"用了 8 个月。
变化 2:混淆攻击(Mix-Up Attack)—— 新增的攻击类型
security-considerations.mdx 里新增了一整节,原文:
An attacker that controls one of the authorization servers an MCP client interacts with may attempt to have the client send it an authorization code or token issued by a different, honest authorization server (a mix-up attack, described in RFC9207 Section 1).
翻译:你连了十个 MCP Server,其中一个是坏人。它可以骗你的客户端把另外九个正经服务器发的授权码/令牌交给它。
为什么 MCP 特别容易中招?因为 01 篇讲过的那个部署特征 —— 一个客户端连很多个服务器。传统 OAuth 场景下一个客户端通常只对一个授权服务器,混淆攻击难以成立;MCP 把这个前提彻底改变了。
变化 3:iss 校验 —— 混淆攻击的解药
对应的缓解措施写在 index.mdx 新增的 Authorization Response Validation 里。规范给了一张判定表,我照抄过来(列名是原文的字段名):
authorization_response_iss_parameter_supported | 响应里有 iss 吗 | 客户端必须怎么做 |
|---|---|---|
true | 有 | 用简单字符串比较,和记录的 issuer 比对 |
true | 没有 | 拒绝这个响应 |
false 或未声明 | 有 | 仍然比对 |
false 或未声明 | 没有 | 放行 |
三个魔鬼细节:
1. 必须先记录 issuer。 规范要求客户端在跳转前就把 issuer 值和 PKCE code verifier 存在同一条记录里,并特别提醒:
The validation in this section depends on that recorded value being authentic; it provides no protection if the expected issuer was obtained from an unvalidated source.
2. 第三行是"宽进"的兜底。 即使服务器没声明支持 iss,只要响应里带了,客户端也要比对 —— 规范解释这是为了兼容"先发 iss、后更新元数据"的服务器。
3. 比较时禁止任何规范化。 这条最容易写错:
clients MUST NOT apply scheme or host case folding, default-port elision, trailing-slash, or percent-encoding normalization ... before comparison.
不许大小写折叠、不许省略默认端口、不许处理尾斜杠、不许 percent-encoding 归一化。必须是裸的字符串相等。
任何"聪明"的 URL 规范化都会给攻击者制造可乘之机 —— 这是安全代码里一条通用戒律:比较凭证时永远用最笨的方法。
规范还预告了下一步:未来某一版会把服务器包含 iss 从 SHOULD 提升到 MUST。
变化 4:凭证必须绑定到发它的授权服务器
client-registration.mdx 新增 Authorization Server Binding:
Clients that use pre-registered credentials, or persist client credentials obtained via Dynamic Client Registration, MUST associate those credentials with the specific authorization server that issued them, keyed by the authorization server's
issueridentifier. When the authorization server changes ... clients MUST NOT reuse client credentials from a different authorization server and MUST re-register with the new authorization server.
而且发现不匹配时的行为也规定了:应该报错,而不是"悄悄尝试用一下看行不行"。
If the authorization server indicated by protected resource metadata no longer matches the one the credentials were registered with, clients SHOULD surface an error rather than silently attempting to use mismatched credentials.
"宁可报错,不要静默降级" —— 这是安全设计和可用性设计冲突时的标准取舍。
七、把四版串起来看
三条主线,每条都能追踪到具体的章节变化:
| 主线 | 2025-03 | 2025-06 | 2025-11 | 2026-07 |
|---|---|---|---|---|
| 角色边界 | MCP Server 可代理第三方授权 | ✂️ 删除,明确 Roles,写入混淆代理 | — | — |
| 客户端身份 | DCR | DCR | ➕ CIMD 与 DCR 并列 | ⚠️ DCR 废弃,凭证绑定 issuer |
| 多服务器风险 | 未涉及 | 令牌受众绑定 | 资源参数、规范化 URI | ➕ 混淆攻击、iss 校验 |
一句话总结这两年:MCP 的授权规范从"照抄 OAuth 跑通",走到了"针对 MCP 特有的『一个客户端连很多服务器』这个部署形态,逐条打补丁"。
每一次改动都是在把信任边界画得更细。 而这正是 01 篇结尾说的那句话在协议层的体现 —— 挡不住注入,就限制被注入之后能造成的后果。
八、对实现者的检查清单
如果你在写 MCP 客户端或服务端,照这个自查:
| 项 | 要求 | 版本 |
|---|---|---|
| 别让 MCP Server 兼职发令牌 | 它是资源服务器 | 2025-06 起 |
| 令牌必须校验受众(audience) | 防止跨服务重放 | 2025-06 起 |
| 新实现别再用 DCR | 改用 CIMD | 2026-07 起 |
| 客户端凭证按 issuer 分开存 | 换了授权服务器要重新注册 | 2026-07 起 |
| 跳转前记录 issuer | 和 PKCE verifier 存一起 | 2026-07 起 |
校验 iss 时用裸字符串比较 | 不做任何 URL 规范化 | 2026-07 起 |
权限不足时用 WWW-Authenticate 告知所需 scope | 而不是笼统返回 403 | 2025-11 起 |
下一篇 → 03 - 工具投毒与 Rug Pull:规范管住了身份,但工具描述本身就是攻击载体 —— 拆 SkillSpector 的检测器,看恶意 MCP Server 具体怎么写。
← 回到 专题索引 · Agent Infra 板块总览