使用 Microsoft Entra ID 保护模型上下文协议 (MCP) 服务器

模型上下文协议(MCP)允许 AI 代理和其他客户端调用从 MCP 服务器公开的工具和数据源。 由于 MCP 服务器可以代表用户或自治代理进行操作,因此应像任何其他 API 一样对其进行保护:在每个请求上都需要 OAuth 2.0 访问令牌,并在运行工具之前验证该令牌。

本文介绍如何将Microsoft Entra ID配置为 MCP 服务器的授权服务器,注册服务器,以便 MCP 客户端可以为其请求令牌,并使用Microsoft Entra 智能体 ID连接 MCP 客户端。

Important

不要从头开始编写自己的令牌验证逻辑。 令牌验证漏洞可能会在不知不觉中使你的 MCP 服务器暴露给未经授权的调用方。 为你的平台使用经过充分测试的身份验证库或中间件,并遵循 在 MCP 服务器中验证访问令牌 中链接的权威指引。

先决条件

MCP 授权如何与Microsoft Entra ID配合使用

在 MCP 授权模型中:

  • MCP 服务器是受 OAuth 2.0 保护的资源。
  • Microsoft Entra ID是颁发访问令牌的授权服务器。
  • MCP 客户端(例如代理)是请求令牌并将其呈现给服务器的客户端。

MCP 规范要求客户端在其令牌请求中发送 resource 参数(从 RFC 8707)来标识它想要令牌的受保护资源。 resource值是 MCP 服务器的规范 URL。 Microsoft Entra ID 会将该 resource 值与在 MCP 服务器的应用注册中配置的 应用程序 ID URI(也称为标识符 URI)进行比较。 如果二者匹配,Microsoft Entra ID 会颁发一个令牌,其受众(aud)声明为你的 MCP 服务器。 如果不匹配,令牌请求将失败。

要使此匹配有效,MCP 服务器必须接受 v2 访问令牌。 有关配置访问令牌版本的确切步骤,请参阅Microsoft Entra ID中注册 MCP 服务器。

端到端流程如下所示:

  1. MCP 客户端会发现服务器的授权要求。 当收到未经身份验证的请求时,你的服务器会返回HTTP 401,并附带一个WWW-Authenticate标头,该标头指向受保护资源元数据(RFC 9728),该元数据进而将Microsoft Entra ID标识为授权服务器。
  2. MCP 客户端向 Microsoft Entra ID 请求访问令牌,并发送 resource=<your MCP server URL>。
  3. Microsoft Entra ID 会验证该请求,将 resource 与你的应用注册中的应用程序 ID URI 进行匹配,并颁发作用域限定为你的服务器的 v2 访问令牌。
  4. MCP 客户端使用标头中的 Authorization: Bearer 令牌调用 MCP 服务器。
  5. MCP 服务器会验证令牌,如果令牌有效,请运行请求的工具。

在 Microsoft Entra ID 中注册 MCP 服务器

将 MCP 服务器注册为应用程序,以便Microsoft Entra ID可以为其颁发令牌。

如果 MCP 服务器由已由 Entra 保护的现有 Web 服务或 REST API 提供服务,则可以重复使用其现有应用注册及其 OAuth 范围。

以下步骤的顺序很重要:必须先启用 v2 访问令牌, 然后 才能设置与服务器 URL 匹配的 HTTPS 应用程序 ID URI。

步骤 1:创建应用注册

  1. 登录到 Microsoft Entra 管理中心。
  2. 导航至 Entra ID>应用注册>新注册。
  3. 输入 MCP 服务器的名称,例如 Contoso MCP server,然后选择“ 注册”。

步骤 2:将访问令牌版本设置为 v2

这是大多数人错过的步骤。 应用注册必须通过在2中将设置为requestedAccessTokenVersion来请求 v2 访问令牌。

  1. 在应用注册中,选择“Manifest”。

  2. 在api对象中,将requestedAccessTokenVersion设置为2:

    "api": {
        "requestedAccessTokenVersion": 2
    }
    
  3. 选择“保存”。

注释

如果跳过此步骤并将应用保留在 v1 访问令牌上,则无法设置与 MCP 服务器 URL 匹配的 HTTPS 应用程序 ID URI,以及发送 resource=<your MCP server URL> 接收错误的 MCP 客户端。 请参阅 常见问题解答和故障排除。

步骤 3:将应用程序 ID URI 设置为 MCP 服务器 URL

应用发出 v2 访问令牌后,将应用程序 ID URI 设置为 MCP 服务器的确切规范 URL。 此值是 MCP 客户端在参数中 resource 发送的内容。

  1. 在应用注册中,选择“ 公开 API”。
  2. 在 应用程序 ID URI 旁边,选择 “添加 ”(或 “编辑”),然后输入 MCP 服务器的 URL,例如 https://mcp.contoso.com。
  3. 选择“保存”。

或者,直接在清单中设置 identifierUris 。 该 identifierUris 属性是一个列表,因此,如果 MCP 服务器可访问多个 URL,请添加客户端可能使用的每个 URL。 客户端通常会将连接到的 URL 作为其resource值发送,并且Microsoft Entra ID仅在该值与其中一个已注册的应用程序 ID URI 完全匹配时颁发令牌。

"identifierUris": [
    "https://mcp.contoso.com",
    "https://mcp.contoso.com/mcp",
    "https://contoso-mcp.chinacloudsites.cn"
]

步骤 4:定义范围

委托范围允许代表已登录用户行事的 MCP 客户端仅请求其所需的访问权限级别。 如果 MCP 服务器为交互式客户端提供服务,请定义至少一个 OAuth 范围,以便客户端可以请求服务器的令牌,用户或管理员可以同意该令牌。

  1. 在应用注册中,选择“ 公开 API”。
  2. 选择添加范围。
  3. 输入反映服务器公开的操作的范围名称,例如 tool.read 或 tool.execute。
  4. 选择谁可以同意(仅限管理员或 管理员和用户),输入同意显示名称和说明,将状态设置为 “已启用”,然后选择“ 添加范围”。

然后,MCP 客户端请求完全限定的范围,该范围结合了应用程序 ID URI 和范围名称,例如 https://mcp.contoso.com/tool.execute。

根据需要定义任意数量的 OAuth 范围,以提供对 MCP 服务器的精细访问。

步骤 5 (可选):定义应用角色

除了代表用户执行操作外,MCP 客户端还可以作为代理标识进行身份验证。 若要请求访问令牌作为代理标识,MCP 客户端发送 OAuth 客户端凭据授予请求并使用范围值,例如 scope=https://mcp.contoso.com/.default。

Entra 应用角色 可用于限制 MCP 客户端对 MCP 服务器的访问。 你将应用角色分配给 MCP 客户端的代理身份。 分配的角色显示在 roles 访问令牌的声明中,服务器会在运行工具之前检查该声明。

  1. 在应用注册中,选择 “应用角色>创建应用角色”。
  2. 输入显示名称和值,例如 Tools.Execute.All,将 “允许的成员类型 ”设置为 “应用程序”,并启用角色。
  3. 将该角色分配给调用您的服务器的代理身份(或其他客户端应用程序)。

有关详细信息,请参阅 添加应用角色并在令牌中接收它们。

发布受保护的资源元数据

MCP 客户端通过读取其 OAuth 2.0 受保护的资源元数据(PRM) 文档,了解如何向服务器进行身份验证。 MCP 授权规范要求每个 HTTP MCP 服务器都提供一个 PRM 文档,并在其 WWW-Authenticate 响应的 401 标头中引用该文档。 本文档告知客户端应使用哪个授权服务器(Microsoft Entra ID),以及应为哪个资源标识符请求令牌。

从您的服务器 URL 派生出的众所周知路径提供该文档的 JSON 表示,例如 https://mcp.contoso.com/.well-known/oauth-protected-resource。 对于受Microsoft Entra ID保护的服务器,它应如下所示:

{
  "resource": "https://mcp.contoso.com",
  "authorization_servers": [
    "https://login.partner.microsoftonline.cn/<tenant-id>/v2.0"
  ],
  "scopes_supported": [
    "tools.read",
    "tools.execute"
  ],
  "bearer_methods_supported": ["header"]
}

按如下所示设置字段:

  • resource — MCP 服务器的规范 URL。 此值必须与 在步骤 3 中注册的应用程序 ID URI 和 resource 客户端发送的参数相同。 如果服务器公开了多个 URL,则每个 PRM 文档描述一个特定的 URL,客户端请求其连接到的 URL 的元数据。
  • authorization_servers — 你的租户的 Microsoft Entra ID 颁发者,https://login.partner.microsoftonline.cn/<tenant-id>/v2.0。 客户端针对该颁发者执行授权服务器元数据发现(例如在 https://login.partner.microsoftonline.cn/<tenant-id>/v2.0/.well-known/openid-configuration 处),以获取 Entra 的授权端点和令牌端点。 使用租户 ID 或已验证的域;仅对多租户服务器使用 organizations 或 common 代替租户 ID。
  • scopes_supported - 可选。 列出 在步骤 4 中定义的委托范围。 客户端使用这些来决定当scope质询未指定WWW-Authenticate时要请求什么。
  • bearer_methods_supported - 设置为 ["header"] 因为服务器需要请求标头中的 Authorization: Bearer 令牌。

Important

authorization_servers 值必须是 v2.0 颁发者(.../v2.0),并且与服务器接受的 v2 访问令牌中的 iss 声明相匹配(请参阅 步骤 2)。 v1 颁发者(https://sts.chinacloudapi.cn/<tenant-id>/)与客户端发现的 v2.0 授权服务器元数据不匹配。

对于未经身份验证的请求,返回一个 401 响应,其 WWW-Authenticate 标头指向此文档。 (可选)包括一个 scope 参数来告知客户端当前操作需要的范围:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.contoso.com/.well-known/oauth-protected-resource", scope="tools.execute"

如果您使用官方 MCP SDK 或 Azure 应用服务 身份验证,则平台可以为您生成并提供此文档和 401 质询内容。 请参阅 MCP 服务器中的“验证访问令牌”。

验证 MCP 服务器中的访问令牌

在每个请求中,MCP 服务器必须在运行工具之前验证访问令牌。 至少,验证令牌的 签名、 颁发者 (iss)、 租户 ID (tid)、 受众 (aud必须等于 MCP 服务器的应用程序 ID)和到期时间。 然后,检查令牌的主体(sub 或 oid)是否已获得执行所请求操作的授权,可使用 角色(roles)声明或其他授权检查来判断。 对于委派访问令牌,还请务必检查 scope(scp)声明,以确认调用方/参与方已获授权执行所请求的操作。

为了避免引入安全漏洞,请不要手动实施这些检查。 使用以下事实来源文章中的指南和库:

使用 Microsoft Entra 智能体 ID 连接 MCP 客户端

当 MCP 客户端是 AI 代理时,请使用Microsoft Entra 智能体 ID,以便代理使用自己的标识而不是嵌入式机密进行身份验证。 代理为 MCP 服务器获取令牌,并在每次调用中显示令牌。

  1. 设置代理的身份。 请参阅在代理中创建和删除代理标识和身份验证协议。
  2. 通过同意在 步骤 4 中定义的委派范围或分配在 步骤 5 中定义的应用角色,授予代理对 MCP 服务器的访问权限。
  3. 让代理为你的 MCP 服务器获取令牌。 客户端发送 resource=<your MCP server URL> (根据 MCP 规范)并请求相应的 OAuth 范围。
  4. 代理使用标头中的 Authorization: Bearer 令牌调用 MCP 服务器。 服务器会验证它,如 MCP 服务器中的“验证访问令牌”中所述。

有关代理如何调用受保护资源的更广泛视图,请参阅 使用代理 ID 配置第三方代理 ,并从 代理调用自定义 API。

常见问题解答和故障排除

我的 MCP 服务器应该使用 v1 或 v2 访问令牌吗?

使用 v2 访问令牌。 按照 2 中所述,将 MCP 服务器的应用注册中的 设置为 requestedAccessTokenVersion。 MCP 授权依赖于将客户端 resource 的参数与 HTTPS 应用程序 ID URI 匹配,并且该配置需要 v2 令牌。

当客户端为我的 MCP 服务器请求令牌时,我收到 AADSTS9010010 错误

AADSTS9010010 表示 在应用注册上配置的应用程序 ID URI 与客户端 OAuth 请求中的参数值 resource 不完全匹配 。 要修复此问题,请执行以下操作:

  1. 检查是否存在末尾斜杠或其他精确匹配差异。 客户端发送的 resource 值必须与 Application ID URI 逐字符完全匹配,包括方案 (https://)、主机名的大小写以及路径。 末尾斜杠是一个常见的罪魁祸首:由于应用程序 ID URI 不能以斜杠结尾,因此发送 resource=https://mcp.contoso.com/ 的客户端永远无法匹配已注册的 https://mcp.contoso.com。 删除尾部斜杠(以及任何其他差异),使客户端 resource 的值和应用程序 ID URI 相同。
  2. 确认应用使用 v2 访问令牌。 如果未 requestedAccessTokenVersion 设置为 2,则无法注册与 MCP 服务器 URL 匹配的 HTTPS 应用程序 ID URI,因此 resource 该值永远无法匹配。 完成 步骤 2,然后在 步骤 3 中重新添加应用程序 ID URI。
  3. 请确保所请求的作用域与 属于同一个应用注册。 当客户端发送在 与 参数引用 resource 的范围不同的应用注册上定义的范围时,也会发生此错误。 Microsoft Entra ID 会将 resource 和作用域解析为同一个资源应用;如果它们指向不同的应用注册,请求就会失败。 确认客户端请求的每个作用域都由你在 resource 中发送其 Application ID URI 的应用注册公开,并删除任何属于其他应用的作用域。

如果我无法使用 v2 访问令牌,该怎么办?

某些 MCP 服务器重复使用现有的应用注册,该注册已向其他客户端颁发 v1 访问令牌,并且无法在不中断这些客户端的情况下切换到 v2 令牌。 在这种情况下,可以保留 v1 令牌,转而通过使用 auduse_guid 配置 aud可选声明,使 声明具有确定性。

默认情况下,audv1 访问令牌中的声明是不确定的 — Microsoft Entra ID可以发出任何应用的应用程序 ID URI(包含或不带尾部斜杠)或资源的客户端 ID。 设置use_guid强制aud始终是采用 GUID 格式的资源客户端 ID。 由于受众不再绑定到特定的应用程序 ID URI,因此Microsoft Entra ID放宽应用的应用程序 ID URI 限制,因此即使应用仍颁发 v1 令牌,也可以将 MCP 服务器的 HTTPS URL 添加为应用程序 ID URI(步骤 3)。 然后,客户端可以发送和接收 resource=<your MCP server URL> 令牌。

将可选声明添加到应用注册的清单文件中:

"optionalClaims": {
    "accessToken": [
        {
            "name": "aud",
            "additionalProperties": ["use_guid"]
        }
    ]
}

设置 use_guid 后,令牌的 aud 声明是你的资源的 客户端 ID(GUID),而不是你的 MCP 服务器 URL。 将 MCP 服务器(或验证令牌的中间件或 MCP SDK)配置为将该客户端 ID GUID 视为受众。 只要可以迁移到 v2 令牌,就应优先采用这种方式(步骤 2),因为 v2 的 aud 声明字段始终是该资源的客户端 ID,并且与 MCP 客户端所发现的授权服务器元数据一致。