MCP OAuth 实战:给 AI 智能体一把钥匙,而非你的密码

用 OAuth 令牌代替主控密钥,MCP 授权规范让 AI 智能体只拿到「一把窄钥匙」
文章以「把密码交给 AI」的风险为切入点,介绍了 MCP(Model Context Protocol)网络授权规范的完整工作流程。核心理念是:永远不要给智能体主控密钥,而是颁发一个 audience(受众)与 scope(权限范围)双重受限的 OAuth 令牌。整套流程包括:服务器通过 401 响应指引客户端读取 `/.well-known/oauth-protected-resource` 元数据文档,客户端随后使用 PKCE 和 `resource` 参数发起精确授权请求,服务端对每次调用校验签名、过期时间、受众与权限范围。当智能体需要超出当前令牌权限的操作时,「步进式授权」机制确保每一次权限扩张都须经用户明确批准。文章还特别强调两条铁律:令牌只能放在请求头、服务器不得转发令牌,以防日志泄露和「混淆代理人」攻击。
你会把自己的密码直接交给一个 AI 智能体吗?大概不会。但当你把一个主控 API Key 粘贴进智能体的配置文件时,本质上做的就是这件事——它从此拥有和你完全相同的权限,无限期有效,直到你某天察觉异常为止。
其实有更好的做法,而且它已经内置在 MCP(Model Context Protocol)协议里了:给智能体一把钥匙,而不是你的密码。下面这篇文章拆解整套授权流程,并以一个真实运行的 Demo 走通每一步。
本地与网络:两种完全不同的场景
开始之前先做一个关键区分。如果你的 MCP 服务器在本地通过标准输入输出(stdio)运行,规范明确建议:不要折腾这一整套授权机制,直接从环境变量读取凭证即可。
但一旦你的服务器搬到网络上、通过 HTTP 对外提供服务,情况就彻底变了——任何人都可以来敲门。这正是 MCP 授权规范发挥作用的地方。它并非什么新奇技术,底层就是标准的 OAuth,只是把若干规则严格地应用了起来。
整套机制有三个角色:
- MCP 客户端:也就是你的智能体或应用。
- MCP 服务器:持有工具和数据,在 OAuth 术语中称为「资源服务器」(Resource Server)。
- 授权服务器(Authorization Server):负责处理登录并签发令牌。
核心思想是:MCP 服务器永远看不到你的密码,它只会看到一个令牌(Token),并据此判断这个令牌被允许做什么。

一次「无令牌」请求会发生什么
Demo 用的是一个极简的笔记服务器,提供两个工具:一个读笔记,一个写笔记。
当客户端不带任何令牌去调用它时,会收到一个 401 Unauthorized。但真正有价值的是返回的响应头——它不是简单地说「不行」,而是明确告诉客户端:规则写在哪里(resource metadata 链接),以及你需要什么权限范围(scope:notes.read)。
换句话说,服务器主动告诉客户端应该如何「正确地请求」。
客户端顺着这个链接,会访问到一份位于 /.well-known/oauth-protected-resource 的小型 JSON 文档。每一个受保护的 MCP 服务器都必须发布这样一份文档。它声明了服务器的身份、列出支持的权限范围,最关键的是——指明了哪个授权服务器有资格为它签发令牌。

登录环节:PKCE 与 resource 参数
接下来客户端发起一次标准的 OAuth 登录,但带了两个重要的额外项。
PKCE:防止授权码被盗用
客户端自己生成一个秘密值,发送出去的只是它经过散列后的「打乱版本」,稍后领取令牌时再证明自己知道原始值。这样一来,即便登录授权码被人截获,单凭它也毫无用处。
resource 参数:令牌只对指定服务器有效
客户端通过完整地址明确声明:这个令牌是给「我们的笔记服务器」用的。同时,它只申请被告知所需要的权限范围——不是要「所有权限」,而仅仅是 notes.read。
解码返回的令牌后,有两个字段最关键:
- audience(受众):表明这个令牌只属于笔记服务器,别无他用。
- scope(范围):表明它只能读笔记,不能做更多。
这意味着,即便令牌泄露,损失也被牢牢限制住:它既不能用于其他服务,也写不了一条笔记。

OAuth 本身是一套已有十余年历史的行业标准授权框架(RFC 6749),核心思想是「委托授权」:用户将某项有限权限委托给第三方应用,而不必交出自己的账号密码。在 OAuth 中,客户端先向授权服务器申请授权码(Authorization Code),再凭码换取访问令牌(Access Token),令牌通常是经过签名的 JSON Web Token(JWT),可在服务端直接验签而无需查库。MCP 授权规范基于 OAuth 2.1 草案,在原有基础上强制要求使用 PKCE、禁止 implicit flow 等安全性较低的流程,并通过 resource 参数(RFC 8707)将令牌绑定到具体服务器,从而把一个通用的行业标准收紧成适合机器客户端(AI 智能体)的安全子集。
服务端的强制校验只需几行代码
在服务器端,权限的强制执行其实非常简洁:
- 校验签名;
- 校验令牌未过期;
- 校验 audience 恰好是本服务器——任何一项失败,返回 401。
随后针对每个工具再检查 scope:读笔记需要 notes.read,写笔记需要 notes.write。
携带当前令牌的读取调用会直接通过。但当智能体尝试去写一条笔记时,服务器会返回 403 Forbidden,并给出精确原因:权限不足(Insufficient scope),你需要 notes.write。

步进式授权(Step-up Authorization)
这种机制叫作「步进式授权」。客户端会回头向用户申请这项额外权限,同时保留已有的权限范围,拿到新令牌后再重试。整个过程中,每一次权限的扩张都由用户亲自掌控,而不是一次性把大权交出去。
两条常被违反的铁律
整套流程中有两个高频踩坑点,务必记牢:
第一,令牌只能放在 Authorization 请求头里,绝不要放进 URL。 一旦出现在 URL 中,它就会被各种日志记录下来,等于明文泄露。
第二,MCP 服务器只能接受为它自己签发的令牌,绝不能把客户端的令牌转手传给另一个 API。 这种错误被称为「混淆代理人」(Confused Deputy),也正是一把本应「狭窄」的钥匙重新膨胀成「主控密钥」的典型路径。
「混淆代理人」(Confused Deputy)攻击得名于 1988 年的一篇经典论文,描述的是这样一种漏洞:一个拥有特定权限的中间程序(代理人),被诱骗以自己的权限去执行攻击者本来无权执行的操作。在 MCP 场景中,如果服务器将收到的客户端令牌原样转发给下游 API,那么攻击者只需控制 MCP 服务器(或向其注入恶意工具调用),就能以服务器的身份冒充用户访问任意下游资源。正确做法是:每次需要调用下游服务时,MCP 服务器应以自身身份重新向授权服务器申请一个新的、专用的令牌,而不是「借用」传进来的那把钥匙。
完整流程回顾
把整条链路串起来:
- 敲门 → 得到 401,并附带「去哪里看规则」的指引;
- 读取 metadata 元数据文档;
- 使用 PKCE 登录,并明确指定目标服务器;
- 获得一个 audience 和 scope 都很狭窄的令牌;
- 服务器在每一次调用时都校验这两项;
- 当智能体需要更多权限时,再次向用户申请。
一句话总结:给钥匙,而非给密码。
对于正在构建 AI 智能体的开发者来说,这套做法最大的意义在于把风险收敛在可控范围内——即使出了问题,损失也被限制在一个具体工具、一个具体权限上,而不是整个账户的全盘失守。如果你在搭建智能体,不妨从「狭窄的钥匙」开始。
相关推荐

Kimi K3.1实测:开源模型逼近Opus,视频生成意外抢镜
Kimi K3.1在直播实测中完成运动图形、3D渲染、小游戏与视频生成等复合任务。本文分析其2.8万亿参数MoE架构的真实表现、与Opus/GPT的体感差距,以及被官方忽略的视频生成能力,并讨论多模型并用时代的工作流变化。

Sam Altman:人生重大建议,为何仍需来自人类?
OpenAI CEO Sam Altman 谈 AI 建议的边界:AI 能劝阻冲动邮件,但人生重大建议仍应来自人类。他期待 AI 成为会反驳的资深同事,而非谄媚工具。

“黑色十月”:AI挖出史上3%严重漏洞?
Reddit 热帖称过去一个月发现了史上 3% 的严重软件漏洞,被称为「黑色十月」。本文拆解这一说法的统计口径问题,分析 AI 辅助代码审计如何加速漏洞发现,以及开发者和企业该如何应对补丁窗口缩短的挑战。