TL;DR:
Connecting AI agents to your Supabase database via MCP lets you run natural language queries directly against your tables without exposing raw credentials to the LLM.
Setting up the native Supabase MCP server locally takes minutes using
npx, but running it securely in production requires strict Row-Level Security (RLS) policies and schema mapping to prevent destructive SQL actions.To avoid managing expired database tokens and broken connection states yourself, Composio's managed MCP gateway handles authentication, security governance, and tool routing automatically, with 100,000 free tool calls per month and no credit card required.
Exposing your production database to an AI agent without guardrails is like leaving your car running with the keys in the ignition. A single misconfigured permission and an agent connecting with the service role key can run DROP TABLE on your entire schema. RLS policies won't stop it, because DROP TABLE is a DDL command governed by role privileges, not row-level access rules. This guide walks through how to set up the Supabase MCP server correctly, configure strict Row-Level Security policies, and offload the operational burden to a managed integration layer when self-hosting becomes a maintenance problem.
How to connect Supabase API tool with your agent
Install Composio
Copy:
npm install @composio/openaiInstall the Composio SDK
Initialize Composio and create tool router session
Copy:
import OpenAI from 'openai';
import { Composio } from '@composio/core';
import { OpenAIResponsesProvider } from '@composio/openai';
const composio = new Composio({
provider: new OpenAIResponsesProvider(),
});
const openai = new OpenAI({});
const session = await composio.create('your-user-id');Import and initialize Composio client, then create a Tool Router session
Execute Supabase tools via tool router with your agent
Copy
const tools = session.tools;
const response = await openai.responses.create({
model: 'gpt-4.1',
tools: tools,
input: [{
role: 'user',
content: 'List all third-party auth integrations for my Supabase project'
}],
});
const result = await composio.provider.handleToolCalls(
'your-user-id',
response.output
);
console.log(result);Get tools from Tool Router session and execute Supabase actions with your Agent
Running natural language database queries
With the server running, you can query your database in plain language.
Testing read access to your tables
Ask your agent: "List the top 5 users by signup date." The MCP server translates this into:
SELECT id, email, created_at
FROM users
ORDER BY created_at DESC
LIMIT 5;The response comes back as structured JSON with field names the agent can reason over directly. This is the core advantage of MCP: the agent works with clean, typed data rather than a wall of raw connection output.
Refining data with joins
The agent handles relational queries across multiple tables. "Show me the last 3 orders for each of the top 5 users" produces a query joining your users and orders tables automatically, provided the foreign key relationship is declared in your schema. The MCP resources specification explains how the server surfaces schema metadata to the agent so it can construct these joins without guessing at column names.
Setting safe permissions for MCP
Giving an agent unrestricted write access to your production database is not a configuration choice you can walk back after the fact. Read-only access is the correct default. If your workflow requires writes, scope them to specific tables and specific operations using a dedicated database role rather than the service role key.
Why Composio handles this differently: Managing database credentials manually turns you into the OAuth janitor, but auth is only the entry point. Composio is action infrastructure: once a user authenticates through a Connect Link URL, credentials persist for all future sessions and the agent gains access to 50,000 agent-ready tools across 300M+ tool calls processed monthly on the platform. That means your agent isn't just reading from Supabase: it can write to HubSpot, send a Slack message, create a GitHub issue, and close the loop, all through one governed path to act, with no conditional logic in your agent code and no token refresh race conditions to debug.
Core concepts of the Supabase MCP integration
The Supabase MCP server acts as a translation layer between your AI agent and your database. Your agent sends natural language requests, the MCP server converts them into structured SQL queries, and your database returns results the agent can reason over.
Think of it this way: the agent is the brain making decisions, the MCP server is the secure communication bridge, and your Supabase database is the storage layer that neither the agent nor the LLM touches directly. Credentials stay server-side. The LLM receives only tool descriptions and calls them through the protocol, which is what makes MCP a safer pattern than giving an agent raw database credentials.
How MCP enables secure database access
The MCP specification builds on the JSON-RPC 2.0 message format. An MCP server operates as a lightweight process that exposes specialized capabilities through standardized protocol primitives: tools, resources, and prompts. When your agent asks "show me the five most recent orders," the MCP server intercepts that intent, builds a parameterized SQL query, executes it against Supabase, and returns structured JSON back to the agent. The key security property here: separation of concerns. Your connection string and service role key stay on the server, never reaching the LLM.
Practical AI database workflows
Real-world use cases where this pattern delivers clear time savings include:
Automated reporting: An agent queries your
analyticstable each morning, formats the results, and drafts a Slack summary without manual intervention.Lead enrichment: An agent cross-references new signups against your
contactstable and populates missing fields from a connected enrichment tool.Customer support lookups: An agent queries order history in real time during a support conversation without exposing the full database to the support interface.
Choosing a transport method
Table 1: Transport method decision matrix
Transport method | Best for | Setup complexity | Security profile |
|---|---|---|---|
stdio | Local dev, single-user desktop agents | Low | No auth layer, one client per process |
Streamable HTTP | Production, multi-user, cloud-hosted | Varies by deployment | Supports auth headers, multi-client |
The operational case is clear: stdio has near-zero network overhead but limits you to one client per process with no auth layer. For production, HTTP Streamable is the right choice. Composio's managed MCP gateway runs over HTTP with auth headers and multi-client support, with no server process to run or maintain on your end.
Verifying schema and foreign key mappings
Before you run complex queries in production, verify that your schema is correctly accessible to the agent. The Composio Supabase toolkit documentation covers the schema introspection capabilities available through the managed integration.
The MCP server exposes your database structure to the agent through structured tool primitives, so the agent knows which tables exist and which columns they contain before it writes a single query. You can ask your agent directly: "What tables do you have access to?" and it will return a list based on what the server has exposed. If a table does not appear in that list, confirm the database role you are using has SELECT privileges on that table.
Explicit foreign key declarations in your schema are critical for preventing agent errors during complex joins. When the agent sees that orders.user_id references users.id, it constructs correct join conditions without guessing. Without that declaration, your agent may infer a relationship from column naming conventions and produce queries that silently return incorrect data.
Restrict agent data access using RLS
RLS works by attaching policies to tables. Each policy defines which rows a given role or user can read, insert, update, or delete. Without a policy in place, Supabase returns zero rows to any query against a table with RLS enabled - the safe default.
RLS governs row-level access for SELECT, INSERT, UPDATE, and DELETE operations only. It has no effect on DDL commands such as DROP TABLE or ALTER TABLE. To prevent an agent from executing schema-destructive commands, restrict the connecting role's privileges directly: never grant DROP, ALTER, or TRUNCATE to any role used for agent connections, and connect as a purpose-built restricted role rather than a superuser or table owner.
Securing AI queries with RLS
Enable RLS on every table you expose through the MCP server:
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
ALTER TABLE users ENABLE ROW LEVEL SECURITY;Supabase enables RLS by default on tables you create through the Dashboard, as documented in the RLS best practices. Tables created directly via SQL do not inherit this default, so enable it explicitly.
Setting up RLS policies
For an AI agent that should only read a user's own profile data, the policy looks like this:
CREATE POLICY "Agent can view own profile"
ON profiles
FOR SELECT
USING (auth.uid() = user_id);For a read-only agent role that should see all orders but never modify them:
-- Create a restricted agent role
CREATE ROLE agent_readonly;
GRANT SELECT ON orders TO agent_readonly;
-- Create the RLS policy for that role
CREATE POLICY "Agent read only access"
ON orders
FOR SELECT
TO agent_readonly
USING (true);How to audit agent access permissions
After writing your policies, test them by switching to the restricted role in your SQL editor:
SET ROLE agent_readonly;
SELECT * FROM orders; -- Should return rows
DELETE FROM orders WHERE id = 1; -- Should fail with permission denied
RESET ROLE;If the DELETE succeeds, your policy has a gap. The USING clause governs reads and deletes. The WITH CHECK clause governs inserts and updates. An UPDATE operation needs both.
Configure read-write permissions and PII masking
Read-only vs. write permissions
Read-only access is safe by default and should be your starting point for any new agent integration. Grant write access only after you have tested the specific write operations the agent will perform, confirmed the RLS policies covering those tables are correct, and enabled audit logging so you can review what the agent did. Rotate service role keys at least quarterly, or immediately if exposure is suspected.
Control agent access by table
Restrict the MCP server's visibility to a specific schema or a whitelisted set of tables rather than exposing your entire database. In PostgreSQL, set the search path for a role to limit which schema the agent can query:
ALTER ROLE agent_readonly SET search_path TO reporting, public;This means the agent only sees tables in the reporting and public schemas, even if other schemas exist in the same database.
Masking PII in your Supabase MCP
Create database views that mask Personally Identifiable Information before the agent can query it. Instead of exposing the users table directly, expose a view:
CREATE VIEW users_masked AS
SELECT
id,
LEFT(email, 3) || '***@***.com' AS email,
created_at,
subscription_tier
FROM users;
GRANT SELECT ON users_masked TO agent_readonly;The agent queries users_masked and never sees raw email addresses. This keeps your workflows functional without compromising data your agent has no business reading.
Audit logs for AI operations
You need to know exactly what your agent did when something goes wrong, and you need that log before you go looking, not after.
Composio's MCP Gateway records an audit trail for every tool call. Each team gets a secure MCP endpoint with toolkit-level controls and a complete log of every action the agent took, which is exactly what a security review needs. For teams using the managed layer, this audit trail is built in rather than something you need to instrument yourself.
Fixing common Supabase MCP connection errors
Most failures fall into three categories: malformed JSON-RPC messages from stdout contamination, authentication errors from incorrect credentials, and query timeouts from missing indexes.
Debugging failed handshake attempts
Stdout contamination is the most common cause of malformed JSON-RPC messages. A stray print() statement, an uncaught exception traceback, or a debug log accidentally routed to stdout instead of stderr breaks the message stream between your client and server. If you are writing a custom server, use the official MCP SDK rather than rolling your own transport layer. Check these three things when a handshake fails:
File path: Confirm the path to your config file is absolute, not relative.
Node version: Run
node --versionto confirm you are on 16 or higher.Environment variables: Confirm your
.envvalues load in the shell context Claude or Cursor is using, not just your terminal session.
Resolving database access denied
If your queries return a permission denied error, work through this sequence:
Confirm the API key in your environment variables matches the key in your Supabase dashboard under Settings > API.
Verify the database role you are connecting with has SELECT privileges on the target tables.
Check that your project's IP allow-list is not blocking the IP address of the machine running the MCP server.
Confirm RLS policies on the target tables include a matching policy for the role you are using. A table with RLS enabled and no matching policy returns zero rows, not an error, so silence is also a symptom.
Optimizing slow database queries
Add indexes on frequently queried columns to reduce query timeouts. Create indexes on columns your RLS policies reference first, since those run on every query against the table:
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_profiles_user_id ON profiles(user_id);For large tables, add a LIMIT clause instruction to your system prompt: "Always add a LIMIT clause of 100 or fewer rows unless the user explicitly requests a full export."
Compatible AI clients for Supabase MCP
Table 2: AI client and transport compatibility
AI client | stdio support | HTTP support | Recommended method |
|---|---|---|---|
Claude Desktop | Yes | Yes (Streamable HTTP via Custom Connectors) | stdio (local), Streamable HTTP (remote) |
Cursor IDE | Yes | Yes | stdio (local), HTTP (remote) |
Claude Code | Yes | Yes | stdio default |
ChatGPT | Yes | Yes (Streamable HTTP) | stdio or Streamable HTTP |
Production / multi-user | No | Yes | HTTP always |
Supabase MCP server cost requirements
Self-hosting the Supabase MCP server has no direct software cost because the package is open-source. The actual costs are:
Cloud compute for running the server process
Engineering time for token refresh logic, security audits, and debugging silent failures
Opportunity cost of not shipping product features while maintaining infrastructure
Composio's free tier gives you 100,000 tool calls per month with no credit card required. The Composio Supabase toolkit handles authentication, token refresh, and tool routing automatically. For a side project or solo workflow, the free tier covers significant volume before you need to consider the $29/month Pro plan.
Connect your Supabase database to Claude Desktop or Cursor today using Composio's managed Supabase MCP gateway. The free tier requires no credit card and gives you 100,000 tool calls per month to test your full workflow before committing to anything. When you're ready to go further, the same endpoint gives your agent access to 50,000+ agent-ready tools across Gmail, GitHub, Slack, HubSpot, and more, all part of the same action infrastructure that processes 300M+ tool calls per month, with authentication, token refresh, and schema handling managed across every integration.
FAQs
Is the Supabase MCP server free to use?
Yes, the native Supabase MCP package is open-source and free to run locally. Self-hosting it on a remote server will incur standard cloud compute costs for the server process and ongoing engineering time for maintenance.
Can an AI agent delete my entire database through MCP?
Yes, if the agent connects using DROP TABLEthe service role key or any role with ownership privileges, it can execute DROP TABLE and other schema-destructive commands. RLS policies do not prevent this: DROP TABLE is a DDL command governed by role privileges, not row-level access rules. To protect against it, connect agents using a purpose-built restricted role with no DROP, ALTER, or TRUNCATE privileges granted. Enable RLS separately to control which rows that role can read or write.
Does Composio support the Supabase MCP server?
Yes, Composio provides a managed MCP gateway that connects to Supabase, handling all token refreshes and security permissions automatically without requiring you to run or maintain a local server process.
How do I verify that my RLS policies are working correctly?
Run SET ROLE agent_readonly; (or whatever restricted role you created) in your Supabase SQL editor, then execute the queries your agent would run. If a DELETE or INSERT succeeds when it should not, your policy has a gap in its USING or WITH CHECK clause that needs to be fixed before connecting an agent.
Key terms glossary
Model Context Protocol (MCP): An open standard built on JSON-RPC 2.0 that connects AI models to external applications and databases. The protocol keeps raw credentials server-side rather than exposing them to the LLM.
Row-Level Security (RLS): A PostgreSQL security feature that restricts which database rows a user or role can query or modify. It evaluates automatically on every query based on the executing context.
stdio transport: A local communication method where an AI client and an MCP server exchange data using standard input and output streams. It works for single-user desktop workflows but does not support production multi-client deployments.
HTTP transport: A remote communication method that allows AI clients to connect to MCP servers hosted on external cloud infrastructure over secure web protocols. It is the correct choice for any production deployment.
Service role key: A JWT credential that bypasses all Row-Level Security policies in Supabase, granting full administrative access to the database. Never use it as the primary credential for agent connections.
Tool Router: Composio's routing layer that inspects incoming agent requests and directs them to the correct toolkit based on which services the user has authenticated, eliminating conditional logic in your agent code.