1- from collections .abc import Callable
1+ from collections .abc import Awaitable , Callable
22from typing import Any
33
44from pydantic import AnyHttpUrl
5- from starlette .routing import Route
5+ from starlette .middleware .cors import CORSMiddleware
6+ from starlette .requests import Request
7+ from starlette .responses import Response
8+ from starlette .routing import Route , request_response
9+ from starlette .types import ASGIApp
610
711from mcp .server .auth .handlers .authorize import AuthorizationHandler
812from mcp .server .auth .handlers .metadata import MetadataHandler
@@ -47,6 +51,19 @@ def validate_issuer_url(url: AnyHttpUrl):
4751REVOCATION_PATH = "/revoke"
4852
4953
54+ def cors_middleware (
55+ handler : Callable [[Request ], Response | Awaitable [Response ]],
56+ allow_methods : list [str ],
57+ ) -> ASGIApp :
58+ cors_app = CORSMiddleware (
59+ app = request_response (handler ),
60+ allow_origins = "*" ,
61+ allow_methods = allow_methods ,
62+ allow_headers = ["mcp-protocol-version" ],
63+ )
64+ return cors_app
65+
66+
5067def create_auth_routes (
5168 provider : OAuthServerProvider [Any , Any , Any ],
5269 issuer_url : AnyHttpUrl ,
@@ -69,21 +86,32 @@ def create_auth_routes(
6986 client_authenticator = ClientAuthenticator (provider )
7087
7188 # Create routes
89+ # Allow CORS requests for endpoints meant to be hit by the OAuth client
90+ # (with the client secret). This is intended to support things like MCP Inspector,
91+ # where the client runs in a web browser.
7292 routes = [
7393 Route (
7494 "/.well-known/oauth-authorization-server" ,
75- endpoint = MetadataHandler (metadata ).handle ,
76- methods = ["GET" ],
95+ endpoint = cors_middleware (
96+ MetadataHandler (metadata ).handle ,
97+ ["GET" , "OPTIONS" ],
98+ ),
99+ methods = ["GET" , "OPTIONS" ],
77100 ),
78101 Route (
79102 AUTHORIZATION_PATH ,
103+ # do not allow CORS for authorization endpoint;
104+ # clients should just redirect to this
80105 endpoint = AuthorizationHandler (provider ).handle ,
81106 methods = ["GET" , "POST" ],
82107 ),
83108 Route (
84109 TOKEN_PATH ,
85- endpoint = TokenHandler (provider , client_authenticator ).handle ,
86- methods = ["POST" ],
110+ endpoint = cors_middleware (
111+ TokenHandler (provider , client_authenticator ).handle ,
112+ ["POST" , "OPTIONS" ],
113+ ),
114+ methods = ["POST" , "OPTIONS" ],
87115 ),
88116 ]
89117
@@ -95,15 +123,25 @@ def create_auth_routes(
95123 routes .append (
96124 Route (
97125 REGISTRATION_PATH ,
98- endpoint = registration_handler .handle ,
99- methods = ["POST" ],
126+ endpoint = cors_middleware (
127+ registration_handler .handle ,
128+ ["POST" , "OPTIONS" ],
129+ ),
130+ methods = ["POST" , "OPTIONS" ],
100131 )
101132 )
102133
103134 if revocation_options .enabled :
104135 revocation_handler = RevocationHandler (provider , client_authenticator )
105136 routes .append (
106- Route (REVOCATION_PATH , endpoint = revocation_handler .handle , methods = ["POST" ])
137+ Route (
138+ REVOCATION_PATH ,
139+ endpoint = cors_middleware (
140+ revocation_handler .handle ,
141+ ["POST" , "OPTIONS" ],
142+ ),
143+ methods = ["POST" , "OPTIONS" ],
144+ )
107145 )
108146
109147 return routes
0 commit comments