CORSMiddleware on /register and /token forwards any non-preflight OPTIONS request straight to the body-reading handler
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 84/100
Direzione di ricerca
Inizia da src/mcp/server/auth/routes.py: leggi _cors() (circa righe 57-63) e le definizioni delle route /token e /register (circa 118-136), poi conferma come CORSMiddleware di starlette stabilisca che una richiesta sia preflight. Aggiungi un controllo prima del dispatch affinché un OPTIONS non-preflight (senza origin, o senza l'header access-control-request-method) risponda 405 con un header Allow invece di raggiungere RegistrationHandler/TokenHandler. Riproduci prima con lo script autonomo httpx/ASGITransport dell'issue; per considerare il lavoro concluso, entrambi i casi di OPTIONS non devono più restituire 201/500 e gli auth test esistenti sotto tests/ devono continuare a passare.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Affected versions: mcp 1.30.0 (confirmed); still present in the latest release, mcp 2.3.0, same code at src/mcp/server/auth/routes.py:119-120 (/token) and :132-136 (/register).
Where
routes.py:57-63:_cors()wraps the handler instarlette.middleware.cors.CORSMiddlewarewithallow_methods=["POST","OPTIONS"].routes.py:118-123and:130-136: both routes listOPTIONSand are wrapped by_cors.starlette/middleware/cors.py:86(starlette 1.7.0):CORSMiddleware.__call__only treats the request as a preflight whenorigin is not NoneANDmethod == "OPTIONS"AND"access-control-request-method" in headers; any otherOPTIONS(including one with no CORS headers at all) falls through tosimple_response, which calls the wrapped handler.
Repro (standalone, mcp + starlette + httpx only)
import anyio
from pydantic import AnyHttpUrl
from starlette.applications import Starlette
from mcp.server.auth.routes import create_auth_routes
from mcp.server.auth.settings import ClientRegistrationOptions
from httpx import ASGITransport, AsyncClient
class DummyProvider:
def __init__(self): self.clients = {}
async def register_client(self, client_info): self.clients[client_info.client_id] = client_info
async def get_client(self, client_id): return self.clients.get(client_id)
async def authorize(self, *a, **k): ...
async def load_authorization_code(self, *a, **k): ...
async def exchange_authorization_code(self, *a, **k): ...
async def load_refresh_token(self, *a, **k): ...
async def exchange_refresh_token(self, *a, **k): ...
async def revoke_token(self, *a, **k): ...
async def main():
provider = DummyProvider()
routes = create_auth_routes(provider, issuer_url=AnyHttpUrl("https://example.test"), client_registration_options=ClientRegistrationOptions(enabled=True))
app = Starlette(routes=routes)
transport = ASGITransport(app=app, raise_app_exceptions=False)
async with AsyncClient(transport=transport, base_url="https://example.test") as client:
r1 = await client.options("/register")
print("OPTIONS /register, no body, no CORS headers ->", r1.status_code)
r2 = await client.request("OPTIONS", "/register", content=b'{"redirect_uris": ["https://client.example/cb"], "client_name": "demo"}', headers={"Content-Type": "application/json"})
print("OPTIONS /register, JSON body, no CORS headers ->", r2.status_code, r2.text[:200])
print("Clients stored:", list(provider.clients.keys()))
anyio.run(main)
Expected vs actual
- Expected: a non-preflight
OPTIONSis rejected (405) or answered empty, never reaching the handler. - Actual: the empty-body
OPTIONSreachesRegistrationHandler.handle, which callsrequest.json()on an empty body and raises an uncaughtJSONDecodeError(unhandled 500), and the JSON-bodyOPTIONSis parsed, assigned aclient_id/client_secret, stored viaprovider.register_client, and answered 201 — a registration created over what looked like a CORS preflight, bypassing rate limiting.
Suggested fix
Check origin is not None and "access-control-request-method" in headers before dispatch, in create_auth_routes/cors_middleware, answering a non-preflight OPTIONS with 405 + Allow header; no Starlette change required.
- Lingua principale
- Python
- Stelle
- 24.5k
- Fork
- 4k
- Merge medio
- 1g 14h
- PR unite (30g)
- 34
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di modelcontextprotocol/python-sdk
-
bug v1 v2
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
modelcontextprotocol/python-sdk#3656 ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
modelcontextprotocol/python-sdk#3655 ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 86/100
modelcontextprotocol/python-sdk#3654 ·
I maintainer di solito rispondono entro 1 giorno
-
bug spec-2026-07-28 v2
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
modelcontextprotocol/python-sdk#3649 ·
I maintainer di solito rispondono entro 1 giorno
-
bug v1 v2
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
modelcontextprotocol/python-sdk#3639 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di modelcontextprotocol/python-sdk
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
I maintainer di solito rispondono entro 1 giorno
-
SR_SECURITY_DESCRIPTOR.fromString drops the SACL when no DACL is presentForse già presa @paul7436 l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
I maintainer di solito rispondono entro 2 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
equinor/fmu-sumo-uploader#302 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
modelscope/evalscope#1821 ·
I maintainer di solito rispondono entro 1 giorno
-
Sanity on ansible-core devel fails: ignore-2.23.txt references the removed import-3.9 testForse già presa @yurnov l’ha presa oggi. Apertaneeds_triage
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 91/100
ansible-collections/kubernetes.core#1275 ·
I maintainer di solito rispondono entro 1 giorno