"""Mounted OAuth servers example for FastMCP. This example demonstrates mounting multiple OAuth-protected MCP servers in a single application, each with its own provider. It showcases RFC 8414 path-aware discovery where each server has its own authorization server metadata endpoint. URL structure: - GitHub MCP: http://127.0.0.1:8000/api/mcp/github/mcp - Google MCP: http://127.0.0.1:8000/api/mcp/google/mcp - GitHub discovery: http://127.0.0.1:8000/.well-known/oauth-authorization-server/api/mcp/github - Google discovery: http://127.0.0.1:8000/.well-known/oauth-authorization-server/api/mcp/google Required environment variables: - FASTMCP_SERVER_AUTH_GITHUB_CLIENT_ID: Your GitHub OAuth app client ID - FASTMCP_SERVER_AUTH_GITHUB_CLIENT_SECRET: Your GitHub OAuth app client secret - FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_ID: Your Google OAuth client ID - FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_SECRET: Your Google OAuth client secret To run: python server.py """ import os import uvicorn from starlette.applications import Starlette from starlette.routing import Mount from fastmcp import FastMCP from fastmcp.server.auth.providers.github import GitHubProvider from fastmcp.server.auth.providers.google import GoogleProvider # Configuration ROOT_URL = "http://127.0.0.1:8000" API_PREFIX = "/api/mcp" # --- GitHub OAuth Server --- github_auth = GitHubProvider( client_id=os.getenv("FASTMCP_SERVER_AUTH_GITHUB_CLIENT_ID") or "", client_secret=os.getenv("FASTMCP_SERVER_AUTH_GITHUB_CLIENT_SECRET") or "", base_url=f"{ROOT_URL}{API_PREFIX}/github", redirect_path="/auth/callback/github", ) github_mcp = FastMCP("GitHub Server", auth=github_auth) @github_mcp.tool def github_echo(message: str) -> str: """Echo from the GitHub-authenticated server.""" return f"[GitHub] {message}" @github_mcp.tool def github_info() -> str: """Get info about the GitHub server.""" return "This is the GitHub OAuth protected MCP server" # --- Google OAuth Server --- google_auth = GoogleProvider( client_id=os.getenv("FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_ID") or "", client_secret=os.getenv("FASTMCP_SERVER_AUTH_GOOGLE_CLIENT_SECRET") or "", base_url=f"{ROOT_URL}{API_PREFIX}/google", redirect_path="/auth/callback/google", ) google_mcp = FastMCP("Google Server", auth=google_auth) @google_mcp.tool def google_echo(message: str) -> str: """Echo from the Google-authenticated server.""" return f"[Google] {message}" @google_mcp.tool def google_info() -> str: """Get info about the Google server.""" return "This is the Google OAuth protected MCP server" # --- Create ASGI apps --- github_app = github_mcp.http_app(path="/mcp") google_app = google_mcp.http_app(path="/mcp") # Get well-known routes for each provider (path-aware per RFC 8414) github_well_known = github_auth.get_well_known_routes(mcp_path="/mcp") google_well_known = google_auth.get_well_known_routes(mcp_path="/mcp") # --- Combine into single application --- # Note: Each provider has its own path-aware discovery endpoint: # - /.well-known/oauth-authorization-server/api/mcp/github # - /.well-known/oauth-authorization-server/api/mcp/google app = Starlette( routes=[ # Well-known routes at root level (path-aware) *github_well_known, *google_well_known, # MCP servers under /api/mcp prefix Mount(f"{API_PREFIX}/github", app=github_app), Mount(f"{API_PREFIX}/google", app=google_app), ], # Use one of the app lifespans (they're functionally equivalent) lifespan=github_app.lifespan, ) if __name__ == "__main__": print("Starting mounted OAuth servers...") print(f" GitHub MCP: {ROOT_URL}{API_PREFIX}/github/mcp") print(f" Google MCP: {ROOT_URL}{API_PREFIX}/google/mcp") print() print("Discovery endpoints (RFC 8414 path-aware):") print( f" GitHub: {ROOT_URL}/.well-known/oauth-authorization-server{API_PREFIX}/github" ) print( f" Google: {ROOT_URL}/.well-known/oauth-authorization-server{API_PREFIX}/google" ) print() uvicorn.run(app, host="0.0.0.0", port=8000)