The Goal

By the end of this blueprint, you and every member of your team will share a snippet library that Claude can read and write to. Anyone with Claude Code can point it at your server URL, sign in once with Supabase Auth, and from then on:

"Save this prompt as 'incident postmortem template' and put it in our team workspace."

"Pull up our eval-rubric snippet."

"What snippets has the team saved about RAG retrieval?"

…will all just work — across machines, across teammates, with proper auth and per-workspace visibility.

What Makes This Different From the Other MCP Blueprint

The existing Build Your Own MCP Server blueprint runs your server locally over STDIO with no auth. This one is the production cousin:

AspectLocal MCP blueprintThis blueprint
TransportSTDIO (subprocess)Streamable HTTP (remote)
AuthNone — local trustFull OAuth 2.1 (Supabase)
StorageSQLite on diskPostgres + Supabase Auth
AudienceSingle userA whole team
DeploymentNone — Claude launches itSupabase Edge Functions
MCP clientsClaude Code on your machineClaude Code / Desktop on any machine

If you've done the local one, this is the natural next step. If you haven't, you'll be fine — we re-explain the relevant MCP concepts as we go.

Want the same library with a tenth of the setup? If your team is small and trusting and you don't need per-user isolation, the Build a Team-Token MCP Server blueprint ships the same snippet library guarded by a single shared token — no OAuth, no consent page, live in ~15 minutes. This blueprint is the production version with real per-user identity; that one is the fast path. Pick by whether you need private snippets and per-person revocation.

Why "Snippets" and Not Real Claude Code Skills

A Claude Code skill is a directory with a SKILL file plus optional supporting files, loaded out of ~/.claude/skills/. Powerful, but the format is opinionated and pulls supporting files from disk — awkward to model as a database row.

We're storing free-form prompt snippets: a title, a body of markdown, and tags. They're easier to author, search, and version. If you want to load them as actual Claude Code skills later, the body is markdown — a thin sync script can write each snippet to its own SKILL in ~/.claude/skills/. We'll cover this in the final step.

The Stack

ChoiceWhy
Supabase Edge Functions (Deno)First-class OAuth 2.1 server, RLS-native Postgres, single supabase functions deploy command, free tier covers small teams.
TypeScript + HonoHono runs on Deno + Node + Bun, has clean middleware, and the MCP SDK ships TypeScript types.
Official MCP SDK@modelcontextprotocol/sdk (pinned at 1.29.0) — Anthropic's reference, handles the JSON-RPC plumbing, supports Streamable HTTP out of the box.
Supabase OAuth 2.1 ServerIn beta as of mid-2026 (free on all plans during the beta). Implements RFC 8414 (metadata), RFC 7591 (dynamic client registration), RFC 9728 (protected resource metadata) — exactly what the MCP spec requires. You supply one small piece yourself: a consent page, which we build in step 4.
Postgres with RLSMulti-tenancy enforced in the database, not in app code. Bugs in tool implementations can't leak data across workspaces.

How the Pieces Fit Together

Five things happen the first time Claude calls the server, in order:

  1. Claude makes an unauthenticated MCP request.
  2. The server responds 401 with a WWW-Authenticate header pointing at its Protected Resource Metadata document. Claude reads that doc, which names Supabase as the authorization server, and discovers Supabase's well-known OAuth endpoints.
  3. Claude (acting as an OAuth 2.1 client with PKCE) opens the user's browser at Supabase's authorization endpoint. Supabase hands off to your consent page — a small static page you'll build in step 4 — where the user signs in and clicks Approve.
  4. Supabase redirects back with an authorization code, Claude exchanges it for an access token, and stores the refresh token.
  5. From now on, every MCP request includes Authorization: Bearer <jwt>. The Edge Function validates the JWT, forwards it into a per-request Supabase client, and Postgres RLS does the rest.

Every later request from any teammate's Claude follows the same flow.

The MCP Surface We'll Expose

Once auth is wired, the actual snippet API stays compact:

Tools (actions Claude can take):

  • list_snippets({ workspace_id?, tag?, search?, limit? }) — list snippets the calling user can see.
  • get_snippet({ id }) — fetch one snippet's full body.
  • save_snippet({ id?, workspace_id, title, body, tags?, visibility? }) — create, or update when id is given.
  • share_snippet({ id, visibility }) — change privateworkspacepublic.
  • list_workspaces() — workspaces this user is a member of.
  • create_workspace({ name }) — spin up a new team workspace.
  • invite_to_workspace({ workspace_id, email, role? }) — owners only.

Resources (data Claude can browse):

  • workspace://<id> — a workspace's metadata.
  • workspace://<id>/snippets — a workspace's snippet collection.
  • snippet://<id> — one snippet's full body.

Eleven steps, end-to-end deployed in production.

What You'll Need Before Step 2

  • A Supabase account (supabase.com — free tier is fine).
  • The Supabase CLI: brew install supabase/tap/supabase (or other install methods).
  • Docker Desktop, running — supabase functions serve executes your function in a local container, so local testing needs it.
  • Node.js 18+ (for the build steps; Deno comes bundled with the Supabase CLI for the runtime).
  • Claude Code or Claude Desktop installed.
  • A code editor with TypeScript support.

Step 2 sets up the Supabase project and scaffolds the repo.