Skip to main content

FastAuthMCP

FastAuthMCP logo

Identity infrastructure for AI agents.

CI PyPI Python 3.11+ License


When an AI agent calls your MCP tools — who is the human behind the request? What are they allowed to do? How do you forward their credentials to downstream APIs?

FastAuthMCP answers these questions. It's an identity runtime that authenticates humans, propagates their identity into tool functions, and forwards user-scoped tokens to enterprise APIs. One config file. Zero changes to your tools.


The Problem

The Model Context Protocol defines how AI agents interact with tools. It says nothing about identity.

Every team building production MCP servers re-invents authentication, authorization, and token propagation from scratch. There is no standard. No shared infrastructure. No reference implementation.

Your MCP server works on your laptop. Then your security team asks:

  • Who is calling these tools?
  • What are they allowed to do?
  • Where's the audit trail?
  • How do downstream APIs get a user-scoped token?

You start building OAuth. Then token refresh. Then per-user propagation. Then authorization. Weeks pass.

The Solution

FastAuthMCP sits between MCP clients and your tools:

┌─────────────────────────────────────────────┐
│  MCP Client (Claude, Gemini, Cursor, etc.)  │
└──────────────────────┬──────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────┐
│              FastAuthMCP                    │
│                                             │
│  Authenticate → Authorize → Propagate      │
│                                             │
│  identity()       @require_roles("admin")   │
│  access_token()   sessions, observability   │
└──────────────────────┬──────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────┐
│  Your Tools → Downstream APIs (Stripe,      │
│  GitHub, SAP, internal services...)         │
└─────────────────────────────────────────────┘
  • Authenticates the human — OAuth2, PKCE, or token exchange
  • Propagates identity — identity() returns who is calling, in every tool
  • Forwards user-scoped tokens — access_token() for downstream API calls
  • Enforces authorization — @require_roles("admin") per tool
  • Works identically — local (stdio + browser) and cloud (HTTP + token exchange)

Quick Start

1. Install

pip install fastauthmcp

2. Change one import

# Before
from fastmcp import FastMCP

# After
from fastauthmcp import FastMCP

Without a config file, this behaves identically to vanilla FastMCP. No overhead.

3. Add identity

Create fastauthmcp.yaml:

auth:
  provider: oidc
  issuer: https://your-idp.example.com
  client_id: your-app
  scopes: [openid, profile, email]

Use identity in your tools:

from fastauthmcp import FastMCP, identity, access_token

mcp = FastMCP("my-server", config="fastauthmcp.yaml")

@mcp.tool()
def whoami() -> dict:
    user = identity()
    return {"email": user.email, "roles": sorted(user.roles)}

@mcp.tool()
def get_orders() -> list:
    token = access_token()  # User-scoped, auto-refreshed
    return httpx.get(
        "https://api.internal.com/orders",
        headers={"Authorization": f"Bearer {token}"},
    ).json()

That's it. Every tool call is now authenticated. The token is always valid — auto-refreshed by the middleware before your code runs.

How It Works

Local: Browser login (Claude Desktop, Cursor)

auth:
  provider: oidc
  issuer: https://your-idp.example.com
  client_id: my-app
  grant_type: authorization_code  # default

First tool call → browser opens → user logs in → token stored in Keychain → all subsequent calls authenticated. No user interaction after the first login.

Cloud: Token exchange (Gemini, remote agents)

auth:
  provider: oidc
  issuer: https://your-idp.example.com
  client_id: cloud-mcp-server
  client_secret: ${FASTAUTHMCP_AUTH_CLIENT_SECRET}
  grant_type: token_exchange
  upstream_token_header: x-user-token
  token_exchange_audience: https://api.internal.com

The calling platform passes a user token → FastAuthMCP exchanges it at the IDP → your tool gets a downstream-scoped token via access_token(). No browser. Per-user scoping.

Machine-to-Machine (headless services)

auth:
  provider: oidc
  issuer: https://your-idp.example.com
  client_id: my-service
  client_secret: ${FASTAUTHMCP_AUTH_CLIENT_SECRET}
  grant_type: client_credentials

Identity Primitives

from fastauthmcp import identity, access_token, require_roles

@mcp.tool()
def whoami() -> dict:
    user = identity()          # Who is calling this tool?
    return {"email": user.email, "subject": user.subject}

@mcp.tool()
def call_api() -> dict:
    token = access_token()     # Forward to downstream APIs
    return httpx.get(url, headers={"Authorization": f"Bearer {token}"}).json()

@mcp.tool()
@require_roles("admin")        # Per-tool authorization
def admin_action() -> str:
    return "access granted"

Supported Platforms

MCP Clients

Platform Transport Guide
Claude Desktop stdio Guide
Google Gemini SSE/HTTP Guide
Cursor IDE SSE Guide
Custom agents Any Guide

Identity Providers

Provider Auth Code Client Credentials Token Exchange Guide
Zitadel ✓ ✓ ✓ (RFC 8693) Guide
Keycloak ✓ ✓ ✓ Guide
Auth0 ✓ ✓ via Actions Guide
Azure Entra ID ✓ ✓ ✓ (OBO) Guide
Okta ✓ ✓ ✓ Guide
Google Cloud ✓ ✓ ✓ (STS) Guide
Any OIDC provider ✓ ✓ ✓ —

Compatibility Lab

FastAuthMCP includes an automated interoperability suite — 34 scenarios validating every provider × flow × security check:

  Authentication ──────────────
  ✓ ZITADEL Auth Code + PKCE → identity propagation
  ✓ Keycloak Client Credentials → service identity
  ✓ Auth0, Azure, Okta — same

  Authorization ─────────────
  ✓ Admin role → tool allowed
  ✓ Viewer role → tool rejected

  Security ────────────────
  ✓ Expired token → rejected
  ✓ Wrong issuer → rejected
  ✓ Wrong audience → rejected

  Result: 34 passed, 0 failed (300ms)
./lab.sh          # Run all scenarios
make lab-ui       # Interactive TUI with LLM + MCP tools

Why FastAuthMCP?

FastAuthMCP DIY API Gateway
Setup 5 minutes Weeks Hours + infra
MCP-aware ✓ ✗ ✗
Identity in tools identity() Manual Not possible
Token forwarding access_token() Build it Depends
Per-tool auth Decorators Build it Route-level
Lock-in None (remove import) — Vendor
Infrastructure None (in-process) None Separate service

Architecture

FastAuthMCP wraps FastMCP via composition. Your tools, prompts, and resources stay unchanged. Remove FastAuthMCP and your app still works.

Request → Observability → Session → Authentication → Authorization → Your Tool

Each layer activates only when its section is present in fastauthmcp.yaml. Omit a section to disable it entirely.

Configuration

All configuration lives in fastauthmcp.yaml. Every section is optional.

auth:
  provider: oidc
  issuer: https://idp.example.com
  client_id: your-client-id
  grant_type: authorization_code
  scopes: [openid, profile, email]
  callback_port: 9876

observability:
  enabled: true
  exporter: otlp
  log_format: json

sessions:
  ttl: 3600

Full reference: docs/GUIDE.md

CLI

fastauthmcp login     # Browser login, store token
fastauthmcp whoami    # Show current identity
fastauthmcp doctor    # Check config + IDP connectivity
fastauthmcp run       # Start the server

Testing

Test without a live IDP:

from fastauthmcp.testing import FastAuthMCPTestClient

client = FastAuthMCPTestClient(app=mcp, email="admin@co.com", roles=["admin"])
result = await client.call_tool("whoami")
assert result["email"] == "admin@co.com"

Documentation

Resource Description
Full Guide Complete integration & development reference
Integration Guides Per-platform and per-IDP setup
Examples Working code samples
Compatibility Lab Automated interoperability suite

Installation Extras

pip install fastauthmcp                # Core (auth, identity, CLI)
pip install fastauthmcp[observability]  # + OpenTelemetry + Prometheus
pip install fastauthmcp[soap]           # + SOAP/XML downstream support
pip install fastauthmcp[keyring]        # + Platform-native token storage
pip install fastauthmcp[dev]            # + Testing tools

Contributing

See CONTRIBUTING.md for guidelines.

git clone https://github.com/enzomar/fastauthmcp.git
cd fastauthmcp
pip install -e ".[dev]"
pytest                        # 359 tests
python -m fastauthmcp.lab run # 34 compatibility scenarios
make lab-ui                   # Interactive TUI

Support

If FastAuthMCP is useful to you:

PayPal

License

Apache 2.0 — see LICENSE.

Metadata

Release files for fastauthmcp 0.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastauthmcp 0.1.5
File Size Uploaded Provenance Actions
fastauthmcp-0.1.5.tar.gz 1.3 MB With provenance Details for fastauthmcp-0.1.5.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for fastauthmcp 0.1.5
File Interpreter ABI Platform Actions
fastauthmcp-0.1.5-py3-none-any.whl Python 3 none any Details for fastauthmcp-0.1.5-py3-none-any.whl

Total release size: 1.4 MB

Release files / fastauthmcp-0.1.5.tar.gz

Download URL fastauthmcp-0.1.5.tar.gz
Size 1.3 MB
Tags Source
SHA-256 checksum
How to use checksums
79bf8572f6debdf6aaeb4d191695dea6391959036a0c656a666cd3322944c1f6
BLAKE2b-256 checksum
How to use checksums
580f181c69da0a09c8facd181ff437b0b086bf4683453fa78c37cb9f7c010a20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.

Transparency log

Release files / fastauthmcp-0.1.5-py3-none-any.whl

Download URL fastauthmcp-0.1.5-py3-none-any.whl
Size 127.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0b7cafb8542901ad68c012195a4d1fe42b9f02ff9043336fef15238510baba78
BLAKE2b-256 checksum
How to use checksums
f5ef0a2c4ee890de20c90df50a950a78b83bbbe574fef83b1d0724e60dbfd56b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.

Transparency log

Security for fastauthmcp 0.1.5

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for fastauthmcp-0.1.5.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 18, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page