This server enables developers to manage and interact with self-hosted Supabase instances through the Model Context Protocol (MCP), providing comprehensive database management tools:
Database Operations: List tables and extensions, execute SQL queries, generate TypeScript types, and access database statistics
Migration Management: List and apply SQL migration scripts
Configuration Access: Retrieve project URL, anonymous key, service role key, and verify JWT secret
User Authentication: List, retrieve, create, update, and delete auth users (note: some operations require direct DB access)
Storage Management: List storage buckets and objects within buckets
Monitoring Tools: View active connections, database stats, and Realtime publications
Development Utilities: Restart the
pg_networker
Provides tools for direct PostgreSQL database operations, including executing SQL queries, viewing database connections and statistics, listing extensions, and querying system catalogs.
Enables interaction with self-hosted Supabase instances, providing tools for database introspection, SQL query execution, schema management, migrations, auth user management, storage bucket operations, and TypeScript type generation.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Self-Hosted Supabase MCP Servershow me the list of tables in the database"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Self-Hosted Supabase MCP Server
Overview
This project provides a Model Context Protocol (MCP) server designed specifically for interacting with self-hosted Supabase instances. It bridges the gap between MCP clients (like IDE extensions) and your local or privately hosted Supabase projects, enabling database introspection, management, and interaction directly from your development environment.
This server was built from scratch, drawing lessons from adapting the official Supabase cloud MCP server, to provide a minimal, focused implementation tailored for the self-hosted use case.
Related MCP server: supabase-mcp
Purpose
The primary goal of this server is to enable developers using self-hosted Supabase installations to leverage MCP-based tools for tasks such as:
Querying database schemas and data.
Managing database migrations.
Inspecting database statistics and connections.
Managing authentication users.
Interacting with Supabase Storage.
Generating type definitions.
It avoids the complexities of the official cloud server related to multi-project management and cloud-specific APIs, offering a streamlined experience for single-project, self-hosted environments.
Features (Implemented Tools)
Tools are categorized by privilege level:
Regular tools are accessible by any authenticated Supabase JWT (
authenticatedorservice_rolerole).Privileged tools require a
service_roleJWT (HTTP mode) or direct database/service-key access (stdio mode).
Schema & Migrations
Tool | Description | Privilege |
| Lists tables in the database schemas | Regular |
| Lists installed PostgreSQL extensions | Regular |
| Lists all available (installable) extensions | Regular |
| Lists applied migrations from | Regular |
| Applies a SQL migration and records it in | Privileged |
| Lists columns for a specific table | Regular |
| Lists indexes for a specific table | Regular |
| Lists constraints for a specific table | Regular |
| Lists foreign keys for a specific table | Regular |
| Lists triggers for a specific table | Regular |
| Lists user-defined database functions | Regular |
| Gets the source definition of a function | Regular |
| Gets the source definition of a trigger | Regular |
Database Operations & Stats
Tool | Description | Privilege |
| Executes an arbitrary SQL query | Privileged |
| Runs | Privileged |
| Shows active connections ( | Regular |
| Retrieves database statistics ( | Regular |
| Shows index usage statistics | Regular |
| Shows pgvector index statistics | Regular |
Security & RLS
Tool | Description | Privilege |
| Lists Row-Level Security policies for a table | Regular |
| Shows RLS enabled/disabled status for tables | Regular |
| Retrieves security and performance advisory notices | Regular |
Project Configuration
Tool | Description | Privilege |
| Returns the configured Supabase URL | Regular |
| Checks if the JWT secret is configured | Regular |
Development & Extension Tools
Tool | Description | Privilege |
| Generates TypeScript types from the database schema | Regular |
| Restarts the | Privileged |
| Retrieves recent log entries (analytics stack or CSV fallback) | Regular |
Auth User Management
Tool | Description | Privilege |
| Lists users from | Regular |
| Retrieves details for a specific user | Regular |
| Creates a new user in | Privileged |
| Updates user details (password bcrypt-hashed if changed) | Privileged |
| Deletes a user from | Privileged |
Storage
Tool | Description | Privilege |
| Lists all storage buckets | Regular |
| Lists objects within a specific bucket | Regular |
| Retrieves storage bucket configuration | Regular |
| Updates storage bucket settings | Privileged |
Realtime Inspection
Tool | Description | Privilege |
| Lists PostgreSQL publications (e.g. | Regular |
Extension-Specific Tools
Tool | Description | Privilege |
| Lists scheduled jobs (requires | Regular |
| Shows recent execution history for a cron job | Regular |
| Lists pgvector indexes (requires | Regular |
Edge Functions
Tool | Description | Privilege |
| Lists deployed Edge Functions | Regular |
| Gets details and metadata for an Edge Function | Regular |
| Retrieves recent logs for an Edge Function | Regular |
About supabase_migrations.schema_migrations
The list_migrations and apply_migration tools rely on the supabase_migrations.schema_migrations table. This table is created and managed by the Supabase CLI — it is not part of the MCP server itself.
How the table is created:
The table is automatically created when you initialise or run migrations using the Supabase CLI:
If you have never run the Supabase CLI against your database, the table will not exist and list_migrations will return an error. You can create it manually with:
Schema difference vs. official Supabase:
The Supabase cloud platform tracks additional columns (e.g. statements, dirty). This MCP server uses the minimal schema (version + name + inserted_at) that is compatible with the Supabase CLI's local-development workflow. If your existing table has extra columns they are simply ignored.
Setup and Installation
Installing via Smithery
To install Self-Hosted Supabase MCP Server for Claude Desktop automatically via Smithery:
Prerequisites
Bun v1.1 or later (replaces Node.js/npm — used for runtime and builds)
Access to your self-hosted Supabase instance (URL, keys, and optionally a direct PostgreSQL connection string).
Steps
Clone the repository:
git clone <repository-url> cd selfhosted-supabase-mcpInstall dependencies:
bun installBuild the project:
bun run buildThis compiles the TypeScript source to JavaScript in the
distdirectory.
Configuration
The server requires configuration details for your Supabase instance. These can be provided via command-line arguments or environment variables. CLI arguments take precedence.
Required:
--url <url>orSUPABASE_URL=<url>: The main HTTP URL of your Supabase project (e.g.,http://localhost:8000).--anon-key <key>orSUPABASE_ANON_KEY=<key>: Your Supabase project's anonymous key.
Optional (but Recommended/Required for certain tools):
--service-key <key>orSUPABASE_SERVICE_ROLE_KEY=<key>: Your Supabase project's service role key. Required for privileged tools and for auto-creating theexecute_sqlhelper function on startup.--db-url <url>orDATABASE_URL=<url>: The direct PostgreSQL connection string for your Supabase database (e.g.,postgresql://postgres:password@localhost:5432/postgres). Required for tools needing direct database access (apply_migration, Auth tools, Storage tools,pg_catalogqueries).--jwt-secret <secret>orSUPABASE_AUTH_JWT_SECRET=<secret>: Your Supabase project's JWT secret. Required when using--transport httpand needed by theverify_jwt_secrettool.--tools-config <path>: Path to a JSON file specifying which tools to enable (whitelist). If omitted, all tools are enabled. Format:{"enabledTools": ["tool_name_1", "tool_name_2"]}.
HTTP transport options (when using
--port <number>: HTTP server port (default:3000).--host <string>: HTTP server host (default:127.0.0.1).--cors-origins <origins>: Comma-separated list of allowed CORS origins. Defaults to localhost only.--rate-limit-window <ms>: Rate limit window in milliseconds (default:60000).--rate-limit-max <count>: Max requests per rate limit window (default:100).--request-timeout <ms>: Request timeout in milliseconds (default:30000).
Important Notes:
execute_sqlMany tools rely on apublic.execute_sqlfunction within your Supabase database for SQL execution via RPC. The server attempts to check for this function on startup. If it's missing and aservice-keyanddb-urlare provided, it will attempt to create the function automatically. If creation fails or keys aren't provided, tools relying solely on RPC may fail.Direct Database Access: Tools interacting directly with privileged schemas (
auth,storage) or system catalogs (pg_catalog) generally requireDATABASE_URLto be configured.Coolify / reverse-proxy deployments:
The
DATABASE_URLmust use the internal hostname reachable from wherever the MCP server process runs, not the public-facing domain.An
ECONNRESETerror during startup means theDATABASE_URLcannot be reached from the server's network context.The server will still start successfully and all tools that don't require a direct DB connection will continue to work normally.
Security
HTTP transport (recommended for remote access)
When running with --transport http, the server enforces:
JWT authentication on all
/mcpendpoints using yourSUPABASE_AUTH_JWT_SECRET.Privilege-based access control (RBAC) — the
roleclaim in the JWT determines which tools are accessible:service_role: Full access (all tools including privileged ones).authenticated: Regular tools only.anon: No tool access.
Rate limiting — configurable request rate limit per IP address.
CORS — configurable allow-list of origins (defaults to localhost only).
Security headers —
X-Content-Type-Options,X-Frame-Options,Strict-Transport-Security, etc.Request timeouts — configurable timeout to prevent resource exhaustion.
Stdio transport (local development)
Stdio mode has no authentication — all tools (including privileged ones) are accessible. It is intended for trusted local clients only (e.g., an IDE extension running on your local machine). A warning is printed on startup when this mode is used.
Password handling for auth user tools
create_auth_user and update_auth_user accept a plain-text password from the MCP client, then immediately hash it with bcrypt (via PostgreSQL's pgcrypto extension: crypt($password, gen_salt('bf'))) before storing it in auth.users. The plain-text password is never stored. Passwords are passed as query parameters (not string-interpolated into SQL), preventing SQL injection.
Note: The password travels over the MCP transport in plain text between the MCP client and server. This is inherent to the MCP protocol interface and unavoidable at this layer. Use the HTTP transport with TLS termination (e.g., behind Kong/nginx) for network protection.
SQL execution security
All database operations in the MCP server use parameterized queries ($1, $2, ...) to prevent SQL injection. The execute_sql tool is an intentional exception — it executes arbitrary SQL by design (it is the tool's purpose). This tool is restricted to service_role privilege level to limit exposure.
Usage
Stdio mode (local MCP clients)
Run the server using Bun, providing the necessary configuration:
HTTP mode (Docker / remote access)
HTTP mode requires --jwt-secret. All /mcp requests must include a valid Supabase JWT in the Authorization: Bearer <token> header.
The server communicates via stdio (default) or HTTP (Streamable HTTP Transport) and is designed to be invoked by an MCP client application (e.g., an IDE extension like Cursor). The client will connect to the server's stdio stream or HTTP endpoint to list and call the available tools.
Client Configuration Examples
Below are examples of how to configure popular MCP clients to use this self-hosted server.
Important:
Replace placeholders like
<your-supabase-url>,<your-anon-key>,<your-db-url>,<path-to-dist/index.js>etc., with your actual values.Ensure the path to the compiled server file (
dist/index.js) is correct for your system.Be cautious about storing sensitive keys directly in configuration files, especially if committed to version control. Consider using environment variables or more secure methods where supported by the client.
Cursor
Create or open the file
.cursor/mcp.jsonin your project root.Add the following configuration:
{ "mcpServers": { "selfhosted-supabase": { "command": "bun", "args": [ "run", "<path-to-dist/index.js>", // e.g., "/home/user/selfhosted-supabase-mcp/dist/index.js" "--url", "<your-supabase-url>", // e.g., "http://localhost:8000" "--anon-key", "<your-anon-key>", // Optional - Add these if needed by the tools you use "--service-key", "<your-service-key>", "--db-url", "<your-db-url>", // e.g., "postgresql://postgres:password@host:port/postgres" "--jwt-secret", "<your-jwt-secret>", // Optional - Whitelist specific tools "--tools-config", "<path-to-your-mcp-tools.json>" // e.g., "./mcp-tools.json" ] } } }
Visual Studio Code (Copilot)
VS Code Copilot allows using environment variables populated via prompted inputs, which is more secure for keys.
Create or open the file
.vscode/mcp.jsonin your project root.Add the following configuration:
{ "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}" } } } }When you use Copilot Chat in Agent mode (@workspace), it should detect the server. You will be prompted to enter the details (URL, keys, path) when the server is first invoked.
Other Clients (Windsurf, Cline, Claude)
Adapt the configuration structure shown for Cursor or the official Supabase documentation, replacing the command and args with the bun run command and the arguments for this server, similar to the Cursor example:
Consult the specific documentation for each client on where to place the mcp.json or equivalent configuration file.
Docker Integration with Self-Hosted Supabase
This MCP server can be integrated directly into a self-hosted Supabase Docker Compose stack, making it available alongside other Supabase services via the Kong API gateway.
Architecture Overview
When integrated with Docker:
The MCP server runs in HTTP transport mode (not stdio)
It's exposed through Kong at
/mcp/v1/*JWT authentication is handled by the MCP server itself
The server has direct access to the database and all Supabase keys
Setup Steps
1. Add the MCP Server as a Git Submodule
From your Supabase Docker directory:
2. Create the Dockerfile
Create volumes/mcp/Dockerfile:
3. Add the MCP Service to docker-compose.yml
Add this service definition to your docker-compose.yml:
4. Add Kong API Gateway Routes
Add the MCP routes to volumes/api/kong.yml in the services section:
5. Enable the MCP Service
The MCP service uses Docker Compose profiles, so it's disabled by default. To enable it:
Option A: Set in
Option B: Enable at runtime:
Accessing the MCP Server
Once running, the MCP server is available at:
Internal (from other containers):
http://mcp:3100External (via Kong):
http://localhost:8000/mcp/v1/
Authentication
When running in HTTP mode, the MCP server validates JWTs using the configured JWT_SECRET. Clients must include a valid Supabase JWT in the Authorization header:
The JWT's role claim determines access:
service_role: Full access to all tools (regular + privileged)authenticated: Access to regular tools onlyanon: No tool access
Health Check
The MCP server exposes a health endpoint:
Security Considerations
When deploying via Docker:
The MCP server runs as a non-root user (
mcp:mcp)JWT authentication is enforced for all tool calls
Privileged tools (like
execute_sql) requireservice_roleJWTCORS is configured via Kong - adjust origins for your deployment
Development
Language: TypeScript
Build:
bun build(viabun run build)Runtime: Bun v1.1+
Test runner:
bun testDependencies: Managed via
bun(bun.lock)Core Libraries:
@supabase/supabase-js,pg(node-postgres),zod(validation),commander(CLI args),@modelcontextprotocol/sdk(MCP server framework),express,jsonwebtoken.
License
This project is licensed under the MIT License. See the LICENSE file for details.