跳到主要内容
版本:Latest(v3.0) 🔥

MCP Oauth2

1. 介绍

mcp-oauth2 是一个 Kong plugin/policy,通过 OAuth2/OIDC(通常与 Keycloak 一起使用)来保护 MCP HTTP endpoints

它提供:

  • 通过 /.well-known/oauth-protected-resource (RFC 9728) 提供 Client discovery,以便 MCP 客户端可以了解授权服务器和支持的范围。
  • JWT access-token validation:检查 iss(发行者)、aud(受众)和使用 JWKS 的签名。
  • (可选)通过将范围映射到允许的 MCP JSON-RPC 方法来提供 authorization by scope/role(例如,从像 mcp_scopes 这样的声明中)。

2. APIM 控制台设置

步骤 1:创建一个新的 API,后端设置为 MCP 服务器。

MCP 服务器 : http://wikipedia-mcp.default.svc.cluster.local:8080/mcp 

因为我们需要通过这个 API 从 VS Code 访问 MCP 服务器,而 VS Code 不支持带有额外路径段的 URL,所以我们将基础路径设置为 “/”(无路径)。

步骤 2:将 mcp-oauth2 策略应用于 API。

步骤 3:点击 mcp-oauth2 策略按钮以显示下面的配置详情。

Section 1: PROTECTED RESOURCE METADATA (RFC 9728)

FieldTypeRequiredDefaultDescription
Protected Resource Metadata PathstringYes/.well-known/oauth-protected-resource• 插件提供的 RFC 9728 受保护资源元数据文档的 URL 路径。
• MCP 客户端获取此信息以发现授权服务器和支持的范围。
• 几乎不需要更改。
Authorization Servers:
  • 一个受信任的授权服务器数组。每个 Keycloak 领域(或其他 OAuth2 提供者)为此 MCP 端点发放令牌时添加一个条目。
  • 点击 + 以添加更多条目。  | Field | Type | Required | Description | | --- | --- | --- | --- | | Url | string | Yes | • public URL of the authorization server(客户端进行身份验证/获取令牌的地方)。
    • 当 jwks_uri 是相对路径时,它也是 base URL for building the JWKS URL

    Example: https://keycloak-demo.apimags.skcloud.io/realms/master | | Issuer | string | Yes | • 与 JWT 中的 iss (发行者)声明匹配。
    • 如果令牌的发行者不匹配,则会被拒绝。
    • 必须是一个 exact string match • 包括协议、主机、端口和路径(没有尾部斜杠)。
    Find it at: <realm-url>/.well-known/openid-configuration → 发行者字段。 | | Audience | string | Yes | • 与 JWT 中的 aud (受众)声明匹配。
    • 防止其他服务的令牌被接受。 
    Must exactly match 在 Keycloak 受众映射器中配置的值。 | | JWKS URI | 字符串 | 是 | • 插件获取授权服务器的公共签名密钥(JWKS)以验证JWT签名的端点。
    • 可以是: Relative path (附加到Url):/.well-known/jwks.json Absolute URL (按原样使用):https://keycloak-demo.apimags.skcloud.io /realms/master/protocol/openid-connect/certs  当Kong无法通过与客户端相同的主机名访问授权服务器时,请使用绝对URL(例如,Docker/k8s网络)。  Default: /.well-known/jwks.json |
Section 2: SUPPORTED OAUTH2 SCOPES 

FieldTypeRequiredDefaultDescription
Scopes Supported字符串数组列在受保护资源元数据文档中,以告知客户端请求哪些范围。这是 informational only • 它指导客户端发现,但不强制执行任何内容。
输入每个范围并按 Enter 添加。

Example: mcp:tools
Section 3: TOKEN VALIDATION

FieldTypeRequiredDefaultDescription
Authorization Header Name字符串授权 • Authorization Header Name = 您的服务器/插件将读取的HTTP头名称,以查找用于令牌验证的访问令牌。
• 通常保持为 Authorization.
• 客户端然后发送令牌,如:Authorization: Bearer <access_token>
• 仅在您的API期望在不同的头中获取令牌时更改它
• (例如,X-Authorization)。

Section 4: UPSTREAM TOKEN FORWARDING 

FieldTypeRequiredDefaultDescription
Forward Authorization Header布尔值• 假 - 在转发到 MCP 服务器之前剥离授权头(更安全的默认值)。
• 真 - 将 Bearer <token> 头转发到上游 MCP 服务器。
• 如果您的 MCP 服务器需要读取令牌(例如,提取用户身份或声明),请启用。
Section 5: ACL

FieldTypeRequiredDefaultDescription
Enable ACL布尔值假 - 任何有效的令牌都可以访问所有 MCP 方法(仍然会进行令牌验证)。
真 - 在验证令牌后,插件还会检查令牌的作用域/角色,以决定特定的 JSON-RPC 方法是否被允许。
ACL Claim字符串作用域• 包含用户权限的 JWT 声明的名称。插件读取此声明并使用其值进行 ACL 检查。
• 常见值:
→ mcp_scopes - 来自 Keycloak 协议映射器的自定义声明

⚠️ 必须 exactly match 在 Keycloak 协议映射器中设置令牌声明名称。
Section 6: SCOPE METHOD MAPPING

将每个作用域/角色映射到允许调用的 MCP JSON-RPC 方法列表。仅在 Enable ACL 为真时有效

FieldTypeRequiredDescription
ScopestringYes (per entry)范围/角色名称。必须与JWT声明中指定的值匹配 ACL Claim.
Example: mcp:tools
Methodsarray of stringsYes (per entry)该范围允许调用的MCP JSON-RPC方法名称。输入每个方法名称并按 Enter 添加。
Example: tools/list, tools/call

⚠️ When ACL is enabled but Scope Method Mapping is empty: 所有请求被拒绝。您必须配置至少一个映射。

💡 Permissions are additive: 用户只需要一个允许该方法的范围。如果令牌中的任何范围允许该方法,则授予访问权限。

Section 7: TIMEOUTS & CACHING
FieldTypeRequiredDefaultDescription
Token Cache TTL (s)numberNo300验证的令牌在Kong的共享内存中缓存的时间(以秒为单位)。在此期间,使用相同令牌的重复请求跳过JWT解码和签名验证。
即使缓存,插件在每个请求上也会重新检查JWT exp 声明并使过期的令牌失效。
HTTP Timeout (ms)numberNo10000从授权服务器获取JWKS(公共签名密钥)的HTTP请求的超时(以毫秒为单位)。如果授权服务器在此时间内未响应,则令牌验证失败。

• 如果授权服务器在慢网络上或冷启动,请增加此值
• 如果授权服务器无法访问,请减少此值以加快失败速度

3. Keycloak 设置

3.1. Keycloak OAuth2 基础

这些步骤配置 Keycloak ,以便MCP客户端可以发现授权服务器并获取具有正确受众的令牌。

3.1.1 创建客户端范围

What this does: 创建一个客户端可以请求的命名范围。当客户端请求该范围时,Keycloak 会将其包含在令牌中 - 并且与此范围附加的任何映射器也会触发。

Step 1: Navigate to Keycloak Admin → Client scopes → Create client scope

Step 2: input data → Click Save.

FieldValueWhy
Namemcp:tools您的 MCP 客户端将请求的范围名称
ProtocolOpenID Connect标准 OAuth2/OIDC 协议
Display on consent screenON显示客户端在登录期间请求的内容
Consent screen text访问 MCP 工具用户可读的描述
Include in token scopeON确保范围值出现在 JWT 范围声明中

3.1.2 添加受众映射器

What this does: 向访问令牌添加一个 aud(受众)声明。该插件验证令牌的受众是否与其配置的值匹配 - 这防止为 other 服务发出的令牌被您的 MCP 端点接受。

Step 1: Navigate to The mcp:tools scope you just created → Mappers tab → Configure a new mapper → Select Audience

Step 2: input data → Click Save
FieldValueWhy
Nameaudience-config此映射器的描述性名称
Included Custom Audienceaudience-name必须与 Kong 插件配置中的受众字段匹配
Add to access token插件读取访问令牌,而不是ID令牌
Add to ID tokenID令牌是为客户端应用程序准备的,而不是资源服务器

3.1.3. 创建新客户端

What this does: 为MCP客户端创建一个连接到Keycloak的客户端。

Step 1: Navigate to Clients → Create client

Step 2: input data Client ID → Click Next.

FieldValueDescription
Client IDMcp-client客户端ID
Step 3: Config → Click Next.

Step 4: Config → Click Save.

3.2. Keycloak: 基于组的ACL设置

本节设置 fine-grained access control 以便不同用户获得不同的MCP权限。架构是:

组 → 领域角色 → 协议映射器 → "mcp_scopes" JWT声明 → ACL

3.2.1. 创建领域角色

What these are: 命名权限层级。每个角色代表用户被允许调用的一组MCP方法。角色名称将出现在JWT的mcp_scopes声明中。

Step 1: Navigate to: Realm roles → Create role (repeat for each)

Step 2: For each role, just fill in the Role name and click Save. No additional configuration needed.
Role NamePurposeExample MCP Methods
mcp:tools工具访问tools/list
mcp:resources资源访问resources/read

3.2.2. 创建组

What these are: 组织用户的容器。与其逐个用户分配角色,不如将角色分配给一个组,然后将用户添加到该组。

Step 1: Navigate to: GroupsCreate group

Step 2: To create a sub-group: Click on the parent group → Create child group
Group NameDescription
mcp-member基本成员访问
mcp-admin对所有 MCP 工具和资源的完全访问

3.2.3. 将角色分配给组

Step 1: Navigate to Groups → Click a group → Role mapping tab → Assign role
GroupRoles to Assign
Mcp-adminmcp:tools, mcp:resources
Mcp-membermcp:tools

点击 Assign

3.2.4. 创建协议映射器 (mcp_scopes 声明)

What this does: 告诉 Keycloak 在访问令牌中包含用户的领域角色(按 mcp: 前缀过滤),作为名为 mcp_scopes 的自定义声明。这是 Kong 插件读取以做出 ACL 决策的声明。 Step 4: Navigate to Client scopes → mcp:tools → Mappers tab → Add mapper → By configuration → Select User Realm Role

Step 2: input data

FieldValueWhy
Namemcp-scopes-mapper描述性名称
Mapper Type用户领域角色将用户的领域角色映射到令牌声明
Token Claim Namemcp_scopes必须与Kong插件配置中的acl_claim匹配
Multivalued用户可以拥有多个角色
Add to access token插件读取访问令牌
Add to ID token不需要进行资源服务器验证
Add to userinfo不需要

 Critical: Token Claim Name (mcp_scopes) 必须 exactly match Kong插件配置中的acl_claim字段。 不匹配意味着插件无法在令牌中找到权限。

3.2.5. 添加用户到组

Step 1: Navigate to Users → Click on a user → Groups tab → Join group → Select the appropriate group

Step 2: Click Join
UserGroupResulting JWT mcp_scopes
canhng1Mcp-memberMcp:tools, Mcp:resources
adminmcp-adminMcp:resources

4. 使用Visual Studio Code进行测试

4.1. 将Kong代理转发到本地

4.2. 创建新的 MCP 服务器

打开 Vs Code,按 Ctrl + Shift + P 并选择 MCP: Add server…. 选择 HTTP 并输入 http://localhost:8100. 给服务器一个在 Visual Studio Code 中使用的唯一名称。在 mcp.json 中你现在应该能看到类似这样的条目:

4.3. 启动服务器并使用 Keyloak 认证连接到模拟 MCP 服务器

登录成功并连接到模拟 MCP 服务器,使用了 22 个工具。