Quickstart — 5 Minutes to Working MCP Auth
Prerequisites
Section titled “Prerequisites”- Docker (for Authgent)
- An MCP server (Python/FastMCP, TypeScript, or Go)
- Optional: PostgreSQL (SQLite used by default for dev)
Step 1 — Generate signing keys
Section titled “Step 1 — Generate signing keys”# Generate an EC P-256 key pair for JWT signingopenssl ecparam -genkey -name prime256v1 -noout -out ec-private.pemopenssl ec -in ec-private.pem -pubout -out ec-public.pem
# Store securely — this signs all your tokenschmod 600 ec-private.pemStep 2 — Run Authgent
Section titled “Step 2 — Run Authgent”docker run -d \ --name authgent \ -p 8080:8080 \ -v $(pwd)/ec-private.pem:/keys/ec-private.pem:ro \ -e AUTHGENT_ISSUER=http://localhost:8080 \ -e AUTHGENT_SIGNING_KEY=/keys/ec-private.pem \ -e AUTHGENT_SIGNING_ALG=ES256 \ -e AUTHGENT_DB_DSN=sqlite:///data/authgent.db \ authgent/authgent:latestVerify it’s running:
curl http://localhost:8080/.well-known/oauth-authorization-server | jq .Expected output:
{ "issuer": "http://localhost:8080", "authorization_endpoint": "http://localhost:8080/oauth/authorize", "token_endpoint": "http://localhost:8080/oauth/token", "registration_endpoint": "http://localhost:8080/oauth/register", "jwks_uri": "http://localhost:8080/.well-known/jwks.json", "response_types_supported": ["code"], "grant_types_supported": ["authorization_code", "client_credentials", "refresh_token"], "code_challenge_methods_supported": ["S256"], "token_endpoint_auth_methods_supported": ["none", "client_secret_basic", "private_key_jwt"]}Step 3 — Protect your MCP server
Section titled “Step 3 — Protect your MCP server”FastMCP (Python)
Section titled “FastMCP (Python)”# Install: pip install fastmcpfrom fastmcp import FastMCPfrom fastmcp.server.auth import RemoteAuthProvider
auth = RemoteAuthProvider( authorization_server_url="http://localhost:8080", audience="http://localhost:8000", required_scopes=["mcp:read"],)
mcp = FastMCP(name="My Server", auth=auth)
@mcp.tool()async def hello(name: str) -> str: """Say hello. Requires mcp:read scope.""" return f"Hello, {name}!"
if __name__ == "__main__": mcp.run(transport="http", host="0.0.0.0", port=8000, path="/mcp")TypeScript SDK
Section titled “TypeScript SDK”// Install: npm install @modelcontextprotocol/sdk jose expressimport { createRemoteJWKSet, jwtVerify } from "jose";import express from "express";
const JWKS = createRemoteJWKSet( new URL("http://localhost:8080/.well-known/jwks.json"));
const app = express();
// Protected Resource Metadata — MCP clients discover auth requirements hereapp.get("/.well-known/oauth-protected-resource", (req, res) => { res.json({ resource: "http://localhost:8000", authorization_servers: ["http://localhost:8080"], });});
// Auth middlewareapp.use("/mcp", async (req, res, next) => { const token = req.headers.authorization?.slice(7); if (!token) return res.status(401).json({ error: "missing_token" }); try { const { payload } = await jwtVerify(token, JWKS, { issuer: "http://localhost:8080", audience: "http://localhost:8000", }); (req as any).auth = payload; next(); } catch { res.status(401).json({ error: "invalid_token" }); }});// go get github.com/authgent/authgent-goimport ( "github.com/authgent/authgent-go/verifier" "net/http")
v, _ := verifier.New(verifier.Config{ Issuer: "http://localhost:8080", Audience: "http://localhost:8000", JWKSURL: "http://localhost:8080/.well-known/jwks.json",})
mux := http.NewServeMux()mux.Handle("/mcp", v.RequireAuth()(yourMCPHandler))http.ListenAndServe(":8000", mux)Step 4 — Connect an MCP client
Section titled “Step 4 — Connect an MCP client”Claude Desktop
Section titled “Claude Desktop”Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{ "mcpServers": { "my-server": { "url": "http://localhost:8000/mcp", "transport": "http" } }}Claude will detect the /.well-known/oauth-protected-resource response, redirect to Authgent’s authorization endpoint, and complete the OAuth flow automatically.
Cursor
Section titled “Cursor”In Cursor settings → MCP → Add server:
- URL:
http://localhost:8000/mcp - Auth: OAuth (auto-detected)
MCP Inspector (testing)
Section titled “MCP Inspector (testing)”npx @modelcontextprotocol/inspector http://localhost:8000/mcpThe inspector handles the OAuth flow automatically and shows all available tools.
Step 5 — Verify token contents
Section titled “Step 5 — Verify token contents”After a successful auth flow, Authgent issues JWTs like this:
{ "iss": "http://localhost:8080", "sub": "user_abc123", "aud": "http://localhost:8000", "exp": 1700000300, "iat": 1700000000, "jti": "tok_xyz", "scope": "mcp:read", "email": "user@yourcompany.com", "name": "Alice"}Decode any token at jwt.io or:
echo "YOUR_TOKEN" | cut -d. -f2 | base64 -d | jq .