fix(oauth): use Protected Resource Metadata scopes in MCP DCR flow

The Dynamic Client Registration flow seeded the registration request
`scope` from the Authorization Server's `scopes_supported` (RFC 8414),
which is a full catalog of every scope the AS can grant across all
resources. Per RFC 9728 and the MCP Scope Selection Strategy, the
resource-specific Protected Resource Metadata `scopes_supported` is the
correct, least-privilege source.

The PRM is already fetched in this function; this change prefers its
`scopes_supported` and keeps the AS `scopes_supported` only as a
fallback when the PRM advertises none. Mirrors the static-credentials
fix in #24690.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jian-Min Lin 2026-06-11 22:17:16 +08:00
parent b1d40f3409
commit beb38e255f

View file

@ -435,6 +435,17 @@ async def get_oauth_client_info_with_dynamic_client_registration(
# Attempt to fetch OAuth server metadata to get registration endpoint & scopes
resource_metadata = await get_protected_resource_metadata(oauth_server_url)
resource = resource_metadata.resource
# Prefer the resource-specific scopes from the Protected Resource Metadata
# (RFC 9728 Section 2) over the Authorization Server's scopes_supported
# (RFC 8414 Section 2). The AS scopes_supported is a full catalog of every
# scope the server can grant across all resources, whereas the PRM
# scopes_supported represents what this specific resource requires - making
# it the correct, least-privilege source. This mirrors the static-credentials
# flow (see #24690).
if resource_metadata.scopes_supported:
oauth_client_metadata.scope = ' '.join(resource_metadata.scopes_supported)
discovery_urls = resource_metadata.get_discovery_urls(oauth_server_url)
for url in discovery_urls:
async with aiohttp.ClientSession(trust_env=True) as session: