""" Run from the repository root: uv run examples/snippets/servers/oauth_server.py """ from pydantic import AnyHttpUrl from mcp.server.auth.provider import AccessToken, TokenVerifier from mcp.server.auth.settings import AuthSettings from mcp.server.fastmcp import FastMCP import contextlib from starlette.applications import Starlette from starlette.routing import Mount, Route from starlette.responses import JSONResponse class SimpleTokenVerifier(TokenVerifier): """Simple token verifier for demonstration.""" async def verify_token(self, token: str) -> AccessToken | None: pass # This is where you would implement actual token validation # Create FastMCP instance as a Resource Server mcp = FastMCP( "Weather Service", # Token verifier for authentication token_verifier=SimpleTokenVerifier(), # Auth settings for RFC 9728 Protected Resource Metadata auth=AuthSettings( issuer_url=AnyHttpUrl("https://huggingface.co/.well-known/oauth-authorization-server"), # Authorization Server URL resource_server_url=AnyHttpUrl("https://freddyaboulton-fastmcp-oauth.hf.space/"), # This server's URL required_scopes=["user"], ), port=7860 ) @mcp.tool() async def get_weather(city: str = "London") -> dict[str, str]: """Get weather data for a city""" return { "city": city, "temperature": "22", "condition": "Partly cloudy", "humidity": "65%", } # Create a combined lifespan to manage both session managers @contextlib.asynccontextmanager async def lifespan(app: Starlette): async with contextlib.AsyncExitStack() as stack: await stack.enter_async_context(mcp.session_manager.run()) yield async def homepage(request): return JSONResponse({'hello': 'world'}) # Create the Starlette app and mount the MCP servers app = Starlette( routes=[ Mount("/sub", mcp.streamable_http_app()), Route("/", homepage), ], lifespan=lifespan, ) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=7860)