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

mcp:tools 作用域。我们将使用它来访问 MCP 服务器上的所有工具。
mcp:tools 客户端作用域,点击 Mappers(映射器),然后点击 Configure a new mapper(配置新映射器)。选择 Audience。
audience-config。在 Included Custom Audience 中添加一个值,设置为 https://:3000。这将是我们测试服务器的 URI。
现在,导航到 Clients(客户端),然后是 Client registration(客户端注册),最后是 Trusted Hosts(信任主机)。禁用 Client URIs Must Match(客户端 URI 必须匹配)设置,并添加您正在进行测试的主机。您可以通过在 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 SDK 之一。 为了测试目的,我们将创建一个极其简单的 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 并输入https://:3000。给服务器起一个在 Visual Studio Code 内部使用的唯一名称。在 mcp.json 中,您现在应该看到如下条目:mcp:tools 作用域。

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

# 符号来调用各个工具。

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