# supabase/mcp: the server that hands your database to Cursor and Claude

> Supabase's Model Context Protocol server gives AI editors a live connection to a real project, and it ships in three flavours with different tool sets and different authentication rules.

**supabase/mcp** — Connect Supabase to your AI assistants

- Repository: https://github.com/supabase/mcp
- Website: https://supabase.com/mcp
- Stars: 2,915 · Forks: 405
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/supabase-mcp

## Three ways to reach the same server, with different tool sets

The README describes one server with three entry points, and the differences between them are not cosmetic. The hosted endpoint is the full product: `https://mcp.supabase.com/mcp`, reached over HTTP with a login prompt that lets you pick the organization containing your project. The Supabase CLI adds a second route at `http://localhost:54321/mcp` for work against a local stack. Self-hosted Supabase offers a third, documented separately. The README is explicit that both the CLI and the self-hosted variants offer a limited subset of tools and no OAuth 2.1.

That last sentence is the one to read twice. If you develop against `localhost:54321` and then point your assistant at the hosted URL, you may find tools that simply are not there, and the difference will not announce itself as an authentication error. There is also a per-project URL builder in the dashboard, reachable through the MCP connection tab, which produces a custom URL with project options baked in rather than relying on the client to send them at call time.

The project is a TypeScript monorepo, not a single package. The top-level `package.json` filters across `@supabase/mcp-utils`, `@supabase/mcp-server-supabase`, and `@supabase/mcp-server-postgrest` for both build and test, which is a reasonable signal that the server and its shared helpers are meant to be consumed separately. The root also carries `pnpm-workspace.yaml`, `mise.toml`, and a `biome.json` pinned to Biome 1.9.4, so formatting is checked by tool rather than by convention. The last push was 2026-09-19 and the repository is not archived, at roughly 2915 stars and 124 open issues.

## The client config is three fields, and the security page comes first

Step one of the setup instructions is not a command. It is a link to Supabase's security best practices page, framed as a prerequisite for understanding the risks of connecting an LLM to your projects. Most MCP server READMEs lead with an install command; this one leads with a warning, which tells you something about how the maintainers think about the surface area.

Step two is the configuration block that almost every client understands:

```json
{
  "mcpServers": {
    "supabase": {
      "type": "http",
      "url": "https://mcp.supabase.com/mcp"
    }
  }
}
```

Three keys, and the whole server definition is the URL. There is no token field because there is no static credential: the client prompts for a Supabase login during setup, and the session that results is what authorizes later calls. The README also covers the case where your client is not one of the listed ones, telling you to copy that MCP information into whatever format the client expects, json or yaml.

The documentation boundary here is worth naming. The README deliberately stops at the configuration block and defers everything else, sending you to the setup documentation for client-specific steps, to supabase.com/mcp for the full tool list and the configuration options, and to the dashboard for the URL builder. It even notes that the docs page offers an interactive builder for those options. So the repository tells you how to connect, and the site tells you what you can do once connected. If you want to know the tool catalogue, the README is not where to look.

## Feature groups, read_only, and project_ref as a narrowing strategy

Configuration happens through URL query parameters, and the README names three of them through the TypeScript bridge. `features` restricts the server to specific feature groups, with the README giving `['database', 'docs']` as the example and noting that it defaults to all default feature groups. `read_only=true` excludes mutating tools. `project_ref` pins the connection to one project, which in turn is what makes `projectScoped` meaningful, since that option omits `project_id` from tool input schemas and drops account-level tools entirely.

Put together, those three parameters describe a least-privilege posture that is genuinely easy to construct: one project, a narrow slice of feature groups, and no write access. That is a much better default for an assistant pointed at production than the out-of-the-box full tool set, and nothing about the URL makes it hard. The README also describes the interactive URL builder on the docs page for generating one of these by hand rather than assembling the query string yourself.

What you give up by narrowing is the point where it stops being obvious. `readOnly` is documented as excluding mutating tools, and there is no README statement about which tools those are, because the catalogue lives on supabase.com/mcp. If your workflow depends on applying a migration, the safe configuration will not perform it, and the tool will simply be absent rather than returning a permission error. Plan for that by deciding up front whether the assistant is meant to observe your schema or change it, because that decision picks the URL.

## The AI SDK bridge and the missing structuredContent

For people embedding the server in an application rather than in an editor, the package exports `createToolSchemas()`, which populates input and output schemas for Vercel AI SDK's MCP client. The point is to let Supabase tools be treated as static tools with client-side validation and inferred TypeScript types, rather than being discovered at runtime:

```ts
import { createToolSchemas } from '@supabase/mcp-server-supabase';
import { createMCPClient } from '@ai-sdk/mcp';
import { streamText } from 'ai';

const mcpClient = await createMCPClient({
  transport: {
    type: 'http',
    url: 'https://mcp.supabase.com/mcp',
  },
});

const tools = await mcpClient.tools({
  schemas: createToolSchemas(),
});

const result = streamText({ model, tools, prompt: '...' });

for (const step of await result.steps) {
  for (const toolResult of step.staticToolResults) {
    if (toolResult.toolName === 'get_project_url') {
      toolResult.input;  // { project_id: string }
      toolResult.output; // { url: string }
    }
  }
}
```

The filtering options on `createToolSchemas()` mirror the URL parameters one for one: `features`, `projectScoped`, and `readOnly`, with the same defaults of `false` for the last two. Keeping both in sync matters, and the README shows them set together on a URL that already carries `project_ref`, `read_only=true`, and `features=database,docs`. If you filter on the TypeScript side and not in the URL, the schemas and the actual tool list disagree.

There is one caveat the README flags with a note, and it is the kind that would otherwise cost an afternoon. This server does not send `structuredContent` in MCP tool results, so AI SDK falls back to parsing JSON out of the `content` text. The typed outputs you see in the example are therefore a convenience layered on a text fallback, not a guarantee from the protocol. If you are asserting on tool output shapes in your own code, that fallback is the thing to test.

## Self-hosting the handler means getting the close() timing right

The same package exports `createSupabaseMcpHandler()` to serve the tools over HTTP from your own endpoint. It accepts the same `SupabaseMcpServerOptions` as `createSupabaseMcpServer()`, with `platform` called out as the important one, because that is where the credential lives.

Two constraints follow from that, and both are stated plainly in the README. First, the handler speaks the current protocol revision only: it is created with `legacy: 'reject'`, so a client limited to the 2025-era protocol gets an HTTP 400 rather than a degraded session. Second, and more awkward, the handler closes over the `platform` you supply. If the credential is per request, you create the handler per request and close it when the response finishes. If the platform is meant to be shared, such as a single service-account token, you create it once and close it at shutdown. The reason is stated plainly too: `close()` aborts in-flight exchanges and tears down the subscription router, so an early close refuses later requests rather than degrading them.

That lifecycle note is the whole self-hosting story in miniature, and it is a real operational constraint rather than an implementation detail. A shared service-account handler gives you a clean long-lived process with a single shutdown hook. A per-request handler has to be disposed on response completion, which means your framework's response lifecycle has to actually fire, or you leak subscriptions. The README also notes that per-request credentials should arrive through URL mode for `create_edge_function_secret`, a detail that comes from the 0.13.0 release notes rather than the setup documentation.

## Version 0.13.0 moved destructive SQL behind a confirmation prompt

The release history is where this project's safety posture becomes concrete. `mcp-server-supabase-v0.13.0`, published 2026-09-17, is marked as a breaking change with a single entry: destructive SQL is now confirmed through elicitation, and the `costConfirmation` option is renamed. Alongside it came a `--http` local HTTP entry for the CLI server, a v2 management API client, support for `skip_elicitations` in the local HTTP server, and URL-mode secret collection for `create_edge_function_secret`.

The elicitation work is not confined to that release. `mcp-utils-v0.8.0` and `mcp-server-supabase-v0.12.0` both shipped on 2026-09-04, and between them they added a project cost confirmation elicitation, a branch cost confirmation elicitation, and a change to hide legacy cost tools from form-capable clients. The grouping of lints in the `get_advisors` response arrived in the same window. Read together, these are the maintainers closing the gap between an agent that can spend money or destroy data and one that has to ask a human first.

That history also explains a design choice in the TypeScript bridge. Elicitation is a client capability: the server asks, and a client that can render a form answers properly, while one that cannot falls back or declines. The `skip_elicitations` option exists precisely because some clients, including the local HTTP server, cannot do this. So the confirmation behavior you get depends on both the server version and the honesty of your client about what it supports. The 0.13.0 rename of `costConfirmation` is the sort of thing that breaks a working integration at upgrade time with no deprecation window, which is worth knowing before you pin a version.

## Conclusion

The hosted endpoint at mcp.supabase.com is the version worth trying first, because it carries the full tool set and gets OAuth 2.1 for free once your client logs in to the right organization. The local CLI and self-hosted routes are useful but genuinely narrower, offering a limited subset of tools with no OAuth 2.1, so a workflow that works against the hosted server may not transfer. What the README settles is the configuration surface: the URL, the feature groups, and the readOnly and projectScoped switches. What it does not settle is the tool catalogue itself, which lives on supabase.com/mcp and is worth reading before you connect anything, since the server hands an agent schema and query tools against production data. For self-hosting, the lifecycle note on createSupabaseMcpHandler is the part to get right, because calling close() at the wrong moment tears down the subscription router for every later request.

## FAQ

### Is there an MCP for Supabase?

Yes. Supabase maintains one, and it is the official server rather than a third-party build. The hosted endpoint is https://mcp.supabase.com/mcp, with separate routes for the Supabase CLI at http://localhost:54321/mcp and for self-hosted installations.

### Is Supabase MCP read only?

It can be. Add read_only=true to the server URL to exclude mutating tools, and the same readOnly option exists on createToolSchemas() for the TypeScript bridge. By default it is not read only, and `project_ref` plus `features` narrow it further.

### Does the Supabase MCP server work with self-hosted installations?

Yes, with a narrower tool set. The README states that self-hosted environments offer a limited subset of tools and no OAuth 2.1. The CLI route at http://localhost:54321/mcp has the same limitation.

## Sources

- [License: Apache-2.0](https://github.com/supabase/mcp/blob/main/LICENSE)
- [Project website](https://supabase.com/mcp)
- [README](https://github.com/supabase/mcp/blob/main/README.md)
- [Releases](https://github.com/supabase/mcp/releases)
- [supabase/mcp on GitHub](https://github.com/supabase/mcp)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/supabase-mcp
