modelcontextprotocol / modelcontextprotocol/python-sdk

Revocation requires client_secret to be present

Aperta Adatta ai principianti
#3,508 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

v1 v2
Lingua principale
Python
Stelle
24.3k
Fork
4k
Merge medio
1g 1h
PR unite (30g)
31

Descrizione

Initial Checks
Release line

2.x (current stable)

Description
What happened?

When Claude Code (or any other public client) triggers revocation - revoke handler requires client_secret to be present, as seen here:

https://github.com/modelcontextprotocol/python-sdk/blob/9972c21aa42054fb1450c5fc614761ed11847ec6/src/mcp/server/auth/handlers/revoke.py#L23

Per OAuth 2.0 specifications (RFC 6749 Section 2.3 and RFC 7009 Section 5), public clients do not have a client_secret and identify themselves using only client_id.
This leads to issue when public clients do not sent client secret at all.

In Pydantic v2, defining a field as str | None without a default value still marks the field as required (i.e., nullable value, but the key must exist in the request body).

Steps to reproduce
  1. Authenticate using a public OAuth client (e.g., Claude Code CLI).
  2. Trigger token revocation (e.g., re-authenticating or logging out).
  3. The authorization server returns a 400 Bad Request with:
    {"error":"invalid_request","error_description":"client_secret: Field required"}
Expected behavior

client_secret should be optional so public clients can revoke tokens without sending a client_secret key.

Fix

Adding default value for client_secret:

client_secret: str | None = None
Workaround

As workaround I'm overriding Request type:

from mcp.server.auth.handlers import revoke

class FixedRevocationRequest(revoke.RevocationRequest):
    client_secret: str | None = None

revoke.RevocationRequest = FixedRevocationRequest
Example Code
from mcp.server.auth.handlers.revoke import RevocationRequest
from pydantic import ValidationError

# Simulate a public client request: client_secret parameter omitted entirely
form_no_secret = {"token": "abc", "client_id": "local-scurri-mcp"}

try:
    req = RevocationRequest.model_validate(form_no_secret)
    print("no-secret: OK ->", req)
except ValidationError as e:
    print("no-secret: FAILS ->", e.errors()[0]["msg"])
Python & MCP Python SDK
MCP version:                                                                                                     2.2.0
Python version:                                                                                                 3.13.9

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia in src/mcp/server/auth/handlers/revoke.py, in RevocationRequest, e rivedi il comportamento di validazione collegato. Conferma che una richiesta di revoca da parte di un client pubblico può omettere client_secret, quindi usa l'esempio Pydantic fornito con solo token e client_id per verificare che la validazione abbia esito positivo.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
python
Ambito
authentication
Tipo di issue
Bug
Difficoltà
1/5
Tempo stimato
Meno di un'ora
Stato di attività
Attiva
Chiarezza
Specificata chiaramente
Idoneità per principianti
91/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.