Skip to content

Commit 0a1a408

Browse files
committed
Add CORS support
1 parent 8e15abc commit 0a1a408

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

src/mcp/server/auth/handlers/token.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,10 @@ async def handle(self, request: Request):
158158

159159
# verify redirect_uri doesn't change between /authorize and /tokens
160160
# see https://datatracker.ietf.org/doc/html/rfc6749#section-10.6
161-
authorize_request_redirect_uri = auth_code.redirect_uri if auth_code.redirect_uri_provided_explicitly else None
161+
if auth_code.redirect_uri_provided_explicitly:
162+
authorize_request_redirect_uri = auth_code.redirect_uri
163+
else:
164+
authorize_request_redirect_uri = None
162165
if token_request.redirect_uri != authorize_request_redirect_uri:
163166
return self.response(
164167
TokenErrorResponse(

src/mcp/server/auth/routes.py

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
from collections.abc import Callable
1+
from collections.abc import Awaitable, Callable
22
from typing import Any
33

44
from 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

711
from mcp.server.auth.handlers.authorize import AuthorizationHandler
812
from mcp.server.auth.handlers.metadata import MetadataHandler
@@ -47,6 +51,19 @@ def validate_issuer_url(url: AnyHttpUrl):
4751
REVOCATION_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+
5067
def 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

Comments
 (0)