modelcontextprotocol / modelcontextprotocol/python-sdk

Allow `OAuthClientProvider` to accept a pre-configured auth server URL

Abierto
#2,121 0 comentarios 0 reacciones 1 asignado Ver en GitHub

@pcarleton ya está trabajando en esto.

Desde el 5/3/2026.

auth enhancement needs confirmation
Lenguaje dominante
Python
Estrellas
24.3k
Forks
4k
Merge medio
1 d 1 h
PR fusionados (30 d)
31

Descripción

Description

Problem

OAuthClientProvider.async_auth_flow in mcp/client/auth/oauth2.py only triggers OAuth discovery when it receives a 401 response. There's no way to tell the client "I already know where the auth server is — skip straight to OASM discovery and token exchange."

This forces an unnecessary round-trip in environments where the authorization server URL is already known (config file, env var, service registry, etc.).

Current behavior

In OAuthClientProvider.__init__:

OAuthClientProvider(
    server_url="http://mcp-server:3002/mcp",
    client_metadata=OAuthClientMetadata(...),
    storage=my_storage,
    redirect_handler=...,
    callback_handler=...,
)

Then inside async_auth_flow (line ~500):

response = yield request  # unauthenticated

if response.status_code == 401:
    # Only NOW does it start discovery:
    # 1. Extract WWW-Authenticate
    # 2. Discover PRM (/.well-known/oauth-protected-resource)
    # 3. Set self.context.auth_server_url from PRM
    # 4. Discover OASM (/.well-known/oauth-authorization-server)
    # 5. Register client (DCR or CIMD)
    # 6. Authorization code + PKCE
    # 7. Retry with token

Steps 1–3 exist purely to resolve auth_server_url. When the caller already has that URL, they're wasted work.

Proposed change

Add an optional authorization_server_url parameter to OAuthClientProvider.__init__:

OAuthClientProvider(
    server_url="http://mcp-server:3002/mcp",
    client_metadata=OAuthClientMetadata(...),
    storage=my_storage,
    redirect_handler=...,
    callback_handler=...,
    authorization_server_url="http://auth-server:9000",  # NEW
)

When provided:

  • Set self.context.auth_server_url at init time
  • In async_auth_flow, skip the initial unauthenticated request and jump directly to OASM fetch → client registration → token exchange → send authenticated request

When omitted, behavior stays identical to today.

Rough implementation sketch

In OAuthContext:

@dataclass
class OAuthContext:
    # ... existing fields ...
    auth_server_url: str | None = None  # already exists, just needs to be settable at init

In OAuthClientProvider.__init__:

def __init__(self, ..., authorization_server_url: str | None = None):
    self.context = OAuthContext(...)
    if authorization_server_url:
        self.context.auth_server_url = authorization_server_url

In async_auth_flow, before response = yield request:

if self.context.auth_server_url and not self.context.is_token_valid():
    # Auth server already known — go straight to OASM + token exchange
    # (skip sending unauthenticated request and waiting for 401)
    ...

Why this matters

  • Latency — One fewer round-trip before the client can do real work.
  • Controlled environments — Enterprise setups always know their auth server. Discovery via 401 adds no value there.
  • Complements existing featuresclient_metadata_url (CIMD) already lets you skip DCR. This is the same idea applied one step earlier in the chain.

Alternatives considered

Approach Limitation
CIMD (client_metadata_url) Skips DCR (step 5), but the 401 trigger + PRM discovery still happens
Pre-populating TokenStorage We don't necessarily manage the TokenStorage
Using httpx.Auth with a static Bearer token Works, but loses the full OAuth lifecycle (refresh, re-auth, etc.)
References
  • OAuthClientProvidermcp/client/auth/oauth2.py line 217
  • OAuthContext.auth_server_url — already exists as a field (line ~107), just populated from PRM today
  • async_auth_flow — the 401 branch starts at line ~504
  • MCP spec — Authorization
  • RFC 9728 — Protected Resource Metadata
  • RFC 8414 — OAuth Authorization Server Metadata

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.