
Put a Lock on Your MCP Server: Add OAuth 2.1 to FastMCP in 20 Lines
Chris Harper
2 min read
Jul 20, 2026 · 12:09 UTC
TL;DR: FastMCP 3.x ships four auth strategies including JWTVerifier and OAuth proxy — add auth=JWTVerifier(...) to your constructor and every unauthenticated caller is blocked before your tools run.
The FastMCP quickstart and resources/prompts tutorials build servers that work great locally. But expose one over the network — for a team, a remote Claude Code session, or a Streamable HTTP endpoint — and every unauthenticated caller can invoke your tools. FastMCP 3.x (v3.2.4, April 2026) solves this with a single constructor argument; your tool code stays unchanged.
Four auth strategies
from fastmcp.auth import (
JWTVerifier, # accept JWTs from a known issuer (Auth0, Supabase, your IdP)
RemoteOAuth, # providers with OAuth Dynamic Client Registration (Keycloak)
OAuthProxy, # providers without DCR: GitHub, Google, Azure
)
JWTVerifier — the right default for most teams
You control the issuer; FastMCP validates the token signature and claims on every inbound request:
from fastmcp import FastMCP
from fastmcp.auth import JWTVerifier
mcp = FastMCP(
"internal-tools",
auth=JWTVerifier(
jwks_uri="https://your-auth0-domain/.well-known/jwks.json",
issuer="https://your-auth0-domain/",
audience="https://api.yourcompany.com",
)
)
@mcp.tool()
def get_customer(customer_id: str) -> dict:
"""Fetches a customer record — only reachable with a valid token."""
return db.customers.get(customer_id)
if __name__ == "__main__":
mcp.run(transport="streamable-http", port=8000)
OAuth proxy for GitHub/Google/Azure
These providers don't support OAuth Dynamic Client Registration, so FastMCP wraps them transparently:
from fastmcp.auth import OAuthProxy
mcp = FastMCP(
"github-tools",
auth=OAuthProxy(
provider="github",
client_id="your-github-app-client-id",
client_secret="your-github-app-client-secret",
scopes=["read:user", "repo"],
)
)
Test with MCP Inspector before wiring up Claude
npx @modelcontextprotocol/inspector
Paste your server URL (http://localhost:8000/mcp) and a test bearer token in the browser UI. Inspector lets you call tools interactively and see exactly what the auth middleware accepts or rejects — before you connect Claude Desktop or Claude Code.
Why PKCE matters for remote servers
The MCP spec mandates OAuth 2.1 with PKCE (Proof Key for Code Exchange) for any server accessed over the network. PKCE drops the client secret from the token exchange — MCP clients run on dev laptops and CI containers where secrets can't be stored safely.
Sources: MCP Authorization — modelcontextprotocol.io · MCP Authentication with FastMCP — PropelAuth · FastMCP Python Guide 2026 — danilchenko.dev · FastMCP — PyPI