5
5
import inspect
6
6
import re
7
7
from collections .abc import AsyncIterator , Awaitable , Callable , Iterable , Sequence
8
- from contextlib import (
9
- AbstractAsyncContextManager ,
10
- asynccontextmanager ,
11
- )
8
+ from contextlib import AbstractAsyncContextManager , asynccontextmanager
12
9
from itertools import chain
13
10
from typing import Any , Generic , Literal
14
11
18
15
from pydantic .networks import AnyUrl
19
16
from pydantic_settings import BaseSettings , SettingsConfigDict
20
17
from starlette .applications import Starlette
18
+ from starlette .exceptions import HTTPException
21
19
from starlette .middleware import Middleware
22
20
from starlette .middleware .authentication import AuthenticationMiddleware
23
- from starlette .exceptions import HTTPException
24
21
from starlette .requests import Request
25
22
from starlette .responses import Response
26
23
from starlette .routing import Mount , Route
32
29
JWTBearerTokenAuthBackend ,
33
30
RequireAuthMiddleware ,
34
31
)
35
- from mcp .server .auth .provider import AccessToken , TokenValidator
36
- from mcp .server .auth .provider import OAuthAuthorizationServerProvider
37
- from mcp .shared .auth import ProtectedResourceMetadata
38
- from mcp .server .auth .settings import (
39
- AuthSettings ,
32
+ from mcp .server .auth .provider import (
33
+ AccessToken ,
34
+ OAuthAuthorizationServerProvider ,
35
+ TokenValidator ,
40
36
)
37
+ from mcp .server .auth .settings import AuthSettings
41
38
from mcp .server .fastmcp .exceptions import ResourceError
42
39
from mcp .server .fastmcp .prompts import Prompt , PromptManager
43
40
from mcp .server .fastmcp .resources import FunctionResource , Resource , ResourceManager
53
50
from mcp .server .stdio import stdio_server
54
51
from mcp .server .streamable_http import EventStore
55
52
from mcp .server .streamable_http_manager import StreamableHTTPSessionManager
53
+ from mcp .shared .auth import ProtectedResourceMetadata
56
54
from mcp .shared .context import LifespanContextT , RequestContext
57
55
from mcp .types import (
58
56
AnyFunction ,
@@ -143,8 +141,9 @@ def __init__(
143
141
name : str | None = None ,
144
142
instructions : str | None = None ,
145
143
auth_server_details : dict [str , Any ] | None = None ,
146
- auth_server_provider : OAuthAuthorizationServerProvider [Any , Any , Any ]
147
- | None = None ,
144
+ auth_server_provider : (
145
+ OAuthAuthorizationServerProvider [Any , Any , Any ] | None
146
+ ) = None ,
148
147
protected_resource_metadata : dict [str , Any ] | None = None ,
149
148
event_store : EventStore | None = None ,
150
149
token_validator : TokenValidator [AccessToken ] | None = None ,
@@ -154,9 +153,11 @@ def __init__(
154
153
self ._auth_server_details = auth_server_details
155
154
self ._protected_resource_metadata = None
156
155
if protected_resource_metadata :
157
- self ._protected_resource_metadata = ProtectedResourceMetadata (** protected_resource_metadata )
156
+ self ._protected_resource_metadata = ProtectedResourceMetadata (
157
+ ** protected_resource_metadata
158
+ )
158
159
self ._token_validator = token_validator
159
-
160
+
160
161
self ._mcp_server = MCPServer (
161
162
name = name or "FastMCP" ,
162
163
instructions = instructions ,
@@ -176,7 +177,9 @@ def __init__(
176
177
warn_on_duplicate_prompts = self .settings .warn_on_duplicate_prompts
177
178
)
178
179
# don't do this check if protected_resource_metadata is not None
179
- if (self .settings .auth is not None ) != (auth_server_provider is not None ) and self ._protected_resource_metadata is None :
180
+ if (self .settings .auth is not None ) != (
181
+ auth_server_provider is not None
182
+ ) and self ._protected_resource_metadata is None :
180
183
# TODO: after we support separate authorization servers (see
181
184
# https://github.com/modelcontextprotocol/modelcontextprotocol/pull/284)
182
185
# we should validate that if auth is enabled, we have either an
@@ -228,8 +231,13 @@ def session_manager(self) -> StreamableHTTPSessionManager:
228
231
async def _serve_protected_resource_metadata (self , request : Request ) -> Response :
229
232
"""Serve the OAuth protected resource metadata."""
230
233
if not self ._protected_resource_metadata :
231
- raise HTTPException (status_code = 404 , detail = "Protected resource metadata not configured" )
232
- return Response (self ._protected_resource_metadata .model_dump_json (), media_type = "application/json" )
234
+ raise HTTPException (
235
+ status_code = 404 , detail = "Protected resource metadata not configured"
236
+ )
237
+ return Response (
238
+ self ._protected_resource_metadata .model_dump_json (),
239
+ media_type = "application/json" ,
240
+ )
233
241
234
242
def run (
235
243
self ,
@@ -706,11 +714,10 @@ async def handle_sse(scope: Scope, receive: Receive, send: Send):
706
714
707
715
# Create routes
708
716
routes : list [Route | Mount ] = []
709
-
717
+
710
718
middleware : list [Middleware ] = []
711
719
required_scopes = []
712
720
713
-
714
721
# Add auth endpoints if auth provider is configured
715
722
if self ._auth_server_provider :
716
723
assert self .settings .auth
@@ -808,21 +815,20 @@ async def handle_streamable_http(
808
815
routes : list [Route | Mount ] = []
809
816
middleware : list [Middleware ] = []
810
817
required_scopes = []
811
- print ("Protected resource metadata: " , self ._protected_resource_metadata )
812
818
if self ._protected_resource_metadata and self ._token_validator :
813
- print ( "Adding protected resource metadata route" )
814
- # only add the well-known route if the protected resource metadata is configured
819
+ # only add the well-known route if the protected resource metadata is
820
+ # configured
815
821
routes .append (
816
822
Route (
817
823
"/.well-known/oauth-protected-resource" ,
818
824
self ._serve_protected_resource_metadata ,
819
- methods = ["GET" ]
825
+ methods = ["GET" ],
820
826
)
821
827
)
822
- # by default assuming that this would be a JWT Bearer Token;
823
- # Make this also optional somehow; may be as part of the protected resource metadata,
824
- # take a class for validting the token
825
- middleware = [
828
+ # by default assuming that this would be a JWT Bearer Token;
829
+ # Make this also optional somehow; may be as part of the protected resource
830
+ # metadata, take a class for validating the token
831
+ middleware = [
826
832
Middleware (
827
833
AuthenticationMiddleware ,
828
834
backend = JWTBearerTokenAuthBackend (
0 commit comments