Skip to main content
模型上下文协议(Model Context Protocol,MCP)中的授权保护对 MCP 服务器所暴露的敏感资源和操作的访问。如果你的 MCP 服务器处理用户数据或管理操作,授权确保只有获得许可的用户才能访问其端点。 MCP 使用标准化的授权流程在 MCP 客户端与 MCP 服务器之间建立信任。它的设计并不聚焦于某个特定的授权或身份系统,而是遵循 OAuth 2.1 所概述的惯例。详细信息参见授权规范

你应该何时使用授权?

虽然 MCP 服务器的授权是可选的,但在以下情况下强烈建议使用:
  • 你的服务器访问用户特定的数据(邮件、文档、数据库)
  • 你需要审计谁执行了哪些操作
  • 你的服务器授予对其需要用户同意的 API 的访问权限
  • 你正在为具有严格访问控制的企业环境构建
  • 你想要按用户实现速率限制或使用跟踪
本地 MCP 服务器的授权对于使用 STDIO 传输的 MCP 服务器,你可以改用基于环境的凭据,或由直接嵌入 MCP 服务器的第三方库提供的凭据。因为基于 STDIO 构建的 MCP 服务器在本地运行,它在获取用户凭据时可以使用一系列灵活的选项,这些选项可能依赖也可能不依赖浏览器内的认证和授权流程。而 OAuth 流程则是为基于 HTTP 的传输设计的,其中 MCP 服务器是远程托管的,客户端使用 OAuth 来确立用户已获授权访问该远程服务器。

授权流程:逐步分解

让我们逐步了解当客户端想要连接到你受保护的 MCP 服务器时会发生什么:
1

初始握手

当你的 MCP 客户端首次尝试连接时,你的服务器以一个 401 Unauthorized 响应,并告诉客户端在哪里找到授权信息,这些信息被记录在一个受保护资源元数据(Protected Resource Metadata,PRM)文档中。该文档由 MCP 服务器托管,遵循一个可预测的路径模式,并在 WWW-Authenticate header 内的 resource_metadata 参数中提供给客户端。
这告诉客户端 MCP 服务器需要授权,以及在哪里获取启动授权流程所需的信息。
2

受保护资源元数据发现

有了指向 PRM 文档的 URI 指针,客户端会获取该元数据以了解授权服务器、所支持的 scope 和其他资源信息。数据通常封装在一个 JSON blob 中,类似于下面这个。
你可以在 RFC 9728 第 3.2 节中看到一个更全面的示例。
3

授权服务器发现

接下来,客户端通过获取授权服务器的元数据来发现它能做什么。如果 PRM 文档列出了多于一个授权服务器,客户端可以决定使用哪一个。选定授权服务器后,客户端随后会构造一个标准的元数据 URI,并向 OpenID Connect (OIDC) DiscoveryOAuth 2.0 Auth Server Metadata 端点(取决于授权服务器的支持)发出请求,并检索另一组元数据属性,这些属性将让它知道完成授权流程所需的端点。
4

客户端注册

处理完所有元数据后,客户端现在需要确保它已在授权服务器上注册。这可以通过两种方式完成。首先,客户端可以与给定的授权服务器预注册,在这种情况下,它可以拥有嵌入的客户端注册信息,用于完成授权流程。另外,客户端可以使用**动态客户端注册(Dynamic Client Registration,DCR)**来动态地向授权服务器注册自己。后一种情形要求授权服务器支持 DCR。如果授权服务器确实支持 DCR,客户端会带着它的信息向 registration_endpoint 发送一个请求:
如果注册成功,授权服务器将返回一个带有客户端注册信息的 JSON blob。
没有 DCR 或预注册如果一个 MCP 客户端连接到一个 MCP 服务器,而该服务器使用的授权服务器不支持 DCR,且客户端未与该授权服务器预注册,那么由客户端开发者负责为最终用户提供一个手动输入客户端信息的可用方式(affordance)。
5

用户授权

客户端现在需要打开一个浏览器到 /authorize 端点,用户可以在那里登录并授予所需的权限。授权服务器随后会带着一个授权码重定向回客户端,客户端将其交换为令牌:
访问令牌是客户端用来向 MCP 服务器认证请求的东西。此步骤遵循标准的 带 PKCE 的 OAuth 2.1 授权码惯例。
6

发起已认证的请求

最后,客户端可以使用嵌入在 Authorization header 中的访问令牌向你的 MCP 服务器发起请求:
MCP 服务器需要校验令牌,并在令牌有效且具有所需权限时处理该请求。

实现示例

为了开始一个实际的实现,我们将使用一个托管在 Docker 容器中的 Keycloak 授权服务器。Keycloak 是一个开源的授权服务器,可以轻松地在本地部署以进行测试和实验。 请确保你下载并安装了 Docker Desktop。我们需要它在开发机器上部署 Keycloak。

Keycloak 设置

从你的终端应用运行以下命令来启动 Keycloak 容器:
此命令会在本地拉取 Keycloak 容器镜像并引导(bootstrap)基本配置。它将运行在端口 8080 上,并有一个密码为 adminadmin 用户。
不用于生产上面的配置可能适合测试和实验;然而,你绝不应在生产中使用它。有关如何为需要可靠性、安全性和高可用性的场景部署授权服务器的更多细节,请参阅为生产配置 Keycloak 指南。
你将能够从浏览器在 http://localhost:8080 访问 Keycloak 授权服务器。
Keycloak 管理后台的认证对话框。
当以默认配置运行时,Keycloak 将已经支持我们 MCP 服务器所需的许多能力,包括动态客户端注册。你可以通过查看 OIDC 配置来核实这一点,该配置位于:
我们还需要设置 Keycloak 以支持我们的 scope,并允许我们的主机(本地机器)动态注册客户端,因为默认策略限制匿名动态客户端注册。 在 Keycloak 后台前往 Client scopes 并创建一个新的 mcp:tools scope。我们将用它来访问 MCP 服务器上的所有工具。
配置 Keycloak scope。
创建 scope 后,请确保将其类型指定为 Default,并已打开 Include in token scope 开关,因为这将是令牌校验所需的。 现在让我们也为 Keycloak 签发的令牌设置一个 audience。配置 audience 很重要,因为它将预期的目的地直接嵌入到签发的访问令牌中。这有助于你的 MCP 服务器验证它拿到的令牌确实是为它准备的,而不是为某个其他 API。这是帮助避免令牌透传(token passthrough)情形的关键。 为此,打开你的 mcp:tools client scope 并点击 Mappers,接着点击 Configure a new mapper。选择 Audience
在 Keycloak 中为令牌配置 audience。
对于 Name,使用 audience-config。为 Included Custom Audience 添加一个值,设为 http://localhost:3000。这将是我们测试服务器的 URI。
不用于生产上面的 audience 配置用于测试。对于生产场景,将需要额外的设置和配置,以确保为签发的令牌正确地约束 audience。具体而言,audience 需要基于从客户端传来的 resource 参数,而不是一个固定值。
现在,导航到 Clients,然后是 Client registration,然后是 Trusted Hosts。禁用 Client URIs Must Match 设置,并添加你进行测试的主机。你可以在 Linux 或 macOS 上运行 ifconfig 命令,或在 Windows 上运行 ipconfig,来获取你当前的主机 IP。你可以通过查看 keycloak 日志中类似 Failed to verify remote host : 192.168.215.1 的一行,来看到你需要添加的 IP 地址。检查该 IP 地址与你的主机关联。取决于你的 docker 设置,这可能是一个桥接网络的地址。
在 Keycloak 中设置客户端注册详情。
获取主机如果你从容器运行 Keycloak,你还将能够从终端的容器日志中看到主机 IP。
最后,我们需要注册一个新客户端,用于让 MCP 服务器本身与 Keycloak 通信以进行诸如令牌自省(token introspection)之类的操作。为此:
  1. 前往 Clients
  2. 点击 Create client
  3. 给你的客户端一个唯一的 Client ID 并点击 Next
  4. 启用 Client authentication 并点击 Next
  5. 点击 Save
值得注意的是,令牌自省只是校验令牌的可用方法_之一_。这也可以借助各语言和平台特定的独立库来完成。 当你打开客户端详情时,前往 Credentials 并记下 Client Secret
在 Keycloak 中创建一个新客户端。
处理密钥切勿将客户端凭据直接嵌入你的代码。我们建议使用环境变量或专门的密钥存储解决方案。
配置好 Keycloak 后,每次触发授权流程时,你的 MCP 服务器都会收到一个像这样的令牌:
解码后,它会看起来像这样:
嵌入的 Audience注意嵌入在令牌中的 aud claim——它当前被设为测试 MCP 服务器的 URI,并从我们先前配置的 scope 推断而来。这在我们的实现中对于校验将很重要。

MCP 服务器设置

我们现在将设置 MCP 服务器以使用本地运行的 Keycloak 授权服务器。取决于你的编程语言偏好,你可以使用受支持的 MCP SDK 之一。 为了测试目的,我们将创建一个极其简单的 MCP 服务器,它暴露两个工具——一个用于加法,另一个用于乘法。服务器将要求授权才能访问这些工具。
你可以在示例仓库中看到完整的 TypeScript 项目。在运行下面的代码之前,请确保你有一个包含以下内容的 .env 文件:
OAUTH_CLIENT_IDOAUTH_CLIENT_SECRET 与我们先前创建的 MCP 服务器客户端关联。除了实现 MCP 授权规范之外,下面的服务器还通过 Keycloak 进行令牌自省,以确保它从客户端收到的令牌是有效的。它还实现了基本的日志记录,让你能够轻松诊断任何问题。
当你运行服务器时,你可以通过提供 MCP 服务器端点,将它添加到你的 MCP 客户端(例如 Visual Studio Code)。有关在 TypeScript 中实现 MCP 服务器的更多细节,参见 TypeScript SDK 文档

测试 MCP 服务器

为了测试目的,我们将使用 Visual Studio Code,但任何支持 MCP 和新授权规范的客户端都适用。 Cmd + Shift + P 并选择 MCP: Add server…。选择 HTTP 并输入 http://localhost:3000。给服务器一个在 Visual Studio Code 内部使用的唯一名称。在 mcp.json 中你现在应该看到一个像这样的条目:
连接时,你会被带到浏览器,在那里你会被提示同意 Visual Studio Code 访问 mcp:tools scope。
VS Code 的 Keycloak 同意表单。
同意后,你将在 mcp.json 中服务器条目的正上方看到列出的工具。
VS Code 中列出的工具。
你将能够在聊天视图中借助 # 符号调用单个工具。
在 VS Code 中调用 MCP 工具。

常见陷阱及如何避免它们

有关全面的安全指导,包括攻击向量、缓解策略和实现最佳实践,请务必通读安全最佳实践。下面点出几个关键问题。
  • 不要自己实现令牌校验或授权逻辑。对于令牌校验或授权决策之类的事情,使用现成的、经过充分测试的安全库。从头做一切意味着,除非你是安全专家,否则你更有可能实现得不正确。
  • 使用短期访问令牌。取决于所使用的授权服务器,此设置可能是可自定义的。我们建议不要使用长期令牌——如果恶意行为者窃取了它们,他们将能够在更长时间内维持其访问。
  • 始终校验令牌。你的服务器收到一个令牌,并不意味着该令牌是有效的,或者它是为你的服务器准备的。始终验证你的 MCP 服务器从客户端得到的内容符合所需的约束。
  • 将令牌存储在安全、加密的存储中。在某些场景中,你可能需要在服务器端缓存令牌。如果是这种情况,确保存储具有正确的访问控制,且不能被有权访问你服务器的恶意方轻易外泄。你还应实现健壮的缓存驱逐策略,以确保你的 MCP 服务器不会重复使用过期或以其他方式无效的令牌。
  • 在生产中强制 HTTPS。除了开发期间的 localhost,不要通过纯 HTTP 接受令牌或重定向回调。
  • 最小权限 scope。不要使用一网打尽的 scope。在可能的情况下按工具或能力拆分访问,并在资源服务器上按路由/工具验证所需的 scope。
  • 不要记录凭据。切勿记录 Authorization header、令牌、授权码或密钥。清洗查询字符串和 header。在结构化日志中编辑(redact)敏感字段。
  • 分离应用凭据与资源服务器凭据。不要将你 MCP 服务器的 client secret 重用于最终用户流程。将所有密钥存储在一个正规的密钥管理器中,而不是源代码控制里。
  • 返回正确的质询。在 401 时,包含带 Bearerrealmresource_metadataWWW-Authenticate,以便客户端可以发现如何认证。
  • DCR(动态客户端注册)控制。如果启用,注意你组织特定的约束,例如受信任的主机、必需的审查和被审计的注册。未认证的 DCR 意味着任何人都可以在你的授权服务器上注册任何客户端。
  • 多租户/realm 混淆。除非明确是多租户,否则锁定到单个 issuer/租户。拒绝来自其他 realm 的令牌,即使它们由同一个授权服务器签名。
  • Audience/resource indicator 滥用。不要配置或接受通用的 audience(如 api)或不相关的 resource。要求 audience/resource 与你配置的服务器匹配。
  • 错误细节泄露。向客户端返回通用消息,但在内部记录带相关性 ID 的详细原因,以便在不暴露内部机制的情况下帮助排查。
  • 会话标识符加固。将 Mcp-Session-Id 视为不受信任的输入;绝不将授权与它绑定。在认证变更时重新生成它,并在服务器端校验其生命周期。

相关标准和文档

MCP 授权建立在这些成熟的标准之上: 有关更多细节,参见: 理解这些标准将帮助你正确地实现授权,并在问题出现时排查它们。