CloudCodeTree LogoCloudCodeTree
AI NewsTutorialsAbout
CloudCodeTree Logo
CloudCodeTree
  • AI News
  • Tutorials
  • About
← Back to AI News
Put a Lock on Your MCP Server: Add OAuth 2.1 to FastMCP in 20 Lines

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

AI
Workflow
MCP
Agents
Best Practices

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