diff --git a/packages/mcp-server-supabase/package.json b/packages/mcp-server-supabase/package.json index 6c47f0f..3d0db03 100644 --- a/packages/mcp-server-supabase/package.json +++ b/packages/mcp-server-supabase/package.json @@ -65,6 +65,7 @@ }, "devDependencies": { "@ai-sdk/anthropic": "catalog:", + "hono": "^4.7.10", "@ai-sdk/mcp": "catalog:", "@electric-sql/pglite": "^0.2.17", "@modelcontextprotocol/sdk": "catalog:", diff --git a/packages/mcp-server-supabase/src/management-api/index.ts b/packages/mcp-server-supabase/src/management-api/index.ts index 74110c0..736225c 100644 --- a/packages/mcp-server-supabase/src/management-api/index.ts +++ b/packages/mcp-server-supabase/src/management-api/index.ts @@ -14,7 +14,8 @@ import type { paths } from './types.js'; export function createManagementApiClient( baseUrl: string, accessToken: string, - headers: Record = {} + headers: Record = {}, + fetch?: (request: Request) => Response | Promise ) { return createClient({ baseUrl, @@ -22,6 +23,7 @@ export function createManagementApiClient( Authorization: `Bearer ${accessToken}`, ...headers, }, + fetch: fetch ? (request) => Promise.resolve(fetch(request)) : undefined, }); } diff --git a/packages/mcp-server-supabase/src/platform/api-platform.test.ts b/packages/mcp-server-supabase/src/platform/api-platform.test.ts new file mode 100644 index 0000000..3a72d21 --- /dev/null +++ b/packages/mcp-server-supabase/src/platform/api-platform.test.ts @@ -0,0 +1,35 @@ +import { Hono } from 'hono'; +import { describe, expect, test } from 'vitest'; +import { createSupabaseApiPlatform } from './api-platform.js'; + +describe('createSupabaseApiPlatform with custom fetch', () => { + test('routes management API calls through custom fetch handler', async () => { + const projects = [ + { + id: 'proj1', + ref: 'proj1', + name: 'Test Project', + organization_id: 'org1', + organization_slug: 'org1', + status: 'ACTIVE_HEALTHY', + created_at: new Date().toISOString(), + region: 'us-east-1', + }, + ]; + + const app = new Hono().get('/v1/projects', (c) => c.json(projects)); + + const platform = createSupabaseApiPlatform({ + accessToken: 'test-token', + fetch: app.fetch.bind(app), + }); + + if (!platform.account) { + throw new Error('account should be defined on the API platform'); + } + + const result = await platform.account.listProjects(); + expect(result).toHaveLength(1); + expect(result[0]?.name).toBe('Test Project'); + }); +}); diff --git a/packages/mcp-server-supabase/src/platform/api-platform.ts b/packages/mcp-server-supabase/src/platform/api-platform.ts index fef901c..a6f849b 100644 --- a/packages/mcp-server-supabase/src/platform/api-platform.ts +++ b/packages/mcp-server-supabase/src/platform/api-platform.ts @@ -57,6 +57,12 @@ export type SupabaseApiPlatformOptions = { * The API URL for the Supabase Management API. */ apiUrl?: string; + + /** + * Custom fetch implementation. Useful for in-process transports (e.g. a + * Hono app's `app.fetch`) so callers can avoid binding a real TCP port. + */ + fetch?: (request: Request) => Response | Promise; }; /** @@ -65,13 +71,15 @@ export type SupabaseApiPlatformOptions = { export function createSupabaseApiPlatform( options: SupabaseApiPlatformOptions ): SupabasePlatform { - const { accessToken, apiUrl } = options; + const { accessToken, apiUrl, fetch } = options; const managementApiUrl = apiUrl ?? 'https://api.supabase.com'; let managementApiClient = createManagementApiClient( managementApiUrl, - accessToken + accessToken, + {}, + fetch ); const account: AccountOperations = { @@ -788,7 +796,8 @@ export function createSupabaseApiPlatform( accessToken, { 'User-Agent': `supabase-mcp/${version} (${clientInfo.name}/${clientInfo.version})`, - } + }, + fetch ); }, account, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b6d9d91..a373ecb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -130,6 +130,9 @@ importers: dotenv: specifier: ^16.5.0 version: 16.6.1 + hono: + specifier: ^4.7.10 + version: 4.11.3 msw: specifier: ^2.7.3 version: 2.10.5(@types/node@22.17.2)(typescript@5.9.2)