Supabase MCP Server
Enables adding an end-user MCP endpoint to a Supabase app, leveraging Supabase Auth, Postgres, and Row Level Security for scoped access to data and tools.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Supabase MCP Servershow my recent orders"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Supa MCP
Your Supabase app, now an MCP.
Run one command to add a polished end-user MCP server to an existing Supabase app. It runs as an Edge Function and uses the app's Supabase Auth, Postgres, and Row Level Security instead of introducing another backend.
This package exposes your application's capabilities to its users. It is not the official Supabase management MCP used to administer Supabase projects.
Guided setup
From a repository that already contains supabase/config.toml:
npx supa-mcp setupThe installer requires Node 22+ and the Supabase CLI. Deno is recommended for the generated local type-check and test; when it is unavailable, setup reports those checks as an explicit next action instead of hanging or pretending they ran.
The installer asks who should be able to connect and which URL they should use, previews every file it will write, generates the Edge Function, and runs its local checks when Deno is available. It then gives you an ordered list of the remaining migration, deployment, OAuth, routing, and verification actions.
The three access choices are:
Supabase OAuth — recommended when your app's users will connect their accounts from an MCP client.
Bearer token — useful when your platform already gives clients a Supabase user access token.
Public — anonymous access through the Supabase
anonrole, with a generated Postgres rate limiter.
Setup is resumable without a hidden state file:
npx supa-mcp setup --resume
npx supa-mcp statusBoth commands inspect the generated project and, when a project ref or URL is available, the deployed endpoint. Re-running setup does not overwrite an application-authored capability file.
What gets generated
supabase/functions/mcp/
├── index.ts
├── capabilities.ts
├── deno.json
├── index_test.ts
└── README.mdThe initializer also adds the required function gateway setting without
replacing the rest of supabase/config.toml:
[functions.mcp]
verify_jwt = falseThis does not make an authenticated MCP public. It lets the Edge Function answer an unauthenticated request with the MCP OAuth challenge before the function validates the resulting Supabase access token itself.
Related MCP server: SupaMCPBuilder
Agent and CI setup
Agents should use the non-interactive JSON interface instead of parsing terminal prose.
Inspect the complete plan without writing:
npx supa-mcp setup --auth oauth --plan --jsonApply it and receive structured next actions:
npx supa-mcp setup \
--auth oauth \
--function mcp \
--server-name "My app" \
--yes \
--jsonResume or re-observe after a user completes a dashboard action:
npx supa-mcp setup --resume --function mcp --yes --json
npx supa-mcp status --function mcp --jsonJSON output has a versioned envelope and stable step IDs:
{
"schemaVersion": 1,
"command": "setup",
"status": "needs_user_action",
"functionName": "mcp",
"auth": "oauth",
"steps": [
{ "id": "scaffold", "status": "complete" },
{ "id": "local_checks", "status": "complete" },
{ "id": "deploy", "status": "ready" },
{ "id": "configure_oauth", "status": "needs_user_action" },
{ "id": "verify_remote", "status": "ready" }
],
"nextActions": [
{ "id": "deploy", "status": "ready" },
{ "id": "configure_oauth", "status": "needs_user_action" },
{ "id": "verify_remote", "status": "ready" }
],
"resumeCommand": "npx supa-mcp setup --resume --function mcp --auth oauth --yes --json"
}--json never prompts. Without --yes, a new setup returns
needs_confirmation and makes no changes. Failures return a structured
command_failed error and a non-zero exit code. Tokens are never included in
the setup report or resume command.
Useful automation flags:
--plan: calculate the full setup plan without writing.--yes: accept selected or default choices without prompting.--resume: inspect the existing scaffold and continue idempotently.--skip-checks: leave Deno checks as a reported next action.--project-ref <ref>: make deployment and endpoint discovery explicit.--public-url <url>: make clients see a clean URL such ashttps://yourapp.com/mcpwhile Supabase continues to run the function.--deploy: deploy the generated function after successful local checks.--apply-migrations: runsupabase db push --yesfor public mode.--url <url>: verify an explicit deployed endpoint.
Public deployment deliberately requires both mutation flags because
supabase db push may include other pending application migrations:
npx supa-mcp setup \
--resume \
--auth public \
--apply-migrations \
--deploy \
--yes \
--jsonWrite your MCP capabilities
Edit the generated capabilities.ts. The package uses the official MCP SDK's
registration API, so there is no parallel tool framework to learn.
import {
jsonResult,
type SupabaseMcpContext,
type SupabaseMcpServer,
} from "supa-mcp";
import { z } from "zod";
export function registerCapabilities(
server: SupabaseMcpServer,
ctx: SupabaseMcpContext,
) {
server.registerTool(
"list_projects",
{
description: "List projects visible to the connected user.",
inputSchema: z.object({}),
},
async () => {
const { data, error } = await ctx.supabase
.from("projects")
.select("id, name, status")
.order("name");
if (error) throw error;
return jsonResult({ projects: data });
},
);
}Every request receives a new ctx.supabase client carrying the connected
user's access token. Queries therefore use the same grants and RLS policies as
the rest of the application.
The generated example also demonstrates a resource, a prompt, and an MCP
multi-round-trip confirmation flow. Advanced MCP features remain available
through the underlying official McpServer.
Finish each access mode
OAuth for end users
OAuth is the default and recommended path. The Edge Function:
returns a Bearer challenge pointing to protected-resource metadata;
advertises the project's Supabase Auth OAuth issuer;
validates the Supabase access token;
creates one RLS-scoped client for that request;
exposes the registered MCP capabilities.
Enable Authentication → OAuth Server in the Supabase Dashboard. Configure an application-owned authorization/consent path and enable dynamic client registration when the intended MCP clients need it.
If the app does not yet have a consent UI, generate the small fallback:
npx supa-mcp setup --consent minimalExisting applications should normally integrate Supabase's authorization details, approve, and deny calls into their own signed-in frontend. The fallback is a runnable bridge, not a replacement for the app's eventual UX.
Existing bearer tokens
npx supa-mcp setup --auth bearerBearer mode accepts an existing Supabase user access token without advertising an interactive OAuth flow. RLS behavior is the same as OAuth.
Intentionally public MCP
npx supa-mcp setup --auth publicPublic mode uses the Supabase anonymous client, so only capabilities and rows
available to the anon role can be reached. It generates a private,
Postgres-backed fixed-window limiter with a default of 60 requests per minute
per caller. The endpoint fails closed until that migration is applied.
Deploy and verify
Setup can perform deployment when explicitly requested:
npx supa-mcp setup \
--resume \
--project-ref PROJECT_REF \
--deploy \
--yesOr run the underlying commands yourself:
supabase functions deploy mcp --no-verify-jwt
npx supa-mcp doctor \
--function mcp \
--url https://PROJECT_REF.supabase.co/functions/v1/mcpdoctor detects the generated auth mode. It checks OAuth discovery, bearer
gating, or public tools and rate-limit headers as appropriate. Add
--token "$USER_JWT" to OAuth or bearer mode for an authenticated
tools/list probe. Use doctor --json in automation.
The remote MCP URL is:
https://PROJECT_REF.supabase.co/functions/v1/mcpThat URL works immediately. A product-facing server can instead use a clean URL without moving the Edge Function:
npx supa-mcp setup \
--resume \
--project-ref PROJECT_REF \
--public-url https://yourapp.com/mcp \
--deploy \
--yesSupa MCP sets MCP_PUBLIC_URL so OAuth discovery advertises the clean URL,
while the authorization issuer remains the project's Supabase Auth server.
Your app or edge provider must proxy both /mcp and every path below it to the
Supabase function; the suffix paths serve MCP authorization metadata.
Clean URL on an existing Next.js site
This uses the domain your app already has, so it needs no new DNS record. Add
an external rewrite to next.config.ts:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
async rewrites() {
return [
{
source: "/mcp/:path*",
destination: "https://PROJECT_REF.supabase.co/functions/v1/mcp/:path*",
},
];
},
};
export default nextConfig;Deploy the site, then verify the public route rather than the upstream URL:
npx supa-mcp doctor --url https://yourapp.com/mcpDedicated MCP subdomain
For https://mcp.yourapp.com, the domain's DNS or hosting provider must route
that hostname. A small Cloudflare Worker can forward the complete route tree:
const upstream = "https://PROJECT_REF.supabase.co/functions/v1/mcp";
export default {
async fetch(request: Request) {
const incoming = new URL(request.url);
const suffix = incoming.pathname === "/" ? "" : incoming.pathname;
const target = new URL(`${upstream}${suffix}${incoming.search}`);
const headers = new Headers(request.headers);
headers.delete("host");
return fetch(target, {
method: request.method,
headers,
body: ["GET", "HEAD"].includes(request.method) ? undefined : request.body,
redirect: "manual",
});
},
};Supa MCP cannot create a DNS record without access to that provider, but setup reports the exact remaining route and verifies it once it exists.
Optional capability scopes
The starter does not require scopes. Add them only when one MCP connection should expose fewer capabilities than another:
server
.withScopes(["projects:read"])
.registerTool("list_projects", { inputSchema: z.object({}) }, async () =>
jsonResult({ projects: [] }),
);Scoped tools, resources, prompts, and resource templates are omitted from
discovery unless the request has every required scope. ctx.hasScope() and
ctx.hasScopes() support finer application decisions.
Applications that store grants in their own tables can resolve scopes through the existing request-scoped client:
createSupabaseMcp({
// server, resourceUrl, auth, and register options
access: {
async resolveScopes(ctx) {
const { data, error } = await ctx.supabase.rpc("my_mcp_scopes");
if (error) throw error;
return data;
},
},
});Scope names and storage remain application-owned. The package does not add an organization, membership, role, or entitlement model. RLS remains the row-level authority.
RLS and multi-tenancy
Edge compute is shared; authorization state is not. The runtime creates a new MCP server, context, and Supabase client for every request. It stores no current user, organization, token, or tenant result in mutable module state.
RLS must still express the application's real ownership model. A simple user-owned table might use:
create policy "Users read their own items"
on public.items
for select
to authenticated
using ((select auth.uid()) = user_id);That is only an example. Do not add a service-role client to end-user handlers. The multi-tenant example includes explicit grants, RLS policies, and a two-user negative isolation test.
Command reference
Command | Purpose |
| Guide or automate the complete installation ladder |
| Inspect local setup and optionally probe the remote endpoint |
| Generate files only; useful as a low-level primitive |
| Diagnose generated files, gateway config, auth, and MCP discovery |
| Delegate to |
Use npx supa-mcp --help for all flags.
Troubleshooting
Setup is waiting for approval in automation. Add --yes --json. JSON mode
never opens an interactive prompt; without --yes, it returns a plan with
needs_confirmation.
The endpoint says Missing authorization header without MCP metadata. The
Supabase gateway is intercepting the request. Ensure the function has
verify_jwt = false and deploy it with --no-verify-jwt.
OAuth discovery returns 502. Enable Supabase OAuth Server and verify the project's authorization-server metadata endpoint is available.
Authentication works but tools return no rows. Inspect table grants and RLS policies. Correct RLS can return an empty result without an authorization error.
Public mode returns rate_limit_unavailable. Apply the generated migration
with supabase db push and confirm the function has its managed Supabase secret
environment.
Setup reports a file conflict. An existing target differs from the
generated template. Merge or move it explicitly. Once a generated scaffold is
recognized, setup --resume leaves application-authored capabilities alone.
Development
Version 0.1.0 pins the runtime dependencies in each generated Deno project. The package test suite covers MCP discovery, scopes, public rate limiting, concurrent request isolation, generated OAuth/public projects, structured CLI output, and real two-user Postgres RLS when integration credentials are available.
pnpm install
pnpm check
pnpm run test:rls
npm pack --dry-runSee SPEC.md for the detailed protocol and architecture contract. Released under the MIT License.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceAn MCP server that connects to Supabase PostgreSQL databases, exposing table schemas as resources and providing tools for data analysis through SQL queries.1MIT
- Alicense-qualityDmaintenanceA runtime-configurable MCP server for Supabase databases that enables dynamic tool creation through JSON configuration. Build custom database operations (select, insert, update, delete) without writing code, with built-in authentication and template support.1111MIT
- Alicense-qualityDmaintenanceMCP server for Supabase, enabling database CRUD, storage management, auth administration, project management, edge functions, and secrets via 31 tools.12MIT
- Alicense-qualityFmaintenanceMCP server for self-hosted Supabase with RLS-aware PostgreSQL and PostgREST layers, enabling safe database introspection, SQL queries, and PostgREST access via natural language.MIT
Related MCP Connectors
MCP server for interacting with the Supabase platform
MCP (Model Context Protocol) server for Appwrite
Self-hosted MCP gateway: turn any API, database or MCP server into AI connectors — no code.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/elsheppo/supa-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server