Skip to content

Auth & security

Every tool call authenticates and acts as the calling user’s own Supabase JWT — never a service-role key. This is a hard architectural rule shared across every MCP server DevFellowship runs (see the DFL MCP fleet docs), not something specific to this server.

  1. Extract the bearer token from Authorization: Bearer <jwt>.
  2. Verify it against the Supabase project’s public JWKS endpoint (SUPABASE_URL/auth/v1/.well-known/jwks.json) — this project signs tokens with ES256 (asymmetric keys), not the older HS256 shared-secret scheme. Verification happens locally against the cached public key; no per-call round trip to Supabase Auth.
  3. Resolve the caller’s org. The server looks up the caller’s own public.users row (org_id, role, active) — the same lookup the staff UI’s useCurrentStaffUser hook makes. No row means “not a registered staff user,” and every tool call is refused.
  4. Build a per-request Supabase client from the project’s publishable (anon) key plus the caller’s raw JWT as the Authorization header. This is the client every tool uses. PostgREST enforces the same org_isolation RLS policy that gates the staff UI’s own reads and writes — a tool cannot return or modify a row outside the caller’s organization, because Postgres itself refuses to show it the row.
  5. Role checks beyond RLS. A few actions have a role gate the schema itself doesn’t express (e.g. only an owner may invite or update staff) — these mirror the same checks the staff UI’s own React components make, reproduced server-side, plus (for invite_staff) re-checked again inside the Edge Function itself as the real enforcement point.

One MCP session (one mcp-session-id) is bound to the JWT presented on its initialize call. A session ID is only honored for the identity that opened it — if it appears from a different (even validly authenticated) caller, the server treats the request as if no session ID was given at all, forcing a fresh handshake.

There’s no separate credential to request. Any real Marques Boxing staff login (the same one used for the web app) mints a usable token via Supabase Auth’s normal password grant — see Getting started.