Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
46 changes: 46 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# AGENTS.md

This file provides guidance to AI coding agents working on this repository.

## Project Overview

Supabase MCP (Model Context Protocol) servers - a pnpm monorepo.

## Packages

| Package | Description |
|---------|-------------|
| `@supabase/mcp-utils` | Shared utilities and base classes for MCP servers |
| `@supabase/mcp-server-supabase` | Main MCP server for Supabase platform |
| `@supabase/mcp-server-postgrest` | PostgREST MCP server |

## Build & Test Commands

```sh
pnpm install # Install all workspace dependencies
pnpm build # Build mcp-utils and mcp-server-supabase
pnpm test # Run all tests in parallel
pnpm test:coverage
pnpm format # Fix formatting with Biome
pnpm format:check
```

## Package Manager

This repo uses **pnpm** exclusively. Do not use npm or yarn.

## Dev Dependencies

- `@biomejs/biome` - Code formatting
- `supabase` - Supabase CLI

## Package-Specific Guides

- [packages/mcp-utils/AGENTS.md](packages/mcp-utils/AGENTS.md)
- [packages/mcp-server-supabase/AGENTS.md](packages/mcp-server-supabase/AGENTS.md)

## Do NOT

- Use `npm` or `yarn` - this repo uses pnpm only
- Modify `mise.lock` or `pnpm-lock.yaml` manually
- Run `pnpm build` during dev sessions - use `pnpm dev` in package directories
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# CLAUDE.md

See [AGENTS.md](./AGENTS.md) for project guidelines.
55 changes: 55 additions & 0 deletions packages/mcp-server-supabase/.claude/skills/architecture/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
name: mcp-server-supabase-architecture
description: Source structure, core layers, and data flow for the Supabase MCP server. Use when modifying the server structure, adding new tool domains, or understanding how components connect.
---

# Architecture Overview

## Source Structure

```
src/
├── server.ts # Main factory: createSupabaseMcpServer()
├── index.ts # Public exports
├── types.ts # Shared Zod schemas
├── tools/ # MCP tool implementations by domain
│ ├── account-tools.ts # list_organizations, get_project, create_project
│ ├── database-operation-tools.ts # execute_sql, list_tables
│ ├── edge-function-tools.ts # deploy_edge_function
│ ├── storage-tools.ts
│ ├── branching-tools.ts
│ ├── debugging-tools.ts
│ ├── development-tools.ts
│ └── docs-tools.ts
├── management-api/ # Supabase Management API client
│ ├── index.ts # Client factory (openapi-fetch)
│ └── types.ts # AUTO-GENERATED - do not edit
├── content-api/ # Documentation GraphQL API
├── pg-meta/ # Database introspection SQL generators
├── platform/ # Platform abstraction layer
│ ├── types.ts # Operation interfaces
│ └── api-platform.ts # Management API implementation
└── transports/
└── stdio.ts # CLI entry point
```

## Core Layers

1. **Server Layer** (`server.ts`) - MCP server factory, feature orchestration
2. **Tools Layer** (`tools/`) - Domain-grouped implementations using `tool()` helper
3. **Platform Layer** (`platform/`) - Abstraction over Supabase APIs
4. **API Clients** - Management API (openapi-fetch), Content API (GraphQL)

## Data Flow

```
AI Client → Stdio Transport → MCP Server → Tool Handler → Platform Operations → Supabase API
```

## Adding a New Tool Domain

1. Create `src/tools/new-domain-tools.ts`
2. Export `getNewDomainTools({ operations, readOnly })` function
3. Add operation interface to `platform/types.ts`
4. Implement operations in `platform/api-platform.ts`
5. Register in `server.ts` conditional tool loading
73 changes: 73 additions & 0 deletions packages/mcp-server-supabase/.claude/skills/testing/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
name: mcp-server-supabase-testing
description: Testing patterns for the Supabase MCP server including MSW HTTP mocking, PGlite database mocking, and AI-powered assertions. Use when writing tests, setting up mocks, or debugging test failures.
---

# Testing Patterns

## Test Types

- **Unit**: `src/**/*.test.ts` - Co-located with source
- **E2E**: `test/e2e/**/*.e2e.ts` - Requires `SUPABASE_ACCESS_TOKEN`
- **Integration**: `test/**/*.integration.ts`

## HTTP Mocking with MSW

All unit tests MUST mock HTTP calls using MSW. Mocks are defined in `test/mocks.ts`.

```typescript
import { setupServer } from 'msw/node';
import { mockManagementApi } from './mocks.ts';

const server = setupServer(...mockManagementApi);

beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' }));
beforeEach(() => {
mockOrgs.clear();
mockProjects.clear();
});
afterAll(() => server.close());
```

## Database Mocking with PGlite

```typescript
import { PGlite } from '@electric-sql/pglite';

const db = new PGlite();
await db.waitReady;
await db.exec(`
CREATE ROLE supabase_read_only_role;
GRANT pg_read_all_data TO supabase_read_only_role;
`);
```

## AI Test Matcher

Custom `toMatchCriteria()` uses Claude API for semantic assertions:

```typescript
// Requires ANTHROPIC_API_KEY
await expect(response.text).toMatchCriteria('Contains a valid SQL query');
```

## Test Setup Pattern

```typescript
async function setup(options = {}) {
const clientTransport = new StreamTransport();
const serverTransport = new StreamTransport();

clientTransport.readable.pipeTo(serverTransport.writable);
serverTransport.readable.pipeTo(clientTransport.writable);

const client = new Client({ name: 'test', version: '1.0' }, { capabilities: {} });
const platform = createSupabaseApiPlatform({ apiUrl, accessToken });
const server = createSupabaseMcpServer({ platform, ...options });

await server.connect(serverTransport);
await client.connect(clientTransport);

return { client, server };
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
name: mcp-server-supabase-tools
description: Tool registration patterns for the Supabase MCP server. Use when creating new tools, modifying existing tools, or understanding how tools are registered with the server.
---

# Tool Registration Patterns

## Creating Tools

Tools use the `tool()` helper from `@supabase/mcp-utils`:

```typescript
import { tool } from '@supabase/mcp-utils';
import { z } from 'zod';

export function getAccountTools({ account, readOnly }: AccountToolsOptions) {
return {
list_organizations: tool({
description: 'Lists all organizations the user is a member of.',
annotations: {
title: 'List organizations',
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: false,
},
parameters: z.object({}),
execute: async () => account.listOrganizations(),
}),

create_project: tool({
description: 'Creates a new Supabase project.',
annotations: {
title: 'Create project',
readOnlyHint: false,
destructiveHint: false,
},
parameters: z.object({
name: z.string(),
organization_id: z.string(),
region: z.enum(AWS_REGION_CODES),
}),
execute: async (params) => account.createProject(params),
}),
};
}
```

## Tool Annotations

- `readOnlyHint`: Tool doesn't modify state
- `destructiveHint`: Tool may delete/corrupt data
- `idempotentHint`: Calling multiple times has same effect
- `openWorldHint`: Tool interacts with external world

## Registering Tools in Server

Tools are conditionally registered in `server.ts`:

```typescript
const server = createMcpServer({
name: 'supabase',
tools: async () => {
const tools: Record<string, Tool> = {};

if (enabledFeatures.has('account') && account) {
Object.assign(tools, getAccountTools({ account, readOnly }));
}

if (enabledFeatures.has('database') && database) {
Object.assign(tools, getDatabaseOperationTools({ database, readOnly }));
}

return tools;
},
});
```

## Read-Only Mode

When `readOnly: true`, tools that modify state should either:
1. Not be registered
2. Throw an error on execute
49 changes: 49 additions & 0 deletions packages/mcp-server-supabase/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# AGENTS.md

This file provides guidance to AI coding agents working on this package.

## Build & Test Commands

```sh
pnpm build # Production build (runs typecheck first)
pnpm dev # Watch mode with auto-rebuild
pnpm typecheck # Type check without emitting

pnpm test # Run all tests
pnpm test:unit # Unit tests only
pnpm test:e2e # E2E tests (requires SUPABASE_ACCESS_TOKEN)
pnpm test:integration # Integration tests

pnpm generate:management-api-types # Regenerate API types from OpenAPI
pnpm registry:update # Update server.json for MCP registry
```

## Environment Variables

| Variable | Required For |
|----------|--------------|
| `SUPABASE_ACCESS_TOKEN` | E2E tests, running the server |
| `ANTHROPIC_API_KEY` | AI test matcher |

## Code Style

- Biome formatting (single quotes, ES5 trailing commas, 2-space indent)
- ESM imports with `.js` extensions
- Zod schemas for all external inputs
- Tests: `*.test.ts` co-located, `*.e2e.ts` in `test/e2e/`

## Do NOT

- Edit `src/management-api/types.ts` - use `pnpm generate:management-api-types`
- Edit `server.json` - use `pnpm registry:update`
- Skip HTTP mocking in unit tests - use MSW
- Run `pnpm build` during development - use `pnpm dev`
- Commit `.env.local` or access tokens

## Agent Skills

For detailed patterns and architecture, see the on-demand skills in `.claude/skills/`:

- **architecture** - Source structure, core layers, data flow
- **testing** - MSW mocking, PGlite, AI test matcher patterns
- **tool-registration** - Creating and registering MCP tools
3 changes: 3 additions & 0 deletions packages/mcp-server-supabase/CLAUDE.md
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These CLAUDE.md can be symlinks to AGENTS.md to save the extra lookup (inspired by the agent setup guide from https://www.effect.solutions/quick-start)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess they did the other way around and linked their Agents.md to Claude.md 😆 Good suggestion to use symlinks, it is more straight forward

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# CLAUDE.md

See [AGENTS.md](@supabase/mcp-server-supabase/AGENTS.md) for package guidelines.
Loading