返回
Kevin Riedl

11 分钟 阅读 · 2026年7月23日
最近审核

下一篇
图片在你的设备上生成,不连接 Instagram。文章链接会复制到剪贴板,供链接贴纸使用。

企业级 MCP 授权架构:一份多租户参考设计

Model Context Protocol 规范终于对授权说了点实在话:使用 OAuth 2.1,用 resource indicators 把每个令牌绑定到特定受众,绝不把客户端令牌透传给下游 API。这些要求是真的。问题在于,它们散落在核心规范、一份安全最佳实践文档和半打 IETF RFC 之间,而几乎每一个为这些关键词排名的页面,都是止步于单服务器场景的安全厂商清单。

这是我们的参考设计,适用于当客户需要一台 MCP 服务器:服务多个租户、对接企业身份提供方、并能通过采购方的安全审查。它厂商中立,已于2026年9月2日对照规范 2026-07-28 修订版重新核查,并画出从身份提供方到按租户隔离数据面的完整信任边界。内容源自 Wavect 在 AI 产品安全加固上的工作。

这篇文章负责实现 MCP 授权层。如果你还在判断 MCP 本身能否成为边界,请先阅读为什么 MCP 不是安全边界,以及数据级访问控制如何补上缺口

在设计一台企业级 MCP 服务器?

 联系 Wavect

各司其职:MCP 服务器是资源服务器,不是授权服务器

最常见的错误,是把 MCP 服务器建成它自己的登录系统。它不是。按当前规范,MCP 服务器是一台 OAuth 2.1 资源服务器。它的职责是校验令牌,而不是签发令牌。签发由一台独立的授权服务器负责,在企业里就是你的身份提供方(Entra ID、Okta、Auth0、Keycloak、Ping),由它与用户交互并签发访问令牌。

这个拆分是近期才有的。第一版授权规范(2025-03-26)期望 MCP 服务器同时充当授权服务器和资源服务器。2025-06-18 修订版通过 pull request 284 拆分了这两个角色,使企业身份提供方可以清晰地接入该架构。授权服务器仍然可以与资源服务器同处一地,但 MCP 服务器被规定的职责就是校验令牌。把这个角色模型定对,下游的一切都会各就各位。定错了,你就在拙劣地重造身份系统。

当前规范究竟要求什么?

表格之前先说两点。第一,MCP 里的授权是可选的,且为基于 HTTP 的传输定义。使用 STDIO 的服务器不应遵循这份授权规范,而应从环境中取凭据。第二,OAuth 2.1 仍是 IETF 草案,不是已发布的 RFC,所以别给它引用 RFC 编号。下面是 2026-07-28 修订版的标准面。

标准引用在 MCP 中的角色级别
OAuth 2.1draft-ietf-oauth-v2-1核心授权框架授权服务器 MUST
Protected Resource MetadataRFC 9728服务器把客户端指向其授权服务器资源服务器 MUST
Resource IndicatorsRFC 8707把令牌绑定到一个受众客户端 MUST
Authorization Server MetadataRFC 8414授权服务器发现MUST(此项或 OIDC)
OpenID Connect DiscoveryOpenID Connect Discovery 1.0授权服务器发现的替代方式MUST(此项或 8414)
Authorization Server Issuer IdentificationRFC 9207防止授权服务器 mix-up服务器 SHOULD 发送,出现时客户端 MUST 校验
PKCEOAuth 2.1 第 7.5.2 节保护 authorization code客户端 MUST 实现并验证支持
Client ID Metadata Documentsdraft-ietf-oauth-client-id-metadata-document-00用 HTTPS URL 作为 client_id客户端与授权服务器 SHOULD
Dynamic Client RegistrationRFC 7591向后兼容的客户端注册已弃用,MAY
Bearer 令牌用法RFC 6750challenge 与 insufficient_scope被引用

2026-07-28 修订版正式弃用 Dynamic Client Registration,转向 Client ID Metadata Documents;它还把保存的客户端凭据绑定到创建它们的授权服务器 issuer,并增加 RFC 9207 授权响应 issuer 校验。PKCE 仍为强制要求:客户端必须在继续前验证 code_challenge_methods_supported,并在技术上可行时使用 S256

授权流程从头到尾怎么走?

整个握手就是一个发现步骤,后接一个标准的 authorization code flow。客户端不带令牌访问服务器,被告知去哪里认证,完成认证,然后带着一个为这台特定服务器签发的令牌回来。

MCP OAuth 2.1 授权时序:401 challenge、protected-resource metadata 发现、带 PKCE 和 resource indicator 的 authorization code flow,然后是资源服务器校验的绑定受众 bearer 令牌

那张图里藏着两个必做细节。服务器必须通过 401 Unauthorized 响应中的 WWW-Authenticate 头,或通过 well-known URI 提供 RFC 9728 Protected Resource Metadata。客户端必须支持两种机制,有头部 URL 时使用它,否则依次探测端点专用和根路径 well-known URI。在 authorization 和 token 请求中,客户端必须发送一个设为 MCP 服务器规范 URI 的 resource 参数,无论授权服务器是否声明支持。

为什么禁止令牌透传,以及你如何校验受众?

这是规范的安全核心,也是大多数自建服务器翻车的地方。规则很直白:MCP 服务器必须校验每个访问令牌都是把它当作目标受众而签发的,并拒绝其他一切。它不得接受为另一个服务签发的令牌,也不得把收到的令牌转发给下游 API。最后这个反模式就是令牌透传,规范对它明令禁止。

原因是 confused deputy 问题。如果你的服务器接受并转发它没有校验的令牌,那么为某个服务泄露或签发的令牌,就变成了另一个服务的万能钥匙,基于受众的限流被绕过,下游审计轨迹显示的是错误的身份。校验受众只是一次 claim 检查,而它就是资源服务器与法律责任之间的那条线。

on every tool call:
  token = bearer_from_authorization_header()   # every request is self-contained
  claims = verify_signature(token, jwks_of(trusted_issuer))
  assert claims.iss == expected_issuer          # pinned per tenant
  assert this_server_uri in claims.aud          # RFC 8707 audience
  assert not expired(claims) and not before(claims)
  assert required_scope_for(tool) in claims.scope
  tenant = claims["tenant"] or claims["org_id"]
  enforce_tenant(tenant)                         # every query, every secret

2026-07-28 核心规范移除了协议握手和 Mcp-Session-Id。每个请求都自包含,授权规范要求每个 HTTP 请求都携带 bearer token。伪代码假设使用 JWT access token,因为这份参考设计依赖已验证的 claim;MCP 并不强制 JWT。使用不透明 token 时,应通过 introspection 或可信网关获得等价且经过验证的 issuer、受众、scope 与租户上下文。

服务器如何在不泄露令牌的情况下访问下游 API?

如果 MCP 服务器需要调用下游 API,它就作为该 API 的 OAuth 客户端,使用一个为该 API 签发的独立令牌。规范告诉你不该做什么(不要透传进入的令牌),但把怎么做留给了生态。一个标准化选项是 RFC 8693 定义的令牌交换:服务器把受众为 MCP 服务器的进入令牌,换成一个受众为下游 API 的新令牌。

服务器在这里扮演双重角色:对客户端是资源服务器,对 API 是 OAuth 客户端。优先选择委托而非冒充,这样原始用户留在 sub claim 里,行动链记录在 act claim 里,正是这一点让你的审计轨迹在跨越这一跳后仍然诚实。令牌交换与 on-behalf-of 流程都在 MCP 核心规范之外,所以把它们当作身份提供方或网关的职责,而不是 MCP 的要求。

多租户参考架构长什么样?

这就是拓扑。一个身份提供方签发绑定受众的令牌,每个租户一个 realm。客户端把这些令牌出示给企业信任边界内一台共享的资源服务器或网关。服务器校验受众、执行按工具的 scope、锁定租户 realm,然后才触达工具、数据和下游 API,每一项都按租户隔离。

多租户 MCP 授权架构:各租户客户端从共享身份提供方获得绑定受众的令牌,出示给一台 MCP 网关,网关校验受众、执行按工具的 scope 并锁定租户 realm,再经 RFC 8693 令牌交换触达下游 API,同时数据面、凭据保险库与审计日志按租户隔离

大多数多租户文章的错误,是把隔离当成数据库问题。它不是。多租户必须在每一层执行,而租户身份来自经过验证的令牌 claim,绝不来自模型能影响的工具输入。下面这张表就是我们逐层走的清单。

隔离控制省略后的后果
身份按租户锁定 issuer 与 realm;拒绝其他 realm 的令牌租户 A 通过租户 B 的 realm 登录
令牌每个请求都校验受众(RFC 8707)与过期在别处签发的令牌被接受
Scope从 IdP 组和角色映射出的最小权限 scope只读角色执行了写操作
工具按租户层级与 scope 过滤可见工具智能体发现一个它无法安全使用的工具
凭据按租户的密钥放在保险库里,对模型和客户端不透明一个租户的 API key 服务了另一个租户
数据基于租户 claim 的行级安全跨租户读取行数据
审计按租户、不可变、带 correlation ID 的日志事故期间无法归因
Kevin Riedl

"租户身份是一个经过验证的令牌 claim。一旦它来自模型可以写入的工具参数,你的隔离就只是演戏。"

按工具的 scope 与 step-up 授权如何运作?

核心协议在 OAuth 层处理 scope,而不是按单个工具,所以真正的按工具授权要你自己在上面搭。规范给了你原语。从最小开始,避免像 allfull-access 这样的大杂烩 scope。当某个工具需要的权限超出当前令牌时,服务器应返回 403,并在 WWW-Authenticate: Bearer error="insufficient_scope" 中给出当前操作所需的全部 scope 和 resource_metadata URI。代表用户运行的客户端应请求这些 scope 与此前请求 scope 的并集,并限制重试次数。

实践中我们把身份提供方的组和 SCIM 角色映射到 scope,再让每个工具以一个所需 scope 为门槛。分析师角色带 invoices:read,能看到只读工具;它永远不带 ledger:write。这与我们在授权审查里用的是同一套纪律,也正是采购团队真正会去测的东西。

如何为 MCP 服务器加上企业 SSO?

有两种形态,选择决定了你大部分的运营成本。

第一种是每台服务器各自 OAuth:每台 MCP 服务器把它的 authorization_servers metadata 指向企业身份提供方。对一两台服务器很干净,到了机队规模就很重复。第二种是 MCP 网关:在所有服务器前放一个执行策略的统一入口,集中做发现、令牌校验、scope 映射、令牌交换和审计。对于跨多个租户运行许多服务器的企业,网关通常是正确答案,因为你有一个地方执行隔离,也有一个地方做审计。

关于协议:2026-07-28 修订版要求授权服务器提供 RFC 8414 metadata 或 OpenID Connect Discovery;客户端必须支持两种发现机制。Protected Resource Metadata 可以列出多个授权服务器,客户端选择其中一个,并必须按 issuer 分开保存凭据与令牌。MCP 没有原生 SAML 流程。纯 SAML 企业需要通过身份提供方或为 MCP 服务器提供 OAuth 或 OIDC 的 broker 搭桥。

如何治理客户端注册与凭据生命周期?

2026-07-28 修订版正式弃用 Dynamic Client Registration。支持全部选项的客户端应依次优先使用预注册凭据、授权服务器声明支持时的 Client ID Metadata Documents、仅为向后兼容保留的 DCR,最后才让用户输入客户端信息。保存的预注册或 DCR 凭据必须与创建它们的 issuer 绑定,不得在其他授权服务器上重复使用。获取 Client ID Metadata Documents 的授权服务器应防范 SSRF、精确校验 redirect URI,并对仅使用 localhost 的重定向明确警告。企业还应把注册绑定到租户,并让未知客户端进入管理员审核。

当前 MCP 规范规定,授权服务器应签发短寿命 access token,必须为公共客户端轮换 refresh token,也可以完全不签发 refresh token。客户端必须在传输和存储中保护 refresh token,不得把 access token 放进 URL query string,并在每个 HTTP 请求中发送 bearer token。以下是我们使用的起始默认值:

凭据典型寿命轮换
访问令牌(客户端到服务器)5 到 15 分钟用 refresh 令牌重新签发
Refresh 令牌(公共客户端)数小时到数天,滑动每次使用都轮换
下游令牌(RFC 8693)数分钟,按调用或按会话重新交换,不要大范围缓存
保险库中的按租户密钥长,但可吊销定期加上疑似泄露时

你必须捕获哪些审计事件?

核心规范没有专门的审计日志要求,但令牌透传的分析已经替你把理由说清了:透传会破坏审计轨迹,因为下游日志显示的是错误身份。在多租户系统里,审计就是你证明隔离生效的方式。把下面这些按租户记录,并带一个能挺过下游那一跳的 correlation ID。

  • 令牌校验结果:接受、因受众拒绝、因 issuer 拒绝、已过期。
  • 授权决策:调用了哪个工具、所需 scope、授予的 scope、放行或拒绝。
  • Step-up 事件:请求的 scope 与实际授予的子集。
  • 令牌交换:为哪个 subject 和 actor 签发了哪个下游受众。
  • 租户上下文:每条记录都带经过验证的租户 claim,好让一次查询能归因到一个租户、一个用户和一个工具。

按服务器、网关,还是托管身份:你怎么选?

给三种可行拓扑一张速用决策矩阵。

方式最适合成本
每台服务器各自 OAuth一两台服务器、单租户搭建成本低,规模上表现差
MCP 网关许多服务器或许多租户搭建成本较高,只有一个执行点
托管 IdP 集成你本来就在 Entra 或 Okta 里厂商锁定,合规最快

只要你排好顺序,从单租户服务器走到多租户并不是重写:先引入租户 claim 并锁定 issuer,把密钥搬进按租户的保险库,加上基于该 claim 的行级安全,再过滤工具可见性并打开按租户审计。每一步都能独立交付、独立测试。用对抗方式测试隔离:拿租户 A 的令牌去打租户 B 的数据,确认它在令牌层就被拒绝,而不仅仅是在查询层被过滤。

最终思考

MCP 授权规范为这套架构给出三项基础要求:以 OAuth 2.1 为框架、用 resource indicators 绑定受众的令牌、以及禁止令牌透传。其余对企业重要的一切,多租户隔离、按工具的 scope、委托的下游访问与审计,都在规范之上,由你来设计。把 MCP 服务器当成一台负责校验与执行的资源服务器,把租户身份放在一个经过验证的 claim 里,并记录足够多的信息来证明隔离生效。做到这些,MCP 服务器就不再是你智能体栈里最薄弱的一环。

来源与延伸阅读

独立验证前的安全加固

正在为独立渗透测试或客户安全审查准备应用?Wavect 会加固权限、密钥、故障路径与回归覆盖,并协助团队关闭发现的问题。

相关服务路径:

只收重要内容

关注与你相关的内容

每当我们发布新文章,你会收到一封简短邮件。你可以关注整个博客,也可以只选感兴趣的主题。

你希望接收哪些内容?
选择主题

免费、双重确认、不使用跟踪像素。

返回
Kevin Riedl

11 分钟 阅读 · 2026年7月23日
最近审核

下一篇

获取下一篇关于AI 与智能体的一线笔记

有新文章时发送一封简短邮件,不使用跟踪像素,也不发送填充内容。

免费、双重确认、不使用跟踪像素。