Authentication

Supabase

Connect Supabase OAuth, sign in from an MCP client, and use ctx.user in tools.

Use this when Supabase Auth is your authorization server. Supabase handles login, consent, client registration, and token issuance. bitmcp verifies access tokens and maps claims to ctx.user.

Enable Supabase OAuth

In the Supabase dashboard:

  1. Open Authentication → Sign In / Providers → OAuth Server
  2. Enable the OAuth 2.1 server
  3. Enable Allow Dynamic OAuth Apps so MCP clients can register
  4. Set the consent URL to a route your app implements (for example http://localhost:3000/auth/consent)
  5. Enable at least one sign-in method

Copy your Project ID (or full project URL for local/self-hosted Supabase).

Set environment variables

SUPABASE_PROJECT_ID=your-project-id

Shared production vars (MCP_URL, BITMCP_STATE_KEY): see Installation → Environment variables.

Configure bitmcp

bitmcp.config.ts
import { defineConfig } from "bitmcp";
import { supabase } from "bitmcp/oauth/supabase";

export default defineConfig({
  name: "notes",
  http: {
    path: "/mcp",
    allowedHosts: ["mcp.example.com"],
  },
  auth: supabase(),
});

Or pass options explicitly:

bitmcp.config.ts
auth: supabase({
  projectId: process.env.SUPABASE_PROJECT_ID!,
  supabaseUrl: "http://127.0.0.1:54321",
}),

Use ctx.user in tools

list-notes/tool.ts
export default defineTool({
  description: "List notes for the signed-in user",
  async execute(_input, ctx) {
    const userId = ctx.user!.id;
    return { userId, notes: [] };
  },
});

Verify

  1. Run the server with pnpm dev or pnpm start
  2. Connect from an OAuth-capable MCP client
  3. Complete Supabase login
  4. Call a tool and confirm ctx.user is populated
  5. Call /mcp without a Bearer token and confirm 401

Row Level Security

To query Supabase as the authenticated user, create a Supabase client in your tool using the access token from the MCP session:

list-notes/tool.ts
import { createClient } from "@supabase/supabase-js";

const supabase = createClient(url, anonKey, {
  global: { headers: { Authorization: `Bearer ${accessToken}` } },
});

bitmcp does not put the raw token on ctx.user. Read it from your auth layer or scope queries by ctx.user.id in application code.

For server-owned operations, use the Supabase service role outside the user context.

Options

supabase(options?: {
  projectId?: string;
  supabaseUrl?: URL | string;
  jwtSecret?: string;
  audience?: string;
  resource?: URL | string;
  requiredScopes?: string[];
  scopesSupported?: string[];
  resourceName?: string;
})
VariableWhen
SUPABASE_PROJECT_IDDefault project id
SUPABASE_URLLocal or self-hosted Supabase instead of projectId
SUPABASE_JWT_SECRETLegacy HS256 tokens (32+ bytes)

MCP_URL and BITMCP_STATE_KEY: Installation → Environment variables.

ctx.user fields: id, email, name, fullName, username, avatarUrl, role, aal, amr, sessionId. Other providers expose the same base fields (id, email, name) plus provider-specific claims.

Options passed to the factory override environment variables.