Supabase MCP Server: Complete Guide
The Supabase MCP server lets an AI agent run SQL, design tables, deploy Edge Functions, and read logs against your Supabase project. That power is the whole point — and the whole risk. This guide covers what it does, how to install it, the feature groups, and the prompt-injection problem you must mitigate with read-only mode and project scoping before you point it at anything real.

On this page · 17 sections▾
One-sentence definition
The Supabase MCP server is the official Model Context Protocol (MCP) server — maintained under supabase-community/supabase-mcp — that exposes your Supabase project to an AI agent as a set of tools, so the model can run SQL, manage schema and migrations, deploy Edge Functions, read logs, manage branches, and search the docs. MCP is the JSON-RPC wire format that lets any LLM client talk to any tool server; the Supabase MCP server is the Supabase-shaped implementation of that.
It is the engine behind the “build an app with an AI agent” loop: you describe a feature in Cursor or Claude, and the agent creates the table, writes the migration, and queries the result without you leaving the editor. You can view it in our catalog or read our explainer on what MCP is first if the protocol itself is new to you.
Why it exists
Before MCP, wiring an agent to a database meant hand-writing a tool layer: a function for “run query,” another for “list tables,” a serialization format, an auth story, and a prompt that taught the model how to call all of it. Every team rebuilt that scaffolding, and every rebuild drifted. The agent that worked in Cursor needed porting to work in Claude.
Supabase shipped its official MCP server in April 2025 to collapse that work into one config block. One server, one protocol, every MCP-speaking client — Cursor, Claude, VS Code Copilot, Windsurf, Claude Code. The agent gets a stable, documented tool surface over a Supabase project, and Supabase controls what that surface exposes. The launch post describes over 20 tools across schema, data, config, logs, and functions.
Takeaway: it exists to make “agent + Postgres” a config line instead of a project. That convenience is exactly why the security section later matters so much.
Mental model: the named pieces
Five pieces, and once you can name them the config stops looking like magic.
Personal access token
Your Supabase identity, passed as SUPABASE_ACCESS_TOKEN (stdio) or a Bearer header (remote). It scopes what the server can reach to what your account can reach.
Project ref
The single-project scope. With --project-ref set, the server can only touch that one project and account-level tools switch off.
Read-only flag
--read-only runs every query as a read-only Postgres user. No inserts, updates, or deletes reach your data through the agent.
Feature groups
The tools, bundled into toggleable sets via --features — database, docs, debugging, development, functions, branching, storage, account.
The fifth piece is the transport: the long-standing local form runs the server as a subprocess via npx (stdio), while the newer hosted form points your client at the remote endpoint https://mcp.supabase.com/mcp over Streamable HTTP. Same tools, same flags — only the spelling differs (CLI flags for stdio, URL query params for remote).
Install: the smallest working example
Two paths. Pick one. The clickable panel below pulls the exact, current config for every client straight from our catalog, so it stays in sync as Supabase ships changes — tap your client (Cursor, Claude Code, VS Code, Windsurf) and copy.
One-line install · Supabase MCP Server
Open server pageInstall
Path A — local (stdio via npx). The config that most setup guides have shown for the longest. Note the two flags doing the safety work, --read-only and --project-ref:
{
"mcpServers": {
"supabase": {
"command": "npx",
"args": [
"-y",
"@supabase/mcp-server-supabase@latest",
"--read-only",
"--project-ref=<your-project-ref>"
],
"env": {
"SUPABASE_ACCESS_TOKEN": "<your-personal-access-token>"
}
}
}
}Create the token under Account → Access Tokens in the Supabase dashboard, and keep it in the env block (not the args) so it stays out of version control if you commit the config. Restart your MCP client after setting it.
Path B — remote (Streamable HTTP). Supabase’s hosted endpoint. The same two safety controls move into URL query params (read_only=true, project_ref) and the token rides in an Authorization header:
{
"mcpServers": {
"supabase": {
"type": "http",
"url": "https://mcp.supabase.com/mcp?project_ref=<ref>&read_only=true",
"headers": {
"Authorization": "Bearer <your-personal-access-token>"
}
}
}
}Whichever path you take, the install is not finished until both read_only and the project scope are set. We treat a config without them as unfinished, for reasons the security section makes concrete.
Feature groups: turn off what you don’t need
The tools are bundled into feature groups. You enable a subset with --features (stdio) or features (remote URL). Fewer groups means a smaller tool surface, a smaller prompt, and a smaller blast radius.
| Group | Does | Default |
|---|---|---|
database | Run SQL, manage tables, apply migrations | On |
docs | Search the Supabase documentation | On |
debugging | Read service logs and advisories | On |
development | API URLs/keys, generate TypeScript types | On |
functions | List, fetch, deploy Edge Functions | On |
account | Manage projects/orgs (off when project-scoped) | On* |
branching | Create/merge dev branches (paid plans) | Off |
storage | Manage storage buckets and config | Off |
*account tools disable themselves once you set a project ref — scoping and account-level control are mutually exclusive by design. Takeaway: if your agent only needs to write app code against a schema, run --features=database,docs and nothing else.
The security problem you can’t skip
The honest core of this post
An agent with broad database access plus untrusted row content plus a way to write data back is a documented data-exfiltration path. It is not theoretical — it was demonstrated against this exact server.
In mid-2025, the security firm General Analysis published a disclosure (it reached the top of Hacker News, 800-plus points) showing a clean attack. A developer used an IDE agent to read recent support tickets through the Supabase MCP server. One ticket’s body was not a real complaint — it was a set of instructions written for the model. The agent, running with service_role credentials that bypass row-level security, followed those instructions: it queried a sensitive tokens table and wrote the result back into the ticket thread, where the attacker could read it.
That is prompt injection: the LLM cannot tell data apart from instructions. As General Analysis put it, models “process all text the same way; whether it is data/context or user instructions.” The database row was data to you and a command to the model.
Simon Willison framed the same incident as his “lethal trifecta”: the attack needs three things together — access to private data, exposure to untrusted instructions, and a way to exfiltrate. Remove any one leg and the attack collapses. That is the entire strategy for hardening this server.
How to harden it (the three legs)
Supabase’s own guidance maps almost one-to-one onto the trifecta. Apply all of it; none of it is optional on real data.
- Don’t connect to production. Point the server at a development project, not your live one. Supabase states this plainly: the MCP server is designed for development and testing. This removes the “private data” leg by making the data non-sensitive.
- Run read-only. The
--read-onlyflag executes queries as a read-only Postgres user, removing the “exfiltrate by writing back” leg. In the General Analysis attack, the write-back into the ticket was how the attacker actually saw the data. - Scope to one project.
--project-refbounds the blast radius to a single project and disables account-level tools. - Keep manual tool approval on. Most clients (Cursor, Claude) ask you to approve each tool call. Supabase recommends never disabling that. It is your last human checkpoint before a query runs.
The contrarian nuance worth internalizing
Willison’s sharpest point: read-only is necessary but not sufficient. It removes the write-back exfiltration path, but a model that can read private data and is exposed to injection can still leak it through its own response text. “Read-only access to your database, combined with the ability to read untrusted content, still leaves you open to data leaks.” The durable fix is not trusting the data — keep production out of reach.
What we got wrong
Three assumptions that cost us, so you can skip them.
We thought read-only made it “safe.” It does not. It closes one leg of the trifecta. We ran a read-only, production-scoped server early on and felt covered — until the Willison piece made it obvious that a read-only agent reading a poisoned row can still surface secrets in its own output. Read-only is the floor, not the ceiling.
We left every feature group on. The defaults enable database, functions, development, debugging, docs, and account. We only needed database and docs for the task. Every extra group is more tools in the prompt and more capability an injected instruction can reach. Trim to what the job needs.
We pasted the token into args. Then committed the config. The token belongs in the env block (or a secret manager), never in a command line that lands in git history. Rotate it if you have ever done this.
Wrong vs right patterns
❌ Wrong
# production ref, full write access, all features
npx -y @supabase/mcp-server-supabase@latest \
--project-ref=<PROD_REF>Live data, write-capable, every tool on. One poisoned row in any table the agent reads is an exfiltration path.
✅ Right
# dev ref, read-only, minimal features
npx -y @supabase/mcp-server-supabase@latest \
--read-only \
--project-ref=<DEV_REF> \
--features=database,docsDevelopment project, read-only, two feature groups, manual approval left on in the client. Three legs of the trifecta addressed.
Common mistakes
- Omitting
--read-onlyon real data. Root cause: the flag is opt-in, not default. If you forget it, the agent can write — and write-back is the exfiltration step in the documented attack. - Pointing it at production. Root cause: it works, and it is tempting. Supabase explicitly advises against it. Use a dev project or a branch.
- Disabling manual tool approval. Root cause: approving every call is friction, so people auto-accept. That deletes the last human in the loop.
- Token in version control. Root cause: putting it in
argsinstead ofenv. Anyone with repo read access then has your Supabase access token. - Client doesn’t speak Streamable HTTP. Root cause: an older client build. Symptom is empty tool lists or connection errors on the remote endpoint. Fall back to the local
npxstdio config.
Who it is for (and who it isn’t)
Use it if: you build on Supabase and want an agent that designs schema, writes migrations, and queries data from inside Cursor, Claude, or VS Code; you work primarily against development projects or branches; you are comfortable setting two flags before you trust it.
Skip it (or lock it down hard) if: your only Supabase project holds production user data with no dev mirror; you cannot enforce read-only and project scoping; you plan to expose the agent to content submitted by untrusted users (tickets, comments, form input) while it can also read private tables. That combination is the lethal trifecta by construction.
Community signal
The loudest community moment for this server was not a launch tweet — it was the security disclosure. The General Analysis write-up, “Supabase MCP can leak your entire SQL database,” drew 800-plus points and several hundred comments on Hacker News. The thread is the best primary read on how practitioners reacted: a mix of “this is inherent to giving an LLM database access” and “the defaults should be safer.”
The contrarian-but-fair voice is Simon Willison’s. He does not say “don’t use it” — he says the docs should be far more explicit about the trifecta, and that read-only alone gives a false sense of safety. That criticism landed: Supabase’s guidance now leads with read-only, project scoping, and a clear “don’t connect to production” warning. The honest summary is that the ecosystem argued its way to safer defaults in public.
(We looked for a verifiable first-party launch tweet to embed here. The X oEmbed endpoint is gated and we do not publish tweet IDs we can’t verify, so we cite Supabase’s official launch post instead.)
The Verdict
Our Take
The Supabase MCP server is the best way to put an AI agent on a Supabase project, and you should use it — on a development project, read-only, project-scoped, with manual tool approval on and feature groups trimmed to what the task needs. Use it that way and it is a genuine productivity multiplier. Point it at production with write access and every feature enabled, and you have built the exact configuration that leaked a database on the front page of Hacker News. The tool is good; the defaults demand respect.
The bigger picture
The Supabase incident became a reference case for a general truth about agent tooling: the moment an LLM can read untrusted content and act on a privileged system, prompt injection is a live threat, not an edge case. This is not a Supabase flaw so much as an MCP-era reality — the same shape recurs with any database, email, or filesystem MCP server.
The durable answers are converging: least-privilege scopes, read-only by default, human-in-the-loop approval, and keeping untrusted data away from privileged agents. Supabase moving its guidance toward read-only and project scoping is part of that industry-wide correction. Browse other database MCP servers or our roundup of the best MCP servers for databases and Supabase — and apply the same trifecta lens to every one.
Frequently asked questions
What is the Supabase MCP server?
It is the official Model Context Protocol server (maintained under supabase-community) that connects an AI agent or IDE to your Supabase project. Through it the agent can run SQL, design tables and migrations, read logs, deploy Edge Functions, manage branches, and search the Supabase docs — over 20 tools in total.
Is the Supabase MCP server safe? What about prompt injection?
It can be made reasonably safe, but it is not safe by default on production data. The well-publicized risk is prompt injection: malicious text inside a database row (a support ticket, a comment) can trick the agent into running unintended queries. Supabase's mitigations are read-only mode, project scoping, manual tool-call approval, and the firm guidance to use a development project — not production.
How do I run the Supabase MCP server in read-only mode?
For the local stdio config, add the `--read-only` flag to the npx args. For the remote endpoint, add `read_only=true` to the URL. Read-only mode executes every query as a read-only Postgres user, so the agent cannot insert, update, or delete. It is the single most important flag to set.
What can the Supabase MCP server do?
Run SQL and manage schema, apply migrations, generate TypeScript types, fetch project config and API keys, read service logs for debugging, deploy and list Edge Functions, create and merge development branches (paid plans), manage storage buckets, and search Supabase documentation. Tools are organized into feature groups you can enable or disable.
Can I use the Supabase MCP server for production?
Supabase explicitly recommends against connecting it to a production project. The official guidance is to point it at a development project, run it read-only and project-scoped, and keep manual tool-call approval on. If you must touch real data, read-only plus scoping reduces — but does not fully remove — the prompt-injection risk.
How does authentication work for the Supabase MCP server?
You authenticate with a Supabase personal access token. The local stdio config reads it from the `SUPABASE_ACCESS_TOKEN` environment variable (or an `--access-token` flag); the remote endpoint sends it as a `Bearer` token in the `Authorization` header, or prompts you to log in during setup. Keep the token out of version control.
What is project scoping in the Supabase MCP server?
Project scoping ties the server to one Supabase project via `--project-ref` (stdio) or `project_ref` (remote URL). A scoped server can only touch that project's resources and the account-management tools are disabled. It is a blast-radius control: if something goes wrong, it goes wrong in exactly one project.
Glossary
- MCP
- Model Context Protocol — the JSON-RPC standard letting any LLM client call any tool server.
- Prompt injection
- Untrusted text that the model reads as instructions instead of as data.
- Lethal trifecta
- Private-data access + untrusted instructions + exfiltration path, all at once.
- Read-only mode
--read-only; runs queries as a read-only Postgres user — no writes.- Project scoping
--project-ref; bounds the server to one project, disabling account tools.service_role- A Supabase key that bypasses row-level security — full table access.
- RLS
- Row-level security; Postgres policies that restrict which rows a role can see.
- Feature group
- A toggleable bundle of tools enabled via
--features. - stdio transport
- Running the server locally as a subprocess via
npx. - Streamable HTTP
- The remote transport for the hosted
mcp.supabase.com/mcpendpoint.
Sources & links
Primary
- Repository: github.com/supabase-community/supabase-mcp
- Official docs: supabase.com/docs/guides/getting-started/mcp and /guides/ai-tools/mcp
- Launch post: supabase.com/blog/mcp-server
Community & security
- General Analysis disclosure: generalanalysis.com/blog/supabase-mcp-blog
- Hacker News thread (800+ points): news.ycombinator.com/item?id=44502318
- Simon Willison, “Supabase MCP’s lethal trifecta”: simonwillison.net
Internal
Databases
Best MCP Servers for Database & Supabase
ReadProtocol
What is the Model Context Protocol?
ReadBrowse
All database MCP servers
ReadFound an issue?
If a flag, feature group, or security default has changed since we wrote this, email [email protected] or read more on our about page. We keep these guides current.