From cc1480eb98cdfe12c133e19253186ffe1f3bd3f2 Mon Sep 17 00:00:00 2001 From: ahfoysal Date: Tue, 7 Jul 2026 17:16:12 +0600 Subject: [PATCH] fix: page advisor lint results --- .../mcp-server-supabase/src/server.test.ts | 40 +++++++++++++++++ .../src/tools/debugging-tools.ts | 45 ++++++++++++++++++- packages/mcp-server-supabase/test/mocks.ts | 6 ++- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/packages/mcp-server-supabase/src/server.test.ts b/packages/mcp-server-supabase/src/server.test.ts index 97dda899..61367d41 100644 --- a/packages/mcp-server-supabase/src/server.test.ts +++ b/packages/mcp-server-supabase/src/server.test.ts @@ -1473,6 +1473,46 @@ describe('tools', () => { expect(result).toEqual({ lints: [] }); }); + test('get advisors supports paging large lint results', async () => { + const { callTool } = await setup(); + + const org = await createOrganization({ + name: 'My Org', + plan: 'free', + allowed_release_channels: ['ga'], + }); + + const project = await createProject({ + name: 'Project 1', + region: 'us-east-1', + organization_id: org.id, + }); + project.status = 'ACTIVE_HEALTHY'; + project.security_advisors = Array.from({ length: 5 }, (_, index) => ({ + name: `lint_${index}`, + })); + + const { result } = await callTool({ + name: 'get_advisors', + arguments: { + project_id: project.id, + type: 'security', + limit: 2, + offset: 1, + }, + }); + + expect(result).toEqual({ + lints: [{ name: 'lint_1' }, { name: 'lint_2' }], + pagination: { + total: 5, + offset: 1, + limit: 2, + next_offset: 3, + }, + }); + }); + test('get performance advisors', async () => { const { callTool } = await setup(); diff --git a/packages/mcp-server-supabase/src/tools/debugging-tools.ts b/packages/mcp-server-supabase/src/tools/debugging-tools.ts index ac0b142a..0929fae2 100644 --- a/packages/mcp-server-supabase/src/tools/debugging-tools.ts +++ b/packages/mcp-server-supabase/src/tools/debugging-tools.ts @@ -24,12 +24,53 @@ const getAdvisorsInputSchema = z.object({ type: z .enum(['security', 'performance']) .describe('The type of advisors to fetch'), + limit: z + .number() + .int() + .positive() + .optional() + .describe('Maximum number of advisor notices to return.'), + offset: z + .number() + .int() + .nonnegative() + .optional() + .describe('Number of advisor notices to skip before returning results.'), }); const getAdvisorsOutputSchema = z.object({ result: z.unknown(), }); +function paginateAdvisorResult(result: unknown, limit?: number, offset = 0) { + if (limit === undefined && offset === 0) return result; + + if ( + !result || + typeof result !== 'object' || + !('lints' in result) || + !Array.isArray(result.lints) + ) { + return result; + } + + const total = result.lints.length; + const lints = result.lints.slice(offset, limit ? offset + limit : undefined); + const next_offset = + limit !== undefined && offset + limit < total ? offset + limit : undefined; + + return { + ...result, + lints, + pagination: { + total, + offset, + limit: limit ?? total - offset, + ...(next_offset !== undefined && { next_offset }), + }, + }; +} + export const debuggingToolDefs = { get_logs: { description: @@ -84,7 +125,7 @@ export function getDebuggingTools({ get_advisors: injectableTool({ ...debuggingToolDefs.get_advisors, inject: { project_id }, - execute: async ({ project_id, type }) => { + execute: async ({ project_id, type, limit, offset }) => { let result: unknown; switch (type) { case 'security': @@ -96,7 +137,7 @@ export function getDebuggingTools({ default: throw new Error(`Unknown advisor type: ${type}`); } - return { result }; + return { result: paginateAdvisorResult(result, limit, offset) }; }, }), }; diff --git a/packages/mcp-server-supabase/test/mocks.ts b/packages/mcp-server-supabase/test/mocks.ts index 6645b648..b1da602d 100644 --- a/packages/mcp-server-supabase/test/mocks.ts +++ b/packages/mcp-server-supabase/test/mocks.ts @@ -586,7 +586,7 @@ export const mockManagementApi = [ } return HttpResponse.json({ - lints: [], + lints: project.security_advisors, }); } ), @@ -606,7 +606,7 @@ export const mockManagementApi = [ } return HttpResponse.json({ - lints: [], + lints: project.performance_advisors, }); } ), @@ -1178,6 +1178,8 @@ export class MockProject { migrations: Migration[] = []; edge_functions = new Map(); storage_buckets = new Map(); + security_advisors: unknown[] = []; + performance_advisors: unknown[] = []; #db?: PGliteInterface;