From 01d6be63930f2b1c1ed374ba58fe83682ef8b1b4 Mon Sep 17 00:00:00 2001 From: ahfoysal Date: Tue, 7 Jul 2026 12:49:25 +0600 Subject: [PATCH 1/2] fix: normalize debug feature alias in tool schemas --- .../src/tools/tool-schemas.test.ts | 15 +++++++++++++++ .../mcp-server-supabase/src/tools/tool-schemas.ts | 10 ++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server-supabase/src/tools/tool-schemas.test.ts b/packages/mcp-server-supabase/src/tools/tool-schemas.test.ts index 1f70e66c..cd147f1d 100644 --- a/packages/mcp-server-supabase/src/tools/tool-schemas.test.ts +++ b/packages/mcp-server-supabase/src/tools/tool-schemas.test.ts @@ -51,6 +51,21 @@ describe('createToolSchemas', () => { expectTypeOf(schemas).toHaveProperty('search_docs'); expectTypeOf(schemas).not.toHaveProperty('execute_sql'); }); + + test('normalizes deprecated feature names', () => { + const deprecatedSchemas = createToolSchemas({ + features: ['debug'] as any, + }); + const currentSchemas = createToolSchemas({ features: ['debugging'] }); + + expect(Object.keys(deprecatedSchemas).sort()).toEqual( + Object.keys(currentSchemas).sort() + ); + expect(Object.keys(deprecatedSchemas).sort()).toEqual([ + 'get_advisors', + 'get_logs', + ]); + }); }); describe('PROJECT_SCOPED_OVERRIDES completeness', () => { diff --git a/packages/mcp-server-supabase/src/tools/tool-schemas.ts b/packages/mcp-server-supabase/src/tools/tool-schemas.ts index 06268911..f437d478 100644 --- a/packages/mcp-server-supabase/src/tools/tool-schemas.ts +++ b/packages/mcp-server-supabase/src/tools/tool-schemas.ts @@ -1,5 +1,9 @@ import type { z } from 'zod/v4'; -import { CURRENT_FEATURE_GROUPS, type FeatureGroup } from '../types.js'; +import { + CURRENT_FEATURE_GROUPS, + featureGroupSchema, + type FeatureGroup, +} from '../types.js'; import { accountToolDefs } from './account-tools.js'; import { branchingToolDefs } from './branching-tools.js'; import { databaseToolDefs } from './database-operation-tools.js'; @@ -247,7 +251,9 @@ export function createToolSchemas< readOnly?: ReadOnly; }): ToolSchemasFor { const enabledFeatures = new Set( - options?.features ?? CURRENT_FEATURE_GROUPS + (options?.features ?? CURRENT_FEATURE_GROUPS).map((feature) => + featureGroupSchema.parse(feature) + ) ); const projectScoped = options?.projectScoped ?? false; const readOnly = options?.readOnly ?? false; From b3a581e39fe2c079532fb932a95c21993c33b157 Mon Sep 17 00:00:00 2001 From: ahfoysal Date: Tue, 7 Jul 2026 14:21:04 +0600 Subject: [PATCH 2/2] fix: hide mutating stdio tools in read-only mode --- packages/mcp-server-supabase/src/server.ts | 45 +++++++++++++------ .../test/stdio.integration.ts | 15 +++++++ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/packages/mcp-server-supabase/src/server.ts b/packages/mcp-server-supabase/src/server.ts index 02128e3f..d85cb071 100644 --- a/packages/mcp-server-supabase/src/server.ts +++ b/packages/mcp-server-supabase/src/server.ts @@ -136,6 +136,14 @@ export function createSupabaseMcpServer(options: SupabaseMcpServerOptions) { tools: async () => { const contentApiClient = await contentApiClientPromise; const tools: Record = {}; + const addTools = (next: Record) => + Object.entries(next).forEach(([name, tool]) => { + if (readOnly && tool.annotations?.readOnlyHint === false) { + return; + } + + tools[name] = tool; + }); const { account, @@ -148,16 +156,15 @@ export function createSupabaseMcpServer(options: SupabaseMcpServerOptions) { } = platform; if (enabledFeatures.has('docs')) { - Object.assign(tools, getDocsTools({ contentApiClient })); + addTools(getDocsTools({ contentApiClient })); } if (!projectId && account && enabledFeatures.has('account')) { - Object.assign(tools, getAccountTools({ account, readOnly })); + addTools(getAccountTools({ account, readOnly })); } if (database && enabledFeatures.has('database')) { - Object.assign( - tools, + addTools( getDatabaseTools({ database, projectId, @@ -167,29 +174,41 @@ export function createSupabaseMcpServer(options: SupabaseMcpServerOptions) { } if (debugging && enabledFeatures.has('debugging')) { - Object.assign(tools, getDebuggingTools({ debugging, projectId })); + addTools(getDebuggingTools({ debugging, projectId })); } if (development && enabledFeatures.has('development')) { - Object.assign(tools, getDevelopmentTools({ development, projectId })); + addTools(getDevelopmentTools({ development, projectId })); } if (functions && enabledFeatures.has('functions')) { - Object.assign( - tools, - getEdgeFunctionTools({ functions, projectId, readOnly }) + addTools( + getEdgeFunctionTools({ + functions, + projectId, + readOnly, + }) ); } if (branching && enabledFeatures.has('branching')) { - Object.assign( - tools, - getBranchingTools({ branching, projectId, readOnly }) + addTools( + getBranchingTools({ + branching, + projectId, + readOnly, + }) ); } if (storage && enabledFeatures.has('storage')) { - Object.assign(tools, getStorageTools({ storage, projectId, readOnly })); + addTools( + getStorageTools({ + storage, + projectId, + readOnly, + }) + ); } return tools; diff --git a/packages/mcp-server-supabase/test/stdio.integration.ts b/packages/mcp-server-supabase/test/stdio.integration.ts index 5e09d8e3..0ae85eec 100644 --- a/packages/mcp-server-supabase/test/stdio.integration.ts +++ b/packages/mcp-server-supabase/test/stdio.integration.ts @@ -66,6 +66,21 @@ describe('stdio', () => { expect(tools.length).toBeGreaterThan(0); }); + test('read-only mode filters mutating tools from tool list', async () => { + const { client } = await setup({ readOnly: true }); + + const { tools } = await client.listTools(); + const toolNames = new Set(tools.map((tool) => tool.name)); + + expect(toolNames.has('apply_migration')).toBe(false); + expect(toolNames.has('deploy_edge_function')).toBe(false); + expect(toolNames.has('create_branch')).toBe(false); + expect(toolNames.has('delete_branch')).toBe(false); + + expect(toolNames.has('list_tables')).toBe(true); + expect(toolNames.has('execute_sql')).toBe(true); + }); + test('missing access token fails', async () => { const setupPromise = setup({ accessToken: null as any });