modelcontextprotocol / modelcontextprotocol/python-sdk

OAuth token refresh hits the wrong endpoint when the auth server lives under a path

Ouverte
#3,240 2 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

P1 v1 v2
Langage dominant
Python
Étoiles
24.3k
Forks
4k
Merge moyen
1 j 1 h
PR mergées (30 j)
31

Description

Ran into this with a hosted MCP server whose authorization server isn't at the origin root — token endpoint is https://host/oauth2/api/v1/token, not https://host/token.

If a client starts up with a cached-but-expired access token (+ refresh token) and hasn't done discovery yet, async_auth_flow refreshes at the very top — before any 401/metadata discovery. So oauth_metadata is None and _refresh_token uses the fallback urljoin(get_authorization_base_url(server_url), "/token"), i.e. just {scheme}://{netloc}/token. That 404s, _handle_refresh_response clears the tokens, and the flow drops to full interactive auth — which a headless/gateway client can't do. So the server silently disconnects every time the access token expires (mine are 5 min, so… constantly).

Same path-stripping fallback is in _get_token_endpoint, _perform_authorization_code_grant (/authorize) and DCR (/register) — refresh is just the one that bites silently.

Repro (roughly):

  • MCP server whose AS metadata puts token_endpoint under a path, not {origin}/token
  • log in normally so tokens get cached
  • let the access token expire (or clear the expiry), reconnect with a fresh provider
  • watch the refresh POST go to https://host/token → 404 → "Token refresh failed" → tokens cleared → it tries to open a browser

Fix looks like: discover metadata before the eager refresh (or stop dropping the issuer path in the fallback). Happy to PR — have a branch that pulls the PRM/ASM discovery out of the 401 branch and runs it before the refresh.

(used some AI help digging into this)

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par suivre async_auth_flow et son chemin de refresh eager jusqu’à _refresh_token, puis comparez le comportement de fallback dans _get_token_endpoint, _perform_authorization_code_grant et DCR. Reproduisez le scénario d’un token expiré mis en cache face à un serveur d’autorisation dont les endpoints de métadonnées incluent un chemin. Le travail est terminé lorsque le refresh utilise l’endpoint de token découvert et n’efface pas les tokens valides ni ne revient à l’authentification interactive.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
python
Domaine
api, authentication
Type d'issue
Bug
Difficulté
4/5
Temps estimé
3-5 jours
Activité
Calme
Clarté
Clairement spécifiée
Accessibilité débutants
48/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.