Supabase MCP Server
A Supabase MCP server built with the Dedalus MCP framework. Provides secure access to Supabase databases via the PostgREST API with credential encryption and JIT token exchange.
Features
Available Tools
Read Operations
| Tool | Description |
|---|---|
db_select | Select rows from a table with optional filters, ordering, and pagination |
db_get_by_id | Get a single row by primary key |
Write Operations
| Tool | Description |
|---|---|
db_insert | Insert one or more rows into a table |
db_update | Update rows matching specified filters |
db_delete | Delete rows matching specified filters |
db_upsert | Insert or update rows on conflict |
RPC
| Tool | Description |
|---|---|
db_rpc | Call a Supabase stored procedure/function |
Prerequisites
- Python 3.10+
- uv package manager
- Supabase project URL and API key
- Dedalus API Key
Setup
- Clone the repository
git clone https://github.com/dedalus-labs/supabase-mcp.git
cd supabase-mcp
- Install dependencies
uv sync
- Configure environment variables
Create a .env file based on .env.example.
Client Usage
import asyncio
import os
from dotenv import load_dotenv
from dedalus_labs import AsyncDedalus, DedalusRunner
from dedalus_mcp.auth import Connection, SecretKeys, SecretValues
load_dotenv()
SUPABASE_URL = os.getenv("SUPABASE_URL")
# Define the Supabase connection
supabase = Connection(
name="supabase-mcp",
secrets=SecretKeys(key="SUPABASE_SECRET_KEY"),
base_url=f"{SUPABASE_URL}/rest/v1",
auth_header_name="apikey",
auth_header_format="{api_key}",
)
# Bind credentials (encrypted client-side, decrypted at dispatch time)
supabase_secrets = SecretValues(supabase, key=os.getenv("SUPABASE_SECRET_KEY", ""))
async def main():
client = AsyncDedalus(
api_key=os.getenv("DEDALUS_API_KEY"),
base_url=os.getenv("DEDALUS_API_URL"),
as_base_url=os.getenv("DEDALUS_AS_URL"),
)
runner = DedalusRunner(client)
result = await runner.run(
input="Select all rows from the users table, limit to 5.",
model="openai/gpt-5",
mcp_servers=["issac/supabase-mcp"],
credentials=[supabase_secrets],
)
print(result.output)
if __name__ == "__main__":
asyncio.run(main())
License
MIT License - see LICENSE for details.
