One OAuth resource
/mcp/oauth accepts OAuth-issued bearer tokens from auth-code,
device, and client-credentials grants, while keeping resource, audience,
issuer, and PKCE behavior visible.
This project gives you two things: a FastAPI server with intentionally
separate MCP auth surfaces, and a standalone mcp-auth CLI that
can discover and exercise those surfaces end to end.
/mcp/oauth accepts OAuth-issued bearer tokens from auth-code,
device, and client-credentials grants, while keeping resource, audience,
issuer, and PKCE behavior visible.
/mcp/bearer-token is deliberately simpler and does not
participate in discovery or token issuance, which makes bearer-only
client behavior easy to isolate.
The CLI is resource-centric, not server-specific. It discovers metadata, selects an auth mode, saves profiles, and keeps tokens valid across dynamic registration and seeded CIMD fixture clients.
The mounted app also exposes read-only /debug/* endpoints, a
tool-policy model with scope declarations and argument validation, and seeded
dev-* fixture clients that let you exercise common flows without a
registration step. flowchart TD
classDef primary fill:#0f172a,stroke:#93c5fd,color:#e5e7eb,stroke-width:1.5px;
classDef secondary fill:#111827,stroke:#7dd3fc,color:#e5e7eb,stroke-width:1.5px;
classDef decision fill:#1e293b,stroke:#fcd34d,color:#e5e7eb,stroke-width:1.5px;
classDef tertiary fill:#172554,stroke:#a5b4fc,color:#e5e7eb,stroke-width:1.5px;
classDef success fill:#1f2937,stroke:#86efac,color:#e5e7eb,stroke-width:1.5px;
classDef failure fill:#3f1d2e,stroke:#fda4af,color:#e5e7eb,stroke-width:1.5px;
CLI["mcp-auth CLI"]:::secondary
APP["app.py\nFastAPI entrypoint"]:::primary
DOCS["/docs, /redoc,\n/docs/oauth-callback"]:::tertiary
subgraph MR["Mounted routers"]
direction TB
BEARER["/mcp/bearer-token\n/test-auth/bearer-token/mint"]:::primary
OAUTH["/mcp/oauth\n/oauth/*"]:::primary
DCR["/oauth/register"]:::secondary
DISC["/.well-known/*"]:::secondary
DEBUG["/debug/*"]:::secondary
end
subgraph CORE["Auth and policy core"]
direction TB
AUTH["auth/*.py"]:::tertiary
POLICY["mcp/policy.py\nmcp/tools.py"]:::tertiary
STORE[("InMemoryTokenStore")]:::success
end
ALT["Source-defined alternate routers:\noauth_v2_2l.py, device_flow.py, oauth_v21.py"]:::decision
CLI --> DISC
CLI --> OAUTH
APP --> BEARER
APP --> OAUTH
APP --> DCR
APP --> DISC
APP --> DEBUG
APP --> DOCS
BEARER --> AUTH
OAUTH --> AUTH
OAUTH --> POLICY
DCR --> AUTH
AUTH --> STORE
POLICY --> STORE
DEBUG --> STORE
ALT --> AUTH uv sync --dev
uv run uvicorn mcp_auth_test_server.app:app --reload --port 8765 In a second terminal:
uv run mcp-auth discover http://127.0.0.1:8765/mcp/oauth
uv run mcp-auth login http://127.0.0.1:8765/mcp/oauth
uv run mcp-auth call http://127.0.0.1:8765/mcp/oauth initialize When you run mcp-auth login --auth-mode auth-code, the CLI
starts a localhost callback listener, prints the consent URL, and waits for
the browser redirect in the background.
If you need the endpoint inventory or want the policy/debug details in one place, start with the reference page.
Most auth test fixtures blur different schemes together. This one does the opposite: each auth surface stays explicit, and the shared OAuth resource keeps resource, issuer, PKCE, policy, and refresh behavior visible enough to test against.