list_tablesLABSCO SUMMARY
Two privilege levels, declared per tool.
The split is what makes this usable with an agent: introspection runs on an ordinary authenticated token, and the migration, SQL, auth and storage writes are the ones that need service_role — so how far the assistant reaches is decided by which credential it gets. Over HTTP that split is enforced from the JWT's role claim; over stdio it is not enforced at all, so run that mode only where you would already trust the client with the database. The migrations tools depend on the table the Supabase CLI creates, so a database the CLI has never touched needs it created first.
What it is
A database-introspection and management server built for self-hosted Supabase rather than the cloud product, so there is no project selection or cloud API in the way. Tools are split by privilege: most read with any authenticated JWT, while the ones that change things require service_role.
What you get
- Schema read out in full: tables, columns, indexes, constraints, foreign keys, triggers and function definitions
- Extensions installed and extensions available to install, plus pg_cron jobs with their run history and pgvector indexes with their statistics
- Migrations listed from the Supabase migrations table, and a new one applied and recorded — that tool needs service_role
- Arbitrary SQL executed and any query explained, both privileged
- Row Level Security status and the policies themselves, listed — the part of a Supabase project hardest to reason about from migrations alone
- Database statistics, live connections and index statistics, plus advisory notices on security and performance
- Auth users listed, read, created, updated and deleted, with passwords hashed by the database rather than stored as given
- Storage buckets and their objects listed, with bucket configuration read and updated
- Edge functions listed with their details and recent logs, realtime publications inspected, and TypeScript types generated from the schema
Requirements
Bun 1.1 or newer, and a self-hosted Supabase the server can reach: its URL and anon key at minimum. Add the service-role key for the privileged tools, and a direct PostgreSQL connection string for anything that touches the auth or storage schemas or the system catalogs. Over stdio there is no authentication at all — every tool, privileged ones included, is available to whatever launched it, which is why that mode is for a trusted local client. The HTTP transport authenticates each request with a JWT and decides access from its role claim, with rate limiting and a CORS allow-list on top. A whitelist file limits which tools exist at all. MIT.
Setup effort
Build from source — git clone https://github.com/HenkDz/selfhosted-supabase-mcp.git
USE CASES
Learning a schema you did not design
List the tables, then the columns, indexes, constraints and foreign keys of the ones that matter, before writing a line of SQL against them.
Working out why a row is invisible
Check whether RLS is on for the table, then read the policies themselves — usually the answer is in a policy rather than in the query.
Making a schema change that stays recorded
Read what has already been applied, then apply the migration through the tool that also records it in the migrations table.
Chasing a slow query
Explain the query, look at whether the indexes meant to serve it are being used, and check what else is connected while it runs.
Sorting out a user who cannot sign in
Find the user in the auth schema, read the record, and reset what needs resetting — the password is hashed by the database rather than stored as sent.
Reading logic that lives in the database
List the functions and triggers, then pull the source of the ones that decide the behaviour you are trying to explain.
43 tools
Listed in project docs. Your client may show a different list.
list_extensionslist_available_extensionslist_migrationsapply_migrationlist_table_columnslist_indexeslist_constraintslist_foreign_keyslist_triggerslist_database_functionsget_function_definitionget_trigger_definitionexecute_sqlexplain_queryget_database_connectionsget_database_statsget_index_statsget_vector_index_statslist_rls_policiesget_rls_statusget_advisorsget_project_urlverify_jwt_secretgenerate_typescript_typesrebuild_hooksget_logslist_auth_usersget_auth_usercreate_auth_userupdate_auth_userdelete_auth_userlist_storage_bucketslist_storage_objectsget_storage_configupdate_storage_configlist_realtime_publicationslist_cron_jobsget_cron_job_historylist_vector_indexeslist_edge_functionsget_edge_function_detailslist_edge_function_logsBEFORE YOU INSTALL
What to know first
Tools you get
43 tools named in the project's documentation.
Requires
- Bun 1.1 or later
- SUPABASE_ANON_KEY in your environment
- SUPABASE_URL in your environment
Optional
- SUPABASE_SERVICE_ROLE_KEY in your environment
- SUPABASE_AUTH_JWT_SECRET in your environment
- DATABASE_URL in your environment
Where it runs
All 5 documented clients run the server on your machine.
INSTALLATION
Connect your client
You clone and build this one yourself.
Server setup
git clone https://github.com/HenkDz/selfhosted-supabase-mcp.git
cd selfhosted-supabase-mcp
bun install
bun run buildMCP Clients
Cursor, Windsurf, Cline, Other MCP clients
{
"mcpServers": {
"selfhosted-supabase": {
"command": "bun",
"args": [
"run",
"<YOUR_PATH_TO_DIST_INDEX_JS>",
"--url",
"<YOUR_SUPABASE_URL>",
"--anon-key",
"<YOUR_ANON_KEY>",
"--service-key",
"<YOUR_SERVICE_KEY>",
"--db-url",
"<YOUR_DB_URL>",
"--jwt-secret",
"<YOUR_JWT_SECRET>",
"--tools-config",
"<YOUR_MCP_TOOLS_JSON>"
]
}
}
}VS Code
{
"inputs": [
{
"type": "promptString",
"id": "sh-supabase-url",
"description": "Self-Hosted Supabase URL",
"default": "http://localhost:8000"
},
{
"type": "promptString",
"id": "sh-supabase-anon-key",
"description": "Self-Hosted Supabase Anon Key",
"password": true
},
{
"type": "promptString",
"id": "sh-supabase-service-key",
"description": "Self-Hosted Supabase Service Key (Optional)",
"password": true,
"required": false
},
{
"type": "promptString",
"id": "sh-supabase-db-url",
"description": "Self-Hosted Supabase DB URL (Optional)",
"password": true,
"required": false
},
{
"type": "promptString",
"id": "sh-supabase-jwt-secret",
"description": "Self-Hosted Supabase JWT Secret (Optional)",
"password": true,
"required": false
},
{
"type": "promptString",
"id": "sh-supabase-server-path",
"description": "Path to self-hosted-supabase-mcp/dist/index.js"
},
{
"type": "promptString",
"id": "sh-supabase-tools-config",
"description": "Path to tools config JSON (Optional, e.g., ./mcp-tools.json)",
"required": false
}
],
"servers": {
"selfhosted-supabase": {
"command": "bun",
"args": [
"run",
"${input:sh-supabase-server-path}",
"--tools-config",
"${input:sh-supabase-tools-config}"
],
"env": {
"SUPABASE_URL": "${input:sh-supabase-url}",
"SUPABASE_ANON_KEY": "${input:sh-supabase-anon-key}",
"SUPABASE_SERVICE_ROLE_KEY": "${input:sh-supabase-service-key}",
"DATABASE_URL": "${input:sh-supabase-db-url}",
"SUPABASE_AUTH_JWT_SECRET": "${input:sh-supabase-jwt-secret}"
}
}
}
}