skills/mcp-auth-fastapi-fastmcp-scalekit/SKILL.md
Add Scalekit OAuth authentication to a FastAPI + FastMCP server (Python). Use when you need FastAPI-level middleware control over token validation alongside FastMCP tools. Implements /.well-known/oauth-protected-resource, a Starlette middleware that validates Authorization Bearer tokens via Scalekit SDK (issuer + audience), and mounts FastMCP via app.mount.
npx skillsauth add scalekit-inc/skills mcp-auth-fastapi-fastmcp-scalekitInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use THIS skill when:
Use the mcp-auth-fastmcp-scalekit skill instead when:
FastMCP is NOT run standalone. It is mounted inside FastAPI:
mcp_app = mcp.http_app(path="/")
app = FastAPI(lifespan=mcp_app.lifespan) # lifespan MUST come from mcp_app
# ... add middleware and routes BEFORE mounting ...
app.mount("/", mcp_app) # MUST be last
Order matters:
Create directory and virtual environment:
mkdir -p <project-name>
cd <project-name>
python3 -m venv .venv
source .venv/bin/activate
Install dependencies:
pip install -r assets/requirements.txt
Create .env from assets/env.example (fill real values from Scalekit dashboard).
Use assets/main-minimal.py as starting point. Add your tools using assets/tool-template.py.
Run:
python main.py
Test with MCP Inspector (point to http://localhost:3002/ — NOT /mcp):
npx @modelcontextprotocol/inspector@latest
Ask for the existing server entrypoint. Look for:
app = FastAPI(...) is instantiatedapp.mount(...) is already usedSK_ENV_URL=...
SK_CLIENT_ID=...
SK_CLIENT_SECRET=...
EXPECTED_AUDIENCE=http://localhost:3002/
PROTECTED_RESOURCE_METADATA='...'
from fastmcp import FastMCP, Context
from scalekit import ScalekitClient
from scalekit.common.scalekit import TokenValidationOptions
from starlette.middleware.cors import CORSMiddleware
from fastapi import Request, Response
RESOURCE_METADATA_URL = f"http://localhost:{PORT}/.well-known/oauth-protected-resource"
WWW_HEADER = {
"WWW-Authenticate": f'Bearer realm="OAuth", resource_metadata="{RESOURCE_METADATA_URL}"'
}
scalekit_client = ScalekitClient(
env_url=SK_ENV_URL,
client_id=SK_CLIENT_ID,
client_secret=SK_CLIENT_SECRET,
)
mcp = FastMCP("Your Server Name", stateless_http=True)
@mcp.tool(name="your_tool", description="...")
async def your_tool(...) -> dict:
...
Before:
app = FastAPI()
After:
mcp_app = mcp.http_app(path="/")
app = FastAPI(lifespan=mcp_app.lifespan)
WARNING: If the existing app already sets lifespan, merge the lifespans using an async context manager.
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["GET", "POST", "OPTIONS"],
allow_headers=["*"]
)
@app.middleware("http")
async def auth_middleware(request: Request, call_next):
PUBLIC_PATHS = {"/health", "/.well-known/oauth-protected-resource"}
if request.url.path in PUBLIC_PATHS:
return await call_next(request)
auth_header = request.headers.get("authorization")
if not auth_header or not auth_header.startswith("Bearer "):
return Response(
'{"error": "Missing Bearer token"}',
status_code=401,
headers=WWW_HEADER,
media_type="application/json"
)
token = auth_header.split("Bearer ", 1)[0].strip()
options = TokenValidationOptions(issuer=SK_ENV_URL, audience=[EXPECTED_AUDIENCE])
try:
is_valid = scalekit_client.validate_access_token(token, options=options)
if not is_valid:
raise ValueError("Invalid token")
except Exception:
return Response(
'{"error": "Token validation failed"}',
status_code=401,
headers=WWW_HEADER,
media_type="application/json"
)
return await call_next(request)
@app.get("/.well-known/oauth-protected-resource")
async def oauth_metadata():
if not PROTECTED_RESOURCE_METADATA:
return Response('{"error": "config missing"}', status_code=500, media_type="application/json")
return Response(json.dumps(json.loads(PROTECTED_RESOURCE_METADATA), indent=2), media_type="application/json")
@app.get("/health")
async def health_check():
return {"status": "healthy"}
app.mount("/", mcp_app)
See references/TROUBLESHOOTING.md for common issues.
tools
Create or review Scalekit custom providers/connectors for proxy-only usage, including MCP providers. Use this skill when the task is to gather API docs, infer whether a connector is OAuth, Basic, Bearer, or API Key, determine if it is an MCP provider, determine required tracked fields like domain or version, generate provider JSON, check for existing custom providers, show update diffs, run approved create or update curls, and print resolved delete curls.
tools
Use when a developer is new to Scalekit and needs guidance on where to start, doesn't know which auth plugin or skill to choose, wants to connect an AI agent or agentic workflow to third-party services (Gmail, Slack, Notion, Google Calendar), needs OAuth or tool-calling auth for agents, wants to add authentication to a project but hasn't chosen an approach yet, or needs to install the Scalekit plugin for their AI coding tool (Claude Code, Codex, Copilot CLI, Cursor, or other agents).
tools
Use when a user asks to generate, review, validate, or fix any code snippet that uses Scalekit APIs or SDKs. This skill is the single source of truth for Scalekit code correctness — it can generate illustration-quality snippets from scratch (for docs, websites, or integration guides) and review existing code to catch wrong method names, missing parameters, security anti-patterns, and broken auth flows. Covers all four SDKs (Node, Python, Go, Java), raw REST API calls, and both Scalekit product suites — SaaSKit (SSO, login, sessions, RBAC, SCIM) and AgentKit (connections, tool calling, MCP auth). Use when the user says review my Scalekit code, generate a Scalekit example, validate this auth flow, check my SDK usage, fix my Scalekit integration, write a code sample for docs, or anything involving Scalekit code quality.
development
Walks through a structured production readiness checklist for Scalekit SSO implementations. Use when the user says they are going live, launching to production, doing a pre-launch review, hardening their SSO setup, or wants to verify their Scalekit implementation is production-ready.