### Run WhoAmI Server (Legacy) Source: https://github.com/mcp-auth/python/blob/master/samples/README.md Start the WhoAmI server, a legacy example demonstrating basic authentication. Ensure you are in the samples directory first. ```bash cd samples uv run uvicorn v0_1_1.whoami:app --host 127.0.0.1 --port 3001 ``` -------------------------------- ### Install MCP Auth Python SDK Source: https://github.com/mcp-auth/python/blob/master/README.md Use this command to install the SDK. It is compatible with pip, poetry, and uv. ```bash pip install mcpauth ``` -------------------------------- ### Run Todo Manager Server (Legacy) Source: https://github.com/mcp-auth/python/blob/master/samples/README.md Start the legacy Todo Manager server, which acts as both an authorization and resource server. Ensure you are in the samples directory first. ```bash cd samples uv run uvicorn v0_1_1.todo-manager.server:app --host 127.0.0.1 --port 3001 ``` -------------------------------- ### Install Dependencies with uv Source: https://github.com/mcp-auth/python/blob/master/samples/README.md Install project dependencies, including development dependencies, using uv. The traditional pip method is also shown as an alternative. ```bash uv pip install -e . uv pip install -e ".[dev]" # Alternative: Traditional pip method (after activating virtual environment) # pip install -e . # pip install -e ".[dev]" ``` -------------------------------- ### Run Todo Manager Server (Current) Source: https://github.com/mcp-auth/python/blob/master/samples/README.md Start the Todo Manager server, which acts as a resource server validating external tokens. Ensure you are in the samples directory first. ```bash cd samples uv run uvicorn current.todo-manager.server:app --host 127.0.0.1 --port 3001 ``` -------------------------------- ### create_verify_jwt Source: https://context7.com/mcp-auth/python/llms.txt Creates a standalone `VerifyAccessTokenFunction` from a JWKS URI string, a `PyJWKClient`, or a single `PyJWK`. Useful when you need a reusable verifier outside the `MCPAuth` class, for example when writing custom middleware or tests. Supports RSA, PSS, and EC algorithms by default. ```APIDOC ## `create_verify_jwt` — Low-level JWT verifier factory Creates a standalone `VerifyAccessTokenFunction` from a JWKS URI string, a `PyJWKClient`, or a single `PyJWK`. Useful when you need a reusable verifier outside the `MCPAuth` class, for example when writing custom middleware or tests. Supports RSA, PSS, and EC algorithms by default. ### Usage **From a JWKS URI:** ```python from mcpauth.utils import create_verify_jwt from mcpauth.exceptions import MCPAuthTokenVerificationException verify = create_verify_jwt( "https://auth.example.com/.well-known/jwks.json", algorithms=["RS256", "ES256"], leeway=60, ) try: auth_info = verify("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...") print(auth_info.subject) # "user-123" print(auth_info.scopes) # ["read:items"] print(auth_info.issuer) # "https://auth.example.com/oidc" print(auth_info.claims) # Full decoded payload dict except MCPAuthTokenVerificationException as e: # e.code: "invalid_token" | "token_verification_failed" print(f"Token rejected: {e.code} — {e.message}") ``` **From a pre-configured PyJWKClient (useful for caching / custom headers):** ```python from mcpauth.utils import create_verify_jwt from jwt import PyJWKClient jwks_client = PyJWKClient( "https://auth.example.com/.well-known/jwks.json", headers={"User-Agent": "my-app/1.0"}, cache_keys=True, ) verify_with_client = create_verify_jwt(jwks_client) ``` ``` -------------------------------- ### Set up Virtual Environment with uv Source: https://github.com/mcp-auth/python/blob/master/samples/README.md Navigate to the project root and create a virtual environment using uv. Activation is optional when using 'uv run'. ```bash cd .. uv venv source .venv/bin/activate ``` -------------------------------- ### Initialize MCPAuth and Access Auth Info Source: https://context7.com/mcp-auth/python/llms.txt Instantiate MCPAuth in resource server mode and access authenticated user information within tool handlers. Ensure environment variables for the authorization server issuer are set. ```python import os from mcpauth import MCPAuth from mcpauth.config import AuthServerType from mcpauth.types import ResourceServerConfig, ResourceServerMetadata from mcpauth.utils import fetch_server_config # Fetch OIDC provider metadata once at startup auth_server_config = fetch_server_config( issuer=os.environ["MCP_AUTH_ISSUER"], # e.g. "https://auth.example.com/oidc" type=AuthServerType.OIDC, ) resource_id = "https://api.example.com/mcp" mcp_auth = MCPAuth( protected_resources=[ ResourceServerConfig( metadata=ResourceServerMetadata( resource=resource_id, authorization_servers=[auth_server_config], scopes_supported=["read:data", "write:data", "admin"], ) ) ] ) # Access authenticated user inside any MCP tool handler def my_tool_handler(): auth_info = mcp_auth.auth_info # Returns AuthInfo | None if auth_info: print(auth_info.subject) # User ID / sub claim print(auth_info.scopes) # ["read:data"] print(auth_info.client_id) # OAuth client ID print(auth_info.issuer) # "https://auth.example.com/oidc" ``` -------------------------------- ### MCPAuth - Main Entry Point Source: https://context7.com/mcp-auth/python/llms.txt The `MCPAuth` class is the primary orchestrator for authentication and authorization. Instantiate it with either a server configuration for legacy authorization server mode or protected resources for resource server mode. It provides middleware, a metadata router, and access to authenticated user information. ```APIDOC ## `MCPAuth` — Main entry point The `MCPAuth` class is the top-level orchestrator. Instantiate it once with either a `server` (legacy authorization-server mode) or `protected_resources` (resource-server mode). It provides the bearer-auth middleware factory, the metadata router, and a thread-safe `auth_info` property to retrieve the current request's token payload inside tool handlers. ```python import os from mcpauth import MCPAuth from mcpauth.config import AuthServerType from mcpauth.types import ResourceServerConfig, ResourceServerMetadata from mcpauth.utils import fetch_server_config # Fetch OIDC provider metadata once at startup auth_server_config = fetch_server_config( issuer=os.environ["MCP_AUTH_ISSUER"], # e.g. "https://auth.example.com/oidc" type=AuthServerType.OIDC, ) resource_id = "https://api.example.com/mcp" mcp_auth = MCPAuth( protected_resources=[ ResourceServerConfig( metadata=ResourceServerMetadata( resource=resource_id, authorization_servers=[auth_server_config], scopes_supported=["read:data", "write:data", "admin"], ) ) ] ) # Access authenticated user inside any MCP tool handler def my_tool_handler(): auth_info = mcp_auth.auth_info # Returns AuthInfo | None if auth_info: print(auth_info.subject) # User ID / sub claim print(auth_info.scopes) # ["read:data"] print(auth_info.client_id) # OAuth client ID print(auth_info.issuer) # "https://auth.example.com/oidc" ``` ``` -------------------------------- ### Fetch Authorization Server Configuration Source: https://context7.com/mcp-auth/python/llms.txt Use fetch_server_config to discover OIDC or OAuth authorization server metadata from a well-known endpoint. An optional transpile_data callback can reshape non-standard metadata. Use fetch_server_config_by_well_known_url to supply an explicit URL. ```python from mcpauth.utils import fetch_server_config, fetch_server_config_by_well_known_url from mcpauth.config import AuthServerType from mcpauth.exceptions import MCPAuthAuthServerException, MCPAuthConfigException # --- Auto-discovered well-known URL (recommended) --- try: oidc_config = fetch_server_config( issuer="https://accounts.google.com", type=AuthServerType.OIDC, # Optional: reshape non-standard metadata transpile_data=lambda data: {**data, "issuer": data.get("iss", data.get("issuer"))}, ) print(oidc_config.metadata.issuer) # "https://accounts.google.com" print(oidc_config.metadata.token_endpoint) # "https://oauth2.googleapis.com/token" print(oidc_config.type) # AuthServerType.OIDC except MCPAuthAuthServerException as e: print(f"Invalid metadata: {e.code} — {e.message}") except MCPAuthConfigException as e: print(f"Fetch failed: {e.message}") # --- Supply an explicit well-known URL --- oauth_config = fetch_server_config_by_well_known_url( well_known_url="https://logto.example.com/.well-known/oauth-authorization-server", type=AuthServerType.OAUTH, ) ``` -------------------------------- ### fetch_server_config - Discover Authorization Server Metadata Source: https://context7.com/mcp-auth/python/llms.txt Fetches OAuth 2.0 / OIDC discovery metadata from a provider's well-known endpoint. It returns a validated `AuthServerConfig` and supports custom data transpilation for non-standard metadata. ```APIDOC ## `fetch_server_config` — Discover authorization server metadata Fetches OAuth 2.0 / OIDC discovery metadata from a provider's well-known endpoint and returns a validated `AuthServerConfig`. For `AuthServerType.OAUTH` it appends `/.well-known/oauth-authorization-server/`; for `AuthServerType.OIDC` it appends `/.well-known/openid-configuration`. An optional `transpile_data` callback lets you reshape non-standard metadata before validation. ```python from mcpauth.utils import fetch_server_config, fetch_server_config_by_well_known_url from mcpauth.config import AuthServerType from mcpauth.exceptions import MCPAuthAuthServerException, MCPAuthConfigException # --- Auto-discovered well-known URL (recommended) --- try: oidc_config = fetch_server_config( issuer="https://accounts.google.com", type=AuthServerType.OIDC, # Optional: reshape non-standard metadata transpile_data=lambda data: {**data, "issuer": data.get("iss", data.get("issuer"))}, ) print(oidc_config.metadata.issuer) # "https://accounts.google.com" print(oidc_config.metadata.token_endpoint) # "https://oauth2.googleapis.com/token" print(oidc_config.type) # AuthServerType.OIDC except MCPAuthAuthServerException as e: print(f"Invalid metadata: {e.code} — {e.message}") except MCPAuthConfigException as e: print(f"Fetch failed: {e.message}") # --- Supply an explicit well-known URL --- oauth_config = fetch_server_config_by_well_known_url( well_known_url="https://logto.example.com/.well-known/oauth-authorization-server", type=AuthServerType.OAUTH, ) ``` ``` -------------------------------- ### create_resource_metadata_endpoint Source: https://context7.com/mcp-auth/python/llms.txt Builds well-known metadata URLs according to RFC 9728 Section 3.1 path-insertion rules. This utility is used internally by the error handler for `WWW-Authenticate` headers and by the metadata router to determine its mount path. ```APIDOC ## `create_resource_metadata_endpoint` — Build well-known metadata URLs A utility that constructs the correct `/.well-known/oauth-protected-resource[/]` URL for a given resource identifier, following RFC 9728 Section 3.1 path-insertion rules. Used internally by the error handler to populate `WWW-Authenticate` response headers and by the metadata router to determine its mount path. ```python from mcpauth.utils import create_resource_metadata_endpoint # Root resource url = create_resource_metadata_endpoint("https://api.example.com") print(url) # "https://api.example.com/.well-known/oauth-protected-resource" # Resource with a path component url = create_resource_metadata_endpoint("https://api.example.com/mcp") print(url) # "https://api.example.com/.well-known/oauth-protected-resource/mcp" # The generated URL appears in 401 WWW-Authenticate headers: # WWW-Authenticate: Bearer resource_metadata="https://api.example.com/.well-known/oauth-protected-resource/mcp", # error="invalid_token", # error_description="The provided token is invalid or has expired." ``` ``` -------------------------------- ### Serve Protected Resource Metadata with Starlette Router Source: https://context7.com/mcp-auth/python/llms.txt Exposes the OAuth 2.0 Protected Resource Metadata document at /.well-known/oauth-protected-resource. Mount this router alongside your MCP app routes. ```python from starlette.applications import Starlette from starlette.routing import Mount from starlette.middleware import Middleware import contextlib mcp_auth = MCPAuth(protected_resources=[...]) # configured as above @contextlib.asynccontextmanager async def lifespan(app: Starlette): async with mcp.session_manager.run(): yield app = Starlette( routes=[ # Exposes GET /.well-known/oauth-protected-resource # (or /.well-known/oauth-protected-resource/mcp for resource_id ending in /mcp) *mcp_auth.resource_metadata_router().routes, Mount( "/", app=mcp.streamable_http_app(), middleware=[Middleware(mcp_auth.bearer_auth_middleware("jwt", resource=resource_id))], ), ], lifespan=lifespan, ) ``` -------------------------------- ### Transpile Resource Metadata to RFC Format Source: https://context7.com/mcp-auth/python/llms.txt Converts internal resource metadata to the RFC 9728 wire format. This is used for external communication and testing. ```python from mcpauth.utils import transpile_resource_metadata from mcpauth.types import ResourceServerMetadata from mcpauth.config import AuthServerType, AuthorizationServerMetadata, AuthServerConfig auth_server = AuthServerConfig( type=AuthServerType.OIDC, metadata=AuthorizationServerMetadata( issuer="https://auth.example.com/oidc", authorization_endpoint="https://auth.example.com/oidc/auth", token_endpoint="https://auth.example.com/oidc/token", response_types_supported=["code"], code_challenge_methods_supported=["S256"], ), ) internal_metadata = ResourceServerMetadata( resource="https://api.example.com/mcp", authorization_servers=[auth_server], scopes_supported=["read:data"], ) wire_metadata = transpile_resource_metadata(internal_metadata) print(wire_metadata.resource) # "https://api.example.com/mcp" print(wire_metadata.authorization_servers) # ["https://auth.example.com/oidc"] print(wire_metadata.scopes_supported) # ["read:data"] ``` -------------------------------- ### Create Low-level JWT Verifier Factory Source: https://context7.com/mcp-auth/python/llms.txt Creates a reusable `VerifyAccessTokenFunction` from a JWKS URI, PyJWKClient, or PyJWK. Supports RSA, PSS, and EC algorithms by default. Useful for custom middleware or tests. ```python from mcpauth.utils import create_verify_jwt from mcpauth.exceptions import MCPAuthTokenVerificationException # From a JWKS URI verify = create_verify_jwt( "https://auth.example.com/.well-known/jwks.json", algorithms=["RS256", "ES256"], leeway=60, ) try: auth_info = verify("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...") print(auth_info.subject) # "user-123" print(auth_info.scopes) # ["read:items"] print(auth_info.issuer) # "https://auth.example.com/oidc" print(auth_info.claims) # Full decoded payload dict except MCPAuthTokenVerificationException as e: # e.code: "invalid_token" | "token_verification_failed" print(f"Token rejected: {e.code} — {e.message}") # From a pre-configured PyJWKClient (useful for caching / custom headers) from jwt import PyJWKClient jwks_client = PyJWKClient( "https://auth.example.com/.well-known/jwks.json", headers={"User-Agent": "my-app/1.0"}, cache_keys=True, ) verify_with_client = create_verify_jwt(jwks_client) ``` -------------------------------- ### Set MCP Auth Issuer Environment Variable Source: https://github.com/mcp-auth/python/blob/master/samples/README.md Configure the required environment variable for the MCP Auth issuer URL. ```bash export MCP_AUTH_ISSUER= ``` -------------------------------- ### Access Authenticated Request Context with AuthInfo Source: https://context7.com/mcp-auth/python/llms.txt The `AuthInfo` Pydantic model holds verified token details. Access it via `mcp_auth.auth_info` within synchronous tool handlers. Check for token presence and required scopes. ```python from mcpauth import MCPAuth from mcpauth.exceptions import MCPAuthBearerAuthException, BearerAuthExceptionCode mcp_auth = MCPAuth(protected_resources=[...]) @mcp.tool() def get_profile() -> dict: auth_info = mcp_auth.auth_info # auth_info fields: # .token – raw Bearer token string # .issuer – "https://auth.example.com/oidc" # .subject – "user-abc123" # .client_id – "my-mcp-client" (from client_id or azp claim) # .scopes – ["read:profile", "write:profile"] # .audience – "https://api.example.com/mcp" (str or list[str]) # .claims – {"sub": "user-abc123", "exp": 1700000000, ...} if not auth_info: raise MCPAuthBearerAuthException(BearerAuthExceptionCode.MISSING_BEARER_TOKEN) if "read:profile" not in auth_info.scopes: raise MCPAuthBearerAuthException(BearerAuthExceptionCode.MISSING_REQUIRED_SCOPES) return { "user_id": auth_info.subject, "client": auth_info.client_id, "scopes": auth_info.scopes, "custom_claim": auth_info.claims.get("my_org_role"), } ``` -------------------------------- ### resource_metadata_router Source: https://context7.com/mcp-auth/python/llms.txt Serves the OAuth 2.0 Protected Resource Metadata document at `/.well-known/oauth-protected-resource[/]`. MCP clients discover this endpoint to learn which authorization servers can issue tokens for this resource and which scopes are supported. ```APIDOC ## `resource_metadata_router` — Serve Protected Resource Metadata Returns a Starlette `Router` that serves the OAuth 2.0 Protected Resource Metadata document at `/.well-known/oauth-protected-resource[/]` as required by RFC 9728. MCP clients discover this endpoint to learn which authorization servers can issue tokens for this resource and which scopes are supported. Mount it at the root alongside the MCP app routes. ### Usage ```python from starlette.applications import Starlette from starlette.routing import Mount from starlette.middleware import Middleware import contextlib mcp_auth = MCPAuth(protected_resources=[...]) # configured as above @contextlib.asynccontextmanager async def lifespan(app: Starlette): async with mcp.session_manager.run(): yield app = Starlette( routes=[ # Exposes GET /.well-known/oauth-protected-resource # (or /.well-known/oauth-protected-resource/mcp for resource_id ending in /mcp) *mcp_auth.resource_metadata_router().routes, Mount( "/", app=mcp.streamable_http_app(), middleware=[Middleware(mcp_auth.bearer_auth_middleware("jwt", resource=resource_id))], ), ], lifespan=lifespan, ) # Verify the metadata endpoint manually: # curl http://localhost:3001/.well-known/oauth-protected-resource # { # "resource": "http://localhost:3001/mcp", # "authorization_servers": ["https://auth.example.com/oidc"], # "scopes_supported": ["read:items", "write:items"], # "bearer_methods_supported": ["header"] # } ``` ``` -------------------------------- ### Create Well-Known Metadata Endpoint URL Source: https://context7.com/mcp-auth/python/llms.txt Constructs the correct RFC 9728 /.well-known/oauth-protected-resource URL for a given resource identifier. This is used in WWW-Authenticate headers and by the metadata router. ```python from mcpauth.utils import create_resource_metadata_endpoint # Root resource url = create_resource_metadata_endpoint("https://api.example.com") print(url) # "https://api.example.com/.well-known/oauth-protected-resource" # Resource with a path component url = create_resource_metadata_endpoint("https://api.example.com/mcp") print(url) # "https://api.example.com/.well-known/oauth-protected-resource/mcp" # The generated URL appears in 401 WWW-Authenticate headers: # WWW-Authenticate: Bearer resource_metadata="https://api.example.com/.well-known/oauth-protected-resource/mcp", # error="invalid_token", # error_description="The provided token is invalid or has expired." ``` -------------------------------- ### AuthInfo Source: https://context7.com/mcp-auth/python/llms.txt `AuthInfo` is the Pydantic model populated after successful token verification. It is stored in the `ContextVar` and accessible via `mcp_auth.auth_info` within any synchronous tool handler called during a request. ```APIDOC ## `AuthInfo` — Authenticated request context `AuthInfo` is the Pydantic model populated after successful token verification. It is stored in the `ContextVar` and accessible via `mcp_auth.auth_info` within any synchronous tool handler called during a request. ### Usage ```python from mcpauth import MCPAuth from mcpauth.exceptions import MCPAuthBearerAuthException, BearerAuthExceptionCode mcp_auth = MCPAuth(protected_resources=[...]) @mcp.tool() def get_profile() -> dict: auth_info = mcp_auth.auth_info # auth_info fields: # .token – raw Bearer token string # .issuer – "https://auth.example.com/oidc" # .subject – "user-abc123" # .client_id – "my-mcp-client" (from client_id or azp claim) # .scopes – ["read:profile", "write:profile"] # .audience – "https://api.example.com/mcp" (str or list[str]) # .claims – {"sub": "user-abc123", "exp": 1700000000, ...} if not auth_info: raise MCPAuthBearerAuthException(BearerAuthExceptionCode.MISSING_BEARER_TOKEN) if "read:profile" not in auth_info.scopes: raise MCPAuthBearerAuthException(BearerAuthExceptionCode.MISSING_REQUIRED_SCOPES) return { "user_id": auth_info.subject, "client": auth_info.client_id, "scopes": auth_info.scopes, "custom_claim": auth_info.claims.get("my_org_role"), } ``` ``` -------------------------------- ### Validate MCP Server Configuration Source: https://context7.com/mcp-auth/python/llms.txt Fetches and validates an AuthServerConfig against MCP specification requirements. Returns a validation result object instead of raising exceptions, allowing for handling of partial compliance. ```python from mcpauth.utils import fetch_server_config, validate_server_config from mcpauth.config import AuthServerType config = fetch_server_config("https://auth.example.com/oidc", AuthServerType.OIDC) result = validate_server_config(config) if result.is_valid: print("Provider is fully MCP-compatible ✓") else: for error in result.errors: # error.code: AuthServerConfigErrorCode enum value # e.g. "pkce_not_supported", "code_response_type_not_supported" print(f"ERROR [{error.code}]: {error.description}") for warning in result.warnings: # e.g. "dynamic_registration_not_supported" print(f"WARN [{warning.code}]: {warning.description}") # Example output for a non-PKCE provider: # ERROR [pkce_not_supported]: The server does not support Proof Key for Code Exchange (PKCE). # WARN [dynamic_registration_not_supported]: Dynamic Client Registration (RFC 7591) is not supported. ``` -------------------------------- ### Bearer Authentication Middleware (Custom Verification) Source: https://context7.com/mcp-auth/python/llms.txt Implements a Starlette middleware using a custom verification function for opaque or introspection tokens. The provided `my_verify` function demonstrates how to handle token introspection and return an `AuthInfo` object or raise an `MCPAuthTokenVerificationException`. ```python from mcpauth.types import AuthInfo from mcpauth.exceptions import MCPAuthTokenVerificationException, MCPAuthTokenVerificationExceptionCode def my_verify(token: str) -> AuthInfo: # Call your introspection endpoint or token store here payload = my_introspect(token) if not payload["active"]: raise MCPAuthTokenVerificationException( MCPAuthTokenVerificationExceptionCode.INVALID_TOKEN ) return AuthInfo( token=token, issuer=payload["iss"], subject=payload["sub"], client_id=payload.get("client_id"), scopes=payload.get("scope", "").split(), claims=payload, ) custom_bearer_mw = Middleware(mcp_auth.bearer_auth_middleware(my_verify, resource=resource_id)) ``` -------------------------------- ### transpile_resource_metadata Source: https://context7.com/mcp-auth/python/llms.txt Converts internal `ResourceServerMetadata` objects to the RFC 9728 wire-format `ProtectedResourceMetadata`. This function is useful for testing and custom serialization, and is also called internally by the metadata router. ```APIDOC ## `transpile_resource_metadata` — Convert internal metadata to RFC format Converts a `ResourceServerMetadata` object (which uses full `AuthServerConfig` objects for `authorization_servers`) into the wire-format `ProtectedResourceMetadata` used by RFC 9728, where `authorization_servers` is a list of issuer URL strings. This is called automatically by the metadata router but is also exposed for use in tests and custom serialization. ```python from mcpauth.utils import transpile_resource_metadata from mcpauth.types import ResourceServerMetadata from mcpauth.config import AuthServerType, AuthorizationServerMetadata, AuthServerConfig auth_server = AuthServerConfig( type=AuthServerType.OIDC, metadata=AuthorizationServerMetadata( issuer="https://auth.example.com/oidc", authorization_endpoint="https://auth.example.com/oidc/auth", token_endpoint="https://auth.example.com/oidc/token", response_types_supported=["code"], code_challenge_methods_supported=["S256"], ), ) internal_metadata = ResourceServerMetadata( resource="https://api.example.com/mcp", authorization_servers=[auth_server], scopes_supported=["read:data"], ) wire_metadata = transpile_resource_metadata(internal_metadata) print(wire_metadata.resource) # "https://api.example.com/mcp" print(wire_metadata.authorization_servers) # ["https://auth.example.com/oidc"] print(wire_metadata.scopes_supported) # ["read:data"] ``` ``` -------------------------------- ### Bearer Authentication Middleware (JWT Mode) Source: https://context7.com/mcp-auth/python/llms.txt Implements a Starlette middleware for JWT verification. It extracts the Bearer token, verifies the signature using the provider's JWKS, and checks issuer, audience, and required scopes. Stores AuthInfo in the context on success and returns RFC-compliant errors on failure. ```python from mcp.server.fastmcp import FastMCP from starlette.applications import Starlette from starlette.routing import Mount from starlette.middleware import Middleware from mcpauth import MCPAuth from mcpauth.config import AuthServerType from mcpauth.types import ResourceServerConfig, ResourceServerMetadata from mcpauth.utils import fetch_server_config import os mcp = FastMCP(name="My MCP Server", stateless_http=True) auth_server = fetch_server_config(os.environ["MCP_AUTH_ISSUER"], AuthServerType.OIDC) resource_id = "https://api.example.com/mcp" mcp_auth = MCPAuth( protected_resources=[ ResourceServerConfig( metadata=ResourceServerMetadata( resource=resource_id, authorization_servers=[auth_server], scopes_supported=["read:items", "write:items"], ) ) ] ) # Built-in JWT mode: verifies signature via provider JWKS, checks issuer bearer_mw = Middleware( mcp_auth.bearer_auth_middleware( "jwt", resource=resource_id, # Required in resource-server mode required_scopes=["read:items"], # 403 if missing audience="https://api.example.com/mcp", # Optional aud check leeway=30, # Seconds of clock skew tolerance show_error_details=False, # Set True during development only ) ) app = Starlette( routes=[ *mcp_auth.resource_metadata_router().routes, Mount("/", app=mcp.streamable_http_app(), middleware=[bearer_mw]), ] ) ``` -------------------------------- ### validate_server_config Source: https://context7.com/mcp-auth/python/llms.txt Validates an AuthServerConfig against MCP specification requirements. It returns a result object indicating validity, errors, and warnings, rather than raising exceptions, allowing for flexible handling of partial compliance. ```APIDOC ## `validate_server_config` — Check MCP specification compliance Validates a fetched `AuthServerConfig` against MCP specification requirements: `code` response type, `authorization_code` grant, PKCE with S256, and (warning only) dynamic client registration. Returns an `AuthServerConfigValidationResult` with `is_valid`, `errors`, and `warnings` lists rather than raising, so callers can decide how to handle partial compliance. ```python from mcpauth.utils import fetch_server_config, validate_server_config from mcpauth.config import AuthServerType config = fetch_server_config("https://auth.example.com/oidc", AuthServerType.OIDC) result = validate_server_config(config) if result.is_valid: print("Provider is fully MCP-compatible ✓") else: for error in result.errors: # error.code: AuthServerConfigErrorCode enum value # e.g. "pkce_not_supported", "code_response_type_not_supported" print(f"ERROR [{error.code}]: {error.description}") for warning in result.warnings: # e.g. "dynamic_registration_not_supported" print(f"WARN [{warning.code}]: {warning.description}") # Example output for a non-PKCE provider: # ERROR [pkce_not_supported]: The server does not support Proof Key for Code Exchange (PKCE). # WARN [dynamic_registration_not_supported]: Dynamic Client Registration (RFC 7591) is not supported. ``` ``` -------------------------------- ### bearer_auth_middleware Source: https://context7.com/mcp-auth/python/llms.txt Provides a Starlette middleware for verifying Bearer tokens (JWT or custom). It extracts the Authorization header, validates the token against issuer, audience, and scopes, and stores authentication information in the context. On failure, it returns appropriate WWW-Authenticate error responses. ```APIDOC ## `bearer_auth_middleware` — JWT / custom token verification middleware Returns a Starlette `BaseHTTPMiddleware` subclass that extracts the `Authorization: Bearer ` header, verifies the token (JWT or custom function), and validates issuer, audience, and required scopes. On success it stores the resulting `AuthInfo` in the context variable. On failure it returns RFC-compliant `WWW-Authenticate` error responses (401 or 403). ```python from mcp.server.fastmcp import FastMCP from starlette.applications import Starlette from starlette.routing import Mount from starlette.middleware import Middleware from mcpauth import MCPAuth from mcpauth.config import AuthServerType from mcpauth.types import ResourceServerConfig, ResourceServerMetadata from mcpauth.utils import fetch_server_config import os mcp = FastMCP(name="My MCP Server", stateless_http=True) auth_server = fetch_server_config(os.environ["MCP_AUTH_ISSUER"], AuthServerType.OIDC) resource_id = "https://api.example.com/mcp" mcp_auth = MCPAuth( protected_resources=[ ResourceServerConfig( metadata=ResourceServerMetadata( resource=resource_id, authorization_servers=[auth_server], scopes_supported=["read:items", "write:items"], ) ) ] ) # Built-in JWT mode: verifies signature via provider JWKS, checks issuer bearer_mw = Middleware( mcp_auth.bearer_auth_middleware( "jwt", resource=resource_id, # Required in resource-server mode required_scopes=["read:items"], # 403 if missing audience="https://api.example.com/mcp", # Optional aud check leeway=30, # Seconds of clock skew tolerance show_error_details=False, # Set True during development only ) ) # Custom verify function — useful for opaque/introspection tokens from mcpauth.types import AuthInfo from mcpauth.exceptions import MCPAuthTokenVerificationException, MCPAuthTokenVerificationExceptionCode def my_verify(token: str) -> AuthInfo: # Call your introspection endpoint or token store here payload = my_introspect(token) if not payload["active"]: raise MCPAuthTokenVerificationException( MCPAuthTokenVerificationExceptionCode.INVALID_TOKEN ) return AuthInfo( token=token, issuer=payload["iss"], subject=payload["sub"], client_id=payload.get("client_id"), scopes=payload.get("scope", "").split(), claims=payload, ) custom_bearer_mw = Middleware(mcp_auth.bearer_auth_middleware(my_verify, resource=resource_id)) app = Starlette( routes=[ *mcp_auth.resource_metadata_router().routes, Mount("/", app=mcp.streamable_http_app(), middleware=[bearer_mw]), ] ) ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.