Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6d1a718
feat!: migrate to MCP SDK v2
raulb Jul 9, 2026
42b56e2
fix: tests
raulb Jul 9, 2026
d0694c6
chore: bump
raulb Jul 10, 2026
658074b
fix: port util.test.ts to v2 SDK client imports
barryroodt Jul 21, 2026
21e2173
test: pin legacy stdio wire contract
barryroodt Aug 11, 2026
e3f194d
chore: pin the stable MCP v2 SDK
barryroodt Aug 11, 2026
cb5b10f
feat!: drop orphaned ExpandRecursively and document the client peer
barryroodt Aug 11, 2026
c6eefcb
feat: serve Supabase MCP over both protocol eras
barryroodt Aug 11, 2026
e464513
fix: report stdio serving errors through serveStdio onerror
barryroodt Aug 11, 2026
bfae7b1
fix: address review findings on dual-era serving
barryroodt Aug 11, 2026
d877078
test: assert the malformed-envelope contract, not the SDK's wording
barryroodt Aug 11, 2026
ce9e313
docs: don't drop close() and handler promises in the mounting example
barryroodt Aug 12, 2026
851f01e
docs: document handler mounting and testing setup
barryroodt Aug 13, 2026
d53b885
feat: normalize MCP structured tool results
barryroodt Aug 18, 2026
af58e74
feat: add pre-execution tool policy seam
barryroodt Aug 18, 2026
8d5894d
feat: add thin MCP elicitation runtime
barryroodt Aug 18, 2026
5bbd0ea
fix: align replay expiry with codec validity and harden parity suite
barryroodt Aug 18, 2026
cd8d7b5
fix: sanitize policy telemetry at the callback boundary
barryroodt Aug 18, 2026
1dea2ba
feat: add pre-consume gate to elicitation runtime
barryroodt Aug 18, 2026
7bb309f
feat: add Supabase cost confirmation policies
barryroodt Aug 18, 2026
4c1572c
feat: require confirmation for paid resource creation
barryroodt Aug 18, 2026
64bd8b3
feat: wire elicitation and opt-out into stdio serving
barryroodt Aug 18, 2026
bd5f404
fix: emit authoritative formSupportReason in policy telemetry
barryroodt Aug 18, 2026
1232ab1
fix: source legacy-era client capabilities in context normalization
barryroodt Aug 18, 2026
de1398d
fix: project legacy tool results against contextual output schema
barryroodt Aug 18, 2026
a97a2f4
fix: let established confirmations survive mid-flow opt-out
barryroodt Aug 18, 2026
c565540
test: complete form-mode contract matrix
barryroodt Aug 18, 2026
557ed95
chore: apply repo formatting
barryroodt Aug 18, 2026
bece494
test: make MAC tamper mutation deterministic
barryroodt Aug 18, 2026
bcef4ff
fix: preserve legacy discovery schema bytes
barryroodt Aug 18, 2026
ba1dc40
test: pin served-surface contract rows
barryroodt Aug 18, 2026
e9a4498
chore: apply repo formatting
barryroodt Aug 18, 2026
43c806c
chore: apply management API types sync from #364
barryroodt Aug 19, 2026
54939df
fix: address elicitation review findings
barryroodt Aug 19, 2026
c5660c9
chore: update management API types
barryroodt Aug 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ Configure your MCP client to run the local build. You may need to restart the se

Optionally, configure `--api-url` to point at a different Supabase instance (defaults to `https://api.supabase.com`)

## Testing

```bash
pnpm test # unit and integration suites for all three packages
pnpm test:coverage # mcp-server-supabase, with coverage
```

### Packaging gates

`scripts/` holds checks that span more than one package and run outside the pnpm workspace. `pnpm test:packed-platform-consumer` packs `@supabase/mcp-server-supabase` together with its workspace dependency `@supabase/mcp-utils`, installs both from real tarballs with plain `npm` in a temporary project, and drives the public surface there. Workspace resolution (`workspace:`, `catalog:`, symlinked `node_modules`) cannot reach that project, which is what makes it a test of the published artifact rather than of the checkout.

Add a script here when a check needs more than one package, or needs to run from outside the workspace. Anything scoped to a single package belongs in that package's own `test` script.

## Releases

Releases are automated via [release-please](https://github.com/googleapis/release-please). It tracks commits on `main` and opens a release PR when there are releasable changes (`fix:` or `feat:`). Merging that PR:
Expand Down
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ See the [Supabase MCP Server](https://supabase.com/mcp) docs for the full list o

The docs also feature an interactive URL builder to populate configuration options for you.

### Disable elicitations

Disable form-mode elicitation for one connection while keeping the legacy `confirm_cost` flow:

- **stdio CLI:** start the server with `--disable-elicitations`.
- **Hosted URL:** add `disable_elicitations=true` to the connection URL query.

## Usage with AI SDK's MCP Client

The `@supabase/mcp-server-supabase` package exports `createToolSchemas()` to populate input and output schemas for Vercel AI SDK's [MCP client](https://ai-sdk.dev/docs/ai-sdk-core/mcp-tools). This allows Supabase MCP tools to be treated as static tools with client-side validation and inferred TypeScript types for their inputs and outputs.
Expand Down Expand Up @@ -110,6 +117,41 @@ const tools = await mcpClient.tools({

For more information, see [Schema Definition](https://ai-sdk.dev/docs/ai-sdk-core/mcp-tools#schema-definition) and [Typed Tool Outputs](https://ai-sdk.dev/docs/ai-sdk-core/mcp-tools#typed-tool-outputs) in the AI SDK docs.

## Self-hosting the MCP endpoint

The `@supabase/mcp-server-supabase` package exports `createSupabaseMcpHandler()` to serve the tools over HTTP from your own endpoint. It accepts the same `SupabaseMcpServerOptions` as `createSupabaseMcpServer()`, most importantly `platform`.

The handler speaks the current protocol revision only. It is created with `legacy: 'reject'`, so a client that only speaks the 2025-era protocol receives an HTTP 400 instead of being served.

When `platform` carries a per-request credential, create the handler per request and close it when the response finishes. The handler closes over the `platform` you supply, so a shared one serves every request with that platform.

A long-lived handler is fine when the `platform` is meant to be shared, a service-account token for example. Create it once and `close()` it at shutdown rather than per response, since `close()` tears down the subscription router and refuses later requests.

```ts
import { createServer } from 'node:http';
import { toNodeHandler } from '@modelcontextprotocol/node';
import { createSupabaseMcpHandler } from '@supabase/mcp-server-supabase';
import { createSupabaseApiPlatform } from '@supabase/mcp-server-supabase/platform/api';

const server = createServer((req, res) => {
const accessToken = getAccessTokenFromRequest(req); // your own auth

const handler = createSupabaseMcpHandler({
platform: createSupabaseApiPlatform({ accessToken }),
});

// `close()` aborts in-flight exchanges, so close on `res` finishing rather
// than when the handler resolves, which would cut streaming responses short.
res.on('close', () => {
handler.close().catch((error) => console.error(error));
});

toNodeHandler(handler)(req, res).catch((error) => console.error(error));
});
```

`toNodeHandler` comes from `@modelcontextprotocol/node`, which is not a dependency of this package. Install it alongside.

## Other MCP servers

### `@supabase/mcp-server-postgrest`
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"build": "pnpm --filter @supabase/mcp-utils --filter @supabase/mcp-server-supabase --filter @supabase/mcp-server-postgrest build",
"test": "pnpm --parallel --filter @supabase/mcp-utils --filter @supabase/mcp-server-supabase --filter @supabase/mcp-server-postgrest test",
"test:coverage": "pnpm --filter @supabase/mcp-server-supabase test:coverage",
"test:packed-platform-consumer": "node scripts/test-packed-platform-consumer.mjs",
"format": "biome check --write .",
"format:check": "biome check ."
},
Expand Down
8 changes: 6 additions & 2 deletions packages/mcp-server-postgrest/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,14 @@ pnpm add @supabase/mcp-server-postgrest

#### Example

The following example uses the [`StreamTransport`](../mcp-utils#streamtransport) to connect directly between an MCP client and server.
The following example uses the [`StreamTransport`](../mcp-utils#streamtransport) to connect directly between an MCP client and server. It also needs `@modelcontextprotocol/client`, which is a separate package from the `@modelcontextprotocol/server` peer dependency and is not installed for you:

```bash
npm i @modelcontextprotocol/client
```

```ts
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { Client } from '@modelcontextprotocol/client';
import { StreamTransport } from '@supabase/mcp-utils';
import { createPostgrestMcpServer } from '@supabase/mcp-server-postgrest';

Expand Down
5 changes: 3 additions & 2 deletions packages/mcp-server-postgrest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@
"@supabase/sql-to-rest": "^0.1.8"
},
"peerDependencies": {
"@modelcontextprotocol/sdk": "catalog:",
"@modelcontextprotocol/server": "catalog:",
"zod": "catalog:"
},
"devDependencies": {
"@modelcontextprotocol/sdk": "catalog:",
"@modelcontextprotocol/client": "catalog:",
"@modelcontextprotocol/server": "catalog:",
"@supabase/auth-js": "^2.67.3",
"@total-typescript/tsconfig": "^1.0.4",
"@types/node": "^22.8.6",
Expand Down
3 changes: 2 additions & 1 deletion packages/mcp-server-postgrest/src/server.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { Client } from '@modelcontextprotocol/client';
import { AuthClient } from '@supabase/auth-js';
import { StreamTransport } from '@supabase/mcp-utils';
import { describe, expect, test } from 'vitest';

import { createPostgrestMcpServer } from './server.js';

// Requires local Supabase stack running
Expand Down
4 changes: 2 additions & 2 deletions packages/mcp-server-postgrest/src/stdio.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env node

import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { parseArgs } from 'node:util';
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';

import { createPostgrestMcpServer } from './server.js';

async function main() {
Expand Down
5 changes: 3 additions & 2 deletions packages/mcp-server-supabase/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,15 @@
"openapi-fetch": "^0.13.5"
},
"peerDependencies": {
"@modelcontextprotocol/sdk": "catalog:",
"@modelcontextprotocol/server": "catalog:",
"zod": "catalog:"
},
"devDependencies": {
"@ai-sdk/anthropic": "catalog:",
"@ai-sdk/mcp": "catalog:",
"@electric-sql/pglite": "^0.2.17",
"@modelcontextprotocol/sdk": "catalog:",
"@modelcontextprotocol/client": "catalog:",
"@modelcontextprotocol/server": "catalog:",
"@total-typescript/tsconfig": "^1.0.4",
"@types/common-tags": "^1.8.4",
"@types/node": "^22.8.6",
Expand Down
7 changes: 7 additions & 0 deletions packages/mcp-server-supabase/server.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@
"format": "boolean",
"isRequired": false
},
{
"type": "named",
"name": "--disable-elicitations",
"description": "Disable form-mode elicitation",
"format": "boolean",
"isRequired": false
},
{
"type": "named",
"name": "--features",
Expand Down
Loading
Loading