modelcontextprotocol / modelcontextprotocol/python-sdk
OAuth: 403 responses without insufficient_scope incorrectly retry with same token
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 24.3k
- Forks
- 4k
- Ø Merge
- 1 T. 1 Std.
- Gemergte PRs (30 T.)
- 31
Beschreibung
Summary
The OAuth client unconditionally retries all 403 responses, even when the error is not insufficient_scope. This causes an unnecessary retry attempt with the same token that will fail for the same reason.
Location
src/mcp/client/auth/oauth2.py, lines 662-681
The Bug
elif response.status_code == 403:
error = self._extract_field_from_www_auth(response, "error")
# Only performs step-up if error == "insufficient_scope"
if error == "insufficient_scope":
self._select_scopes(response)
token_response = yield await self._perform_authorization()
await self._handle_token_response(token_response)
# BUG: Retries unconditionally, even when no new tokens were obtained
self._add_auth_header(request)
yield request
Lines 679-681 execute regardless of whether step-up authorization occurred, causing a retry with the same credentials.
Expected vs Actual Behavior
| Scenario | Expected | Actual |
|---|---|---|
403 with insufficient_scope |
Get new tokens → retry | ✅ Correct |
403 with different error (e.g., invalid_token) |
Raise error immediately | ❌ Retries once with same token, then fails |
| 403 with no error field | Raise error immediately | ❌ Retries once with same token, then fails |
Impact
- Wasted network round-trip: Client makes doomed retry request that will fail for the same reason
- Poor error feedback: Delays error reporting by one request cycle
- Spec non-compliance: MCP Authorization Spec implies retry only for
insufficient_scope - Resource waste: Unnecessary load on server and client
Fix
Move the retry logic inside the if error == "insufficient_scope": block and raise an error otherwise:
elif response.status_code == 403:
error = self._extract_field_from_www_auth(response, "error")
if error == "insufficient_scope":
try:
self._select_scopes(response)
token_response = yield await self._perform_authorization()
await self._handle_token_response(token_response)
# Retry with new tokens
self._add_auth_header(request)
yield request
except Exception:
logger.exception("OAuth flow error")
raise
else:
# Permanent authorization failure - cannot be resolved by retry
raise OAuthFlowError(
f"Access forbidden: {error or 'insufficient permissions'}"
)
References
- RFC 6750 Section 3.1 - Defines
insufficient_scopeas the only 403 error code - MCP Authorization Spec - Scope challenge handling
Authored by Claude, reviewed by @maxisbey
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Lies src/mcp/client/auth/oauth2.py ungefähr in den Zeilen 662–681 und konzentriere dich darauf, wie 403-Antworten behandelt werden, nachdem das Feld error extrahiert wurde. Bestätige das Verhalten für insufficient_scope, einen anderen Fehler und kein error-Feld; abgeschlossen ist die Aufgabe, wenn nur der scope-challenge-Pfad einen erneuten Versuch unternimmt und andere 403-Antworten sofort eine Exception auslösen.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- python
- Bereich
- authentication
- Issue-Typ
- Bug
- Schwierigkeit
- 2/5
- Geschätzter Aufwand
- 1-3 Stunden
- Aktivitätsstatus
- Veraltet
- Klarheit
- Klar beschrieben
- Anfängerfreundlichkeit
- 55/100