MCP starter kit
FastAPI + Supabase + OAuth2 (PKCE) + SSE/Streamable HTTP. Works with Claude Desktop, Claude.ai custom connectors, and Cursor—out of the box.
✨ TL;DR for the capabilities
Swipe through what makes this starter kit special
Scroll or click to see all capabilities
Quick Start
Pick your path
One-line bring-up
cd backend && uv sync && uv run uvicorn app.main:app --reloadWhen stuck, run: ./scripts/preflight.sh && npx @modelcontextprotocol/inspector
FAST Start Guide
The 6 things we fix
Real problems, concrete solutions. Each fix addresses a specific pain point that stops teams from shipping MCP servers.
1) Auth that sticks
Claude.ai/Desktop flows (PKCE, refresh) often half-work; user context disappears.
Full OAuth2 + PKCE, short-lived access tokens with auto-refresh, get_current_user injected into every tool.
@router.post("/api/v1/tools/items.create", response_model=Item)
def create(input: CreateItemInput, user=Depends(get_current_user)):
return repo.create_item(owner_id=user.id, **input.model_dump())2) Streaming that doesn't flake
SSE timeouts, proxies, dropped connections → partial results.
SSE with heartbeats + graceful cleanup; Streamable HTTP fallback for hostile networks.
return EventSourceResponse(gen(), ping=15) # heartbeat keeps streams alive3) Data isolation by default
Hand-rolled WHERE owner_id = ? leaks in multi-tenant demos.
Postgres Row-Level Security (RLS) via Supabase; policies enforce per-user/org access.
ALTER TABLE items ENABLE ROW LEVEL SECURITY;
CREATE POLICY items_owner ON items
USING (owner_id = auth.uid()) WITH CHECK (owner_id = auth.uid());4) First success in minutes (not days)
Blank servers don't demo; teams stall before value.
Working CRUD tools + a 3-step Quickstart (clone → .env → run → connect → items.create).
Endpoint: /api/v1/mcp/sse
Claude.ai (HTTPS): https://{PUBLIC_BASE_URL}/api/v1/mcp/sse
Desktop (Local): http://127.0.0.1:8000/api/v1/mcp/sse5) Operable under bursty loads
Tail-latency spikes, silent timeouts, no breadcrumbs.
Async FastAPI, pooled DB, bounded concurrency & back-pressure, sensible timeouts; /health + structured logs with request IDs.
No code example
6) Runs anywhere, quickly
"Works on my laptop" + platform-specific wiring hell.
Containerized app with copy-paste deploys (Docker, Cloud Run, K8s, Render, Railway, ECS, ACI) and HTTPS/local endpoints for Claude.
FROM python:3.11-slim
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN pip install uv && uv sync --frozen
COPY app ./app
CMD ["uv","run","uvicorn","app.main:app","--host","0.0.0.0","--port","8000"]One-liner:
MCP Starter Kit makes Claude MCP boring in all the right ways—auth that sticks, streams that don't flake, data that stays in its lane—so you can ship real tools fast, anywhere.
What this project does
MCP Starter Kit is a production-ready Model Context Protocol server built on FastAPI (Python 3.11+) with Postgres 15+ (via Supabase RLS) and OAuth2/OIDC + PKCE. It gives you a protocol-correct transport, real auth/tenancy, and a clean tool surface that streams results.
Transport (protocol-correct)
- •Streamable HTTP endpoint at
POST /mcp(JSON-RPC 2.0 requests; supports server-to-client streaming for long jobs). - •SSE compatibility at
GET /mcp/ssewith unified event shapes. - •Back-pressure, idle timeouts, and resumable streams for long-running tools.
Auth & Discovery (no bespoke glue)
- •OIDC discovery exposed under
/.well-known/oauth-authorization-server. - •Authorization Code + PKCE required for desktop/native clients.
- •Access tokens → request context; structured JWT claims (sub, tenant) propagate to handlers.
Tenancy & Data Safety (by construction)
- •Row-Level Security on all user/tenant tables; policies use JWT claims for scoping.
- •Separate service role for admin/automation (kept out of request paths).
- •End-to-end request IDs and structured logs on every tool call.
Tool Surface (small, composable)
- •Registry-driven tools: CRUD, Search, Job patterns.
- •Handlers are stream-capable (progress + partials) and JSON-schema described.
- •Clear seams: transport → auth → handler → domain/service/DB.
Ops Rails (ship without yak-shaving)
- •Health/readiness:
GET /healthz,GET /readyz. - •Sensible defaults: timeouts, connection pooling, retry/backoff, and consistent error envelopes.
- •Dockerfile + DB migrations; env-first config (
MCP_*,OAUTH_*,DB_*).
Client Compatibility (drop-in)
- •Works with common MCP hosts (e.g., Claude Desktop, Inspector).
- •Standard flow:
tools/list→tools/call(streamed) → final result.
At a glance (filesystem map)
/app
/mcp # transport wiring, JSON-RPC, streaming
/auth # OIDC discovery, PKCE, token exchange, middleware
/tools # registry + tool handlers (CRUD/Search/Job examples)
/domain # business logic services
/db # migrations, RLS policies, queries
/ops # healthz/readyz, logging, error envelopesMinimal tool handler (one file)
# /tools/search.py
@tool("search.index", in_schema=SearchIn, out_schema=SearchOut, stream=True)
async def search_index(q: str, limit: int = 10, ctx: Ctx = Depends()):
yield Progress(message="querying index")
rows = await services.search(q=q, limit=limit, tenant=ctx.jwt.sub)
for r in rows:
yield Partial(r)
return SearchOut(items=rows)Why this exists
Three architectural decisions that remove the friction from building production MCP servers.
Auth that mirrors Claude reality
Full OAuth2 + PKCE with refresh that works for Claude.ai (HTTPS) and Claude Desktop (localhost). This removes 80% of real-world integration pain.
Dual-transport, same semantics
SSE with heartbeats plus an HTTP fallback that emits the same event sequence. Networks can be flaky; behavior shouldn't be.
RLS-first data model
Postgres Row-Level Security is the default, so "act-as-user" is enforced in the database, not by developer willpower.
How it works
Endpoints:
https://your-domain.com/api/v1/mcp/ssehttps://your-domain.com/healthAuth:
OAuth2 (PKCE) → short-lived JWT with auto-refresh → user context arrives in your tool handler
Transports:
SSE with heartbeats for streaming; HTTP fallback for resilient requests
Tools:
Ready-made CRUD + logout; add your own handlers with typed inputs/outputs
Security:
Row-Level Security ensures each user only sees their own rows
First-call trace:
["items.create", "items.list", "logout"]Trusted by developers
Everything you need to build MCP servers
Production-ready components and integrations to get your MCP server running quickly.
FastAPI Backend
Modern Python web framework with automatic API documentation and validation.
Supabase Integration
Real-time database with built-in authentication and row-level security.
OAuth2 PKCE
Secure authentication flow compatible with Claude Desktop and web clients.
Spin up your MCP server today.
Apache-2.0 • Self-hosted • Remove in minutes if it's not a fit.