Is Supabase MCP safe? A 10-point setup checklist, and what read-only mode doesn't stop

Safe enough for development, if you set it up that way: one project, read-only, few tools, a person approving each call, and no secrets the session can reach.

Supabase MCP is safe enough for development if you set it up for that: scope it to one non-production project, turn on read-only mode, enable only the tool groups you need, keep a person approving each call, and keep secrets out of the database the session can read. Supabase’s own docs say prompt injection is the main risk and that its mitigations aren’t foolproof.1

None of those settings is on by default except the tool groups, and the most important control, what the database role can read, isn’t an MCP setting at all. This post is the setup we’d use, with a local reproduction of the one point most people get wrong. For what the July 2025 demonstration actually showed, read the Supabase MCP leak, from the primary sources.

The short answer

  • Development project or branch: yes, with the settings below.
  • Production: only when the task needs production data, and then scoped, read-only and with few tool groups, as Supabase’s docs advise.1
  • For your customers or end users: no. Supabase’s docs say not to give the server to them.1
Every MCP tool call goes through your rules first. Here a delete that doesn’t say which rows is stopped before it reaches the database. These are the rules deedglass init starts with; the call is made up.

The checklist

# Check Why
1 The server URL carries project_ref=<your dev project>. Without it the session can reach every project you can, plus account tools.1
2 The URL carries read_only=true. Queries run as a read-only Postgres user.1
3 The URL carries features= with only the groups you use. Every group except Storage is on by default.1
4 The project is a development project or a branch. Branches start without the main project’s data by default.5
5 No table the session can read holds secrets or tokens. Read-only still reads.4
6 Nothing connects with service_role or postgres. service_role bypasses row-level security; postgres has admin privileges.3
7 Manual approval stays on in your client; no “always allow”. Supabase recommends it and warns against “Always Approve”.2
8 You read the SQL before approving, not just the tool name. Ad-hoc SQL goes through one tool, execute_sql, so its name says little.1
9 The session that reads customer text can’t write where outsiders read. That write was the exit in the demo.4
10 Unattended routines use read-only, project-scoped tools only, and stop instead of writing. Supabase’s advice for runs nobody watches.1

Is Supabase MCP read-only by default?

No. The hosted server lives at https://mcp.supabase.com/mcp, and you narrow it with URL query parameters: project_ref scopes it to one project and turns off account tools, read_only=true runs every query as a read-only Postgres user, and features enables only the tool groups you name.1 The groups on by default are Database, Debugging, Development, Edge Functions, Account management and Docs; Storage is off.1

Sign-in is a browser OAuth flow by default; a personal access token is for CI, where a browser isn’t available.1 Supabase’s docs note that the server runs with your developer permissions, which is why the scope parameters matter.1

Scope it to one project and a few tools

A client config with every narrowing parameter set looks like this (the shape most MCP clients use; the project ref is a placeholder):

Code Data in JSON, the format software uses to pass records and settings.

{
  "mcpServers": {
    "supabase": {
      "type": "http",
      "url": "https://mcp.supabase.com/mcp?project_ref=abcdefghijklmnop&read_only=true&features=database,docs"
    }
  }
}

database,docs is enough to inspect tables and run queries. Add development or debugging when you need them, not by default. Fewer groups means fewer tools the model can pick, which is how Supabase frames them: a smaller attack surface.1

Some actions ask you to confirm through the client before they run: cost confirmation for creating a project or a branch, and destructive SQL confirmation for execute_sql and apply_migration outside read-only mode.1 Supabase calls these a guardrail, and each one can be skipped with a skip_elicitations parameter.1 Don’t skip them on a project with data you care about.

What read-only stops, and what it doesn’t

Read-only mode stops writes. It doesn’t stop reads, and in the July 2025 demonstration the read was the secret. General Analysis says so directly: read-only access still permits reads the database role can perform.4

You can see the difference in five minutes on any local Postgres. We rebuilt the demo’s three tables with dummy data on PostgreSQL 17.11 and ran the assistant’s two queries three ways. First, as the table owner inside a read-only transaction, the way a read-only session works:

Code What the screen or file shows, copied as is.

begin read only;
select provider, refresh_token from integration_tokens;
 provider | refresh_token
----------+---------------
 crm      | dummy-rt-0001
 mail     | dummy-rt-0002
(2 rows)

insert into support_messages (ticket_id, sender, body)
  select 7, 'agent', string_agg(refresh_token, ', ') from integration_tokens;
ERROR:  cannot execute INSERT in a read-only transaction

Second, as a role granted SELECT on every table, a stand-in for a broad read-only user: the same two rows came back, and the insert failed with permission denied for table support_messages. Third, as a role granted SELECT on support_tickets and support_messages only:

Code What the screen or file shows, copied as is.

select subject, status from support_tickets where status = 'open';
     subject      | status
------------------+--------
 Billing question | open
(1 row)

select provider, refresh_token from integration_tokens;
ERROR:  permission denied for table integration_tokens

Read-only closed the exit in both broad cases. Only the narrow role kept the tokens unread. One more detail from Postgres’s side: a read-only session setting such as default_transaction_read_only is only a default for new transactions, and the session can change it.6 A read-only role can’t grant itself more. Supabase’s docs describe read-only mode as a read-only Postgres user, which is the stronger of the two.1

So the real control is upstream of MCP: what the credential can read. Keep tokens, keys and anything the support flow doesn’t need out of the database the session reaches, or behind grants it doesn’t hold. Our Postgres access guide has the tested SQL for a role, column grants and row-level security.

Use a branch or a dev project, not production

Supabase built MCP to help developers prototype and test, and its blog says it works best against development, staging or branched databases, or anonymised data.2 A branch starts without the main project’s data or storage by default, and merging it runs a deployment that applies its pending migrations.5 That’s the setup you want: the assistant writes migrations against an empty copy, and changes reach production through your normal review.

The current docs are a little more permissive than the blog: connect to a production project only when the task requires production evidence, and then scope it, make it read-only and restrict the tool groups.1 Treat that as the exception, with a person in the loop for the whole session.

Keep approval on, and read the query

Supabase’s recommendations include keeping manual approval on in your MCP client and being wary of “Always Approve”.2 The catch is fatigue: after the twentieth harmless list_tables, people click through. Two habits help:

  • Approve queries, not tools. Ad-hoc SQL goes through execute_sql, so the tool name tells you little.1 Read the SQL. SELECT * FROM integration_tokens in a session about a support ticket is the whole attack in one line.
  • Approve destinations. When the next call is a write, ask where the data lands and who can read it.

Split the trifecta

Simon Willison’s lethal trifecta is private data, untrusted content and the ability to externally communicate in one agent.7 A Supabase session that reads customer-written rows (tickets, comments, profile fields) has untrusted content by design. Supabase wraps SQL results with instructions telling the model not to follow commands inside the data, and says plainly that this isn’t foolproof.1 So take one leg away:

  • A session that reads customer text gets no write tools and no tables with secrets.
  • A session that writes migrations doesn’t read customer rows.
  • Neither runs with service_role. Supabase’s docs describe it as the role the API uses to bypass Row Level Security.3

The general version, for every MCP server, is in our MCP security checklist.

Try it

If your agent connects to Supabase Postgres directly rather than through Supabase’s server, npx -y deedglass connect runs read-only checks on a read-only session and prints a plan before anything changes; with --apply it creates least-privilege roles and enforces a starter policy.8 The Supabase guide has the steps. To grade the setup you have today, run npx deedglass scan (what the grade means); the playground shows a database doing more than one statement said, in a browser tab.

Questions people ask

Can I use Supabase MCP in production?

Supabase’s docs say to connect to a production project only when the task requires production evidence, and then to scope the server to that project, enable read-only mode and restrict the feature groups.1 For day-to-day work, use a branch or a development project.

Does read-only mode stop prompt injection?

No. It stops writes, so an injected instruction can’t change data or write it somewhere an attacker reads. It doesn’t stop the model from reading what the role can read and showing it to you. Supabase says prompt injection remains the top concern even in read-only mode.2

Should I use the service_role key with an AI agent?

No. Supabase’s docs describe service_role as the role the API uses to bypass Row Level Security.3 Give the agent a role with grants for the tables its job needs.

Is Supabase MCP safe to give to my customers?

No. Supabase’s docs say not to give it to your customers or end users.1

Written with AI assistance and checked against our claims register.

The takeaway

Supabase MCP is safe enough for development when scoped: one project, read-only, few tools, a person approving calls and no secrets in reach.

Read nextThe Supabase MCP "leak": what the July 2025 demonstration showed, and what changed after Try it: install in 7 s

Related on this site

More posts

Sources

  1. 1Supabase docs: Model context protocol (MCP) · supabase.com · checked 25 October 2026
  2. 2Supabase blog: Defense in Depth for MCP Servers (16 September 2025) · supabase.com · checked 25 October 2026
  3. 3Supabase docs: Postgres roles · supabase.com · checked 25 October 2026
  4. 4General Analysis: Supabase MCP Security: How Prompt Injection Leaked Private Tables · generalanalysis.com · checked 25 October 2026
  5. 5Supabase docs: Branching · supabase.com · checked 13 October 2026
  6. 6PostgreSQL docs: Client connection defaults · postgresql.org · checked 13 October 2026
  7. 7Simon Willison: The lethal trifecta for AI agents · simonwillison.net · checked 14 October 2026
  8. 8Deedglass docs: Deedglass with Supabase Postgres · docs.deedglass.com · checked 25 October 2026

Published 25 October 2026, sources last checked 25 October 2026. If something here is out of date, write to hello@deedglass.com.

Try it on your own setup

npx deedglass scan

Grades only your own setup. Nothing is uploaded.

Pricing