何时应该使用授权?
虽然 MCP 服务器的授权是 可选的,但在以下情况下强烈建议使用:- 您的服务器访问特定于用户的数据(电子邮件、文档、数据库)
- 您需要审计谁执行了哪些操作
- 您的服务器授予对其 API 的访问权限,这需要用户同意
- 您正在为具有严格访问控制的企业环境构建
- 您想要实施每个用户的速率限制或使用跟踪
授权流程:逐步指南
让我们 walkthrough 当客户端想要连接到受保护的 MCP 服务器时会发生什么:初始握手
当您的 MCP 客户端首次尝试连接时,您的服务器会响应 这告诉客户端 MCP 服务器需要授权,以及在哪里获取必要的信息来启动授权流程。
401 Unauthorized 并告诉客户端在哪里可以找到授权信息,这些信息捕获在 受保护资源元数据 (PRM) 文档 中。该文档由 MCP 服务器托管,遵循可预测的路径模式,并在 WWW-Authenticate header 中的 resource_metadata 参数中提供给客户端。受保护资源元数据发现
有了指向 PRM 文档的 URI 指针,客户端将获取元数据以了解授权服务器、支持的作用域和其他资源信息。数据通常封装在 JSON blob 中,类似于以下内容。您可以在 RFC 9728 第 3.2 节 中看到更全面的示例。
授权服务器发现
接下来,客户端通过获取其元数据来发现授权服务器可以做什么。如果 PRM 文档列出了多个授权服务器,客户端可以决定使用哪一个。选定授权服务器后,客户端将构建标准元数据 URI 并向 OpenID Connect (OIDC) 发现 或 OAuth 2.0 授权服务器元数据 端点(取决于授权服务器支持)发出请求,并检索另一组元数据属性,这将使其知道完成授权流程所需的端点。
客户端注册
处理好所有元数据后,客户端现在需要确保它已在授权服务器注册。这可以通过两种方式完成。首先,客户端可以与给定的授权服务器 预注册,在这种情况下,它可以拥有嵌入的客户端注册信息,用于完成授权流程。或者,客户端可以使用 动态客户端注册 (DCR) 向授权服务器动态注册自己。后一种场景需要授权服务器支持 DCR。如果授权服务器确实支持 DCR,客户端将向其信息发送请求到 如果注册成功,授权服务器将返回带有客户端注册信息的 JSON blob。
registration_endpoint:用户授权
客户端现在需要打开浏览器到 访问令牌是客户端将用于向 MCP 服务器验证请求的令牌。此步骤遵循标准 OAuth 2.1 授权代码与 PKCE 约定。
/authorize 端点,用户可以在那里登录并授予所需的权限。然后授权服务器将重定向回客户端,附带一个授权代码,客户端将其交换为令牌:实现示例
要开始实际实现,我们将使用托管在 Docker 容器中的 Keycloak 授权服务器。Keycloak 是一个开源授权服务器,可以轻松部署在本地进行测试和实验。 确保您下载并安装了 Docker Desktop。我们需要它来在我们的开发机器上部署 Keycloak。Keycloak 设置
从您的终端应用程序中,运行以下命令以启动 Keycloak 容器:8080 上运行,并具有一个 admin 用户和 admin 密码。
您将能够从浏览器中的 http://localhost:8080 访问 Keycloak 授权服务器。

mcp:tools 作用域。我们将使用它来访问 MCP 服务器上的所有工具。

mcp:tools 客户端作用域并点击 Mappers,然后点击 Configure a new mapper。选择 Audience。

audience-config。为 Included Custom Audience 添加一个值,设置为 http://localhost:3000。这将是我们测试服务器的 URI。
现在,导航到 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 设置。

- 转到 Clients。
- 点击 Create client。
- 为您的客户端提供一个唯一的 Client ID 并点击 Next。
- 启用 Client authentication 并点击 Next。
- 点击 Save。

MCP 服务器设置
我们现在将设置我们的 MCP 服务器以使用本地运行的 Keycloak 授权服务器。根据您的编程语言偏好,您可以使用支持的 MCP SDKs 之一。 出于我们的测试目的,我们将创建一个极其简单的 MCP 服务器,公开两个工具 - 一个用于加法,另一个用于乘法。服务器将需要授权才能访问这些工具。- TypeScript
- Python
- C#
您可以在 示例存储库 中查看完整的 TypeScript 项目。在运行下面的代码之前,确保您有一个包含以下内容的 运行服务器时,您可以通过提供 MCP 服务器端点将其添加到您的 MCP 客户端,例如 Visual Studio Code。有关在 TypeScript 中实现 MCP 服务器的更多详细信息,请参阅 TypeScript SDK 文档。
.env 文件:OAUTH_CLIENT_ID 和 OAUTH_CLIENT_SECRET 与我们之前创建的 MCP 服务器客户端相关联。除了实现 MCP 授权规范外,下面的服务器还通过 Keycloak 进行令牌内省,以确保它从客户端收到的令牌是有效的。它还实现了基本日志记录,以便您可以轻松诊断任何问题。测试 MCP 服务器
为了测试目的,我们将使用 Visual Studio Code,但任何支持 MCP 和新授权规范的客户端都适用。 按 Cmd + Shift + P 并选择 MCP: Add server…。选择 HTTP 并输入http://localhost:3000。给服务器起一个在 Visual Studio Code 内部使用的唯一名称。在 mcp.json 中你现在应该能看到如下条目:
mcp:tools 权限范围。

mcp.json 中的服务器条目正上方看到列出的工具。

# 符号调用单个工具。

常见陷阱及如何避免
为了获得全面的安全指导,包括攻击向量、缓解策略和实施最佳实践,请务必阅读 安全最佳实践。下面列出了一些关键问题。- 不要自己实现令牌验证或授权逻辑。使用现成的、经过良好测试且安全的库来处理令牌验证或授权决策。从头开始做所有事情意味着除非你是安全专家,否则更有可能实现错误。
- 使用短寿命的访问令牌。根据使用的授权服务器,此设置可能是可定制的。我们建议不要使用长寿命令牌——如果恶意行为者窃取了它们,他们将能够维持更长时间的访问。
- 始终验证令牌。仅仅因为你的服务器收到了令牌并不意味着令牌是有效的或它是发给你的服务器的。始终验证你的 MCP 服务器从客户端收到的内容是否符合所需的约束。
- 将令牌存储在安全的加密存储中。在某些场景中,你可能需要在服务器端缓存令牌。如果是这种情况,请确保存储具有正确的访问控制,并且不能被拥有服务器访问权限的恶意方轻易外泄。你还应该实施强大的缓存驱逐策略,以确保你的 MCP 服务器不会重用过期或其他无效的令牌。
- 在生产环境中强制使用 HTTPS。除了在开发期间针对
localhost外,不要通过纯 HTTP 接受令牌或重定向回调。 - 最小权限范围。不要使用全包权限范围。尽可能按工具或能力拆分访问权限,并在资源服务器上按路由/工具验证所需的权限范围。
- 不要记录凭证。永远不要记录
Authorization头、令牌、代码或密钥。清理查询字符串和头。在结构化日志中脱敏敏感字段。 - 分离应用与资源服务器凭证。不要将 MCP 服务器的客户端密钥用于最终用户流程。将所有密钥存储在适当的密钥管理器中,而不是源代码控制中。
- 返回适当的质询。在 401 上,包含
WWW-Authenticate以及Bearer、realm和resource_metadata,以便客户端可以发现如何进行身份验证。 - DCR(动态客户端注册)控制。如果启用,请注意特定于你组织的约束,例如受信任的主机、所需的审查和审计注册。未经身份验证的 DCR 意味着任何人都可以向你的授权服务器注册任何客户端。
- 多租户/域混淆。固定到单个发行者/租户,除非明确是多租户。即使由同一授权服务器签名,也要拒绝来自其他域的令牌。
- 受众/资源指示器误用。不要配置或接受通用受众(如
api)或不相关的资源。要求受众/资源与你配置的服务器匹配。 - 错误细节泄露。向客户端返回通用消息,但在内部记录带有关联 ID 的详细原因,以帮助故障排除而不暴露内部细节。
- 会话标识符加固。将
Mcp-Session-Id视为不可信的输入;永远不要将授权与其绑定。在身份验证更改时重新生成并在服务器端验证生命周期。