modelcontextprotocol / modelcontextprotocol/python-sdk
RequireAuthMiddleware omits RFC 6750 scope in WWW-Authenticate on 401/403
Personne n'a encore pris cette issue.
- Langage dominant
- Python
- Étoiles
- 24.3k
- Forks
- 4k
- Merge moyen
- 1 j 1 h
- PR mergées (30 j)
- 31
Description
Initial Checks
- I confirm that I'm using the latest version of MCP Python SDK
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Description
Summary
RequireAuthMiddleware._send_auth_error builds WWW-Authenticate with error and error_description (and optional resource_metadata), but never includes the scope parameter, even when required_scopes is configured.
This breaks RFC 6750 Section 3.1 and the MCP Authorization scope-selection / step-up flow. The SDK client already expects scope via extract_scope_from_www_auth() and uses it in get_client_metadata_scopes() as the highest-priority source when handling 403 insufficient_scope.
Actual behavior
For a server configured with required_scopes=["api.read"]:
401 (no/invalid token):
WWW-Authenticate: Bearer error="invalid_token", error_description="Authentication required"
403 (token missing required scope):
WWW-Authenticate: Bearer error="insufficient_scope", error_description="Required scope: api.read"
Neither response includes scope="api.read".
Expected behavior
When required_scopes is non-empty, the challenge should include the RFC 6750 scope parameter, e.g.:
WWW-Authenticate: Bearer error="insufficient_scope", error_description="Required scope: api.read", scope="api.read"
(and similarly for 401 when scopes are configured, so the client can request the correct scopes on initial authorization).
Impact
- MCP clients cannot reliably discover required scopes from the challenge header.
- Step-up authorization falls back to PRM
scopes_supported(or omits scope), which is lower priority per the MCP scope selection strategy and can fail when PRM does not advertise scopes. - The SDK client already implements the correct consumer side; only server emission is missing.
Root cause
In src/mcp/server/auth/middleware/bearer_auth.py, _send_auth_error builds:
www_auth_parts = [f'error="{error}"', f'error_description="{description}"']
if self.resource_metadata_url:
www_auth_parts.append(f'resource_metadata="{self.resource_metadata_url}"')
It never appends scope= from self.required_scopes, which is already available on the middleware instance.
Present on both v1.x and main (verified in current source).
Suggested fix
When self.required_scopes is non-empty, append:
www_auth_parts.append(f'scope="{" ".join(self.required_scopes)}"')
Happy to open a PR against v1.x once a maintainer assigns this issue to me. Please also advise whether a follow-up for main (v2) is desired.
Example Code
Python & MCP Python SDK
Python: 3.14.6
MCP Python SDK: 1.28.1 (also reproduced against current v1.x / main source of RequireAuthMiddleware._send_auth_error)
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez dans src/mcp/server/auth/middleware/bearer_auth.py, en vous concentrant sur RequireAuthMiddleware._send_auth_error et sa construction existante de WWW-Authenticate. Examinez la couverture des réponses d’authentification environnantes, puis vérifiez les cas 401 et 403 avec required_scopes configuré ; c’est terminé lorsque le challenge expose le scope requis tout en préservant les paramètres existants.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- python
- Domaine
- authentication, backend, security
- Type d'issue
- Bug
- Difficulté
- 2/5
- Temps estimé
- 1-3 heures
- Activité
- Calme
- Clarté
- Clairement spécifiée
- Accessibilité débutants
- 78/100