feat(self-hosted): implement queryLogs for the MCP debugging tools (#48900)

> [!IMPORTANT]  
>
> Only merge this when (https://github.com/supabase/platform/pull/36804)
is merged, as the AI assistant will not have access to the `query_logs`
tool for the remote MCP server

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature (self-hosted / CLI Studio MCP server).

## What is the current behavior?

Self-hosted `getDebuggingOperations`
(`apps/studio/lib/api/self-hosted/mcp.ts`) implements only `getLogs`, so
the MCP `debugging` group exposes `get_logs` — a fixed per-service log
dump built by `getLogQuery`. Logs are served by Logflare, which speaks
BigQuery SQL.

## What is the new behavior?

Bumps `@supabase/mcp-server-supabase` to `^0.10.0` (adds `query_logs` +
`logsDialect`, and hides `get_logs` wherever a platform declares
`queryLogs`) and moves logs over to it.

- **Self-hosted `query_logs`:** declares `logsDialect: 'bigquery'` and
implements `queryLogs`, passing the model's SQL straight through to the
same Logflare `logs.all` endpoint (arbitrary `sql` param) — no new
endpoint, no dialect translation.
- **Drops `get_logs` from self-hosted:** `getLogs` throws (the server
hides it once `queryLogs` exists) and the per-service `getLogQuery`
builder is deleted; the model now writes its own BigQuery SQL, guided by
the dialect schema hint.
- **Honors no-logs mode:** `query_logs` throws when `logs:all` is
disabled — the self-hosted default, enabled via the
`docker-compose.logs.yml` override.
- **Assistant:** switches the dashboard assistant from `get_logs` to
`query_logs` (allowlist, drift guard, prompt, mocks, evals).

Refs AI-1046


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * AI debugging can query recent project logs using read-only SQL.
* Log queries support optional time-range filters, filtering,
aggregation, and joins.
* Self-hosted debugging checks whether logging is enabled before running
queries.

* **Bug Fixes**
* Updated debugging workflows and validation to consistently use the new
log-query capability.
* Removed reliance on legacy service-specific log filtering and query
behavior.

* **Documentation**
* Updated MCP debugging tool guidance to describe SQL-based log queries.

* **Tests**
* Expanded coverage for enabled, disabled, and unsupported logging
scenarios.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pedro RodriguesandClaude Opus 4.8 authored and GitHub committed 2026-08-12 13:11:23 +01:00
1 parent b5462a9609
commit 47595f8ac7
14 files changed
+134 -157

No files matched your search

+1 -1
View File
@@ -56,7 +56,7 @@ The Supabase MCP server provides tools organized into feature groups. All groups
### Debugging
- `get_logs` - Retrieve service logs (API, Postgres, Edge Functions, Auth, Storage, Realtime)
- `query_logs` - Run a read-only SQL query against project logs to filter, aggregate, or join across log fields
- `get_advisors` - Get security and performance advisors
### Development
+1 -1
View File
@@ -11,7 +11,7 @@ export const dataset: AssistantEvalCase[] = [
prompt: 'Check if my project is having issues right now and tell me what to fix first.',
},
expected: {
requiredTools: ['get_advisors', 'get_logs'],
requiredTools: ['get_advisors', 'query_logs'],
},
metadata: { category: ['debugging', 'rls_policies'] },
},
+1 -1
View File
@@ -741,7 +741,7 @@ export const CHAT_PROMPT = `
- Use \`deploy_edge_function\` solely for deployment, not for presenting example code.
## Project Health Checks
- Use \`get_advisors\` to identify project issues; if unavailable, suggest the user use the Supabase dashboard.
- Use \`get_logs\` to access recent project logs.
- Use \`query_logs\` to access recent project logs by running a read-only SQL query against them.
## Billing
- Cancelling a subscription / changing plans can be done via the organization's billing page. Link directly to https://supabase.com/dashboard/org/_/billing.
- To check organization usage, use the organization's usage page. Link directly to https://supabase.com/dashboard/org/_/usage.
+10 -10
View File
@@ -34,7 +34,7 @@ describe('tool allowance by opt-in level', () => {
list_policies: { execute: vitest.fn().mockResolvedValue({ status: 'success' }) },
// Log tools
get_advisors: { execute: vitest.fn().mockResolvedValue({ status: 'success' }) },
get_logs: { execute: vitest.fn().mockResolvedValue({ status: 'success' }) },
query_logs: { execute: vitest.fn().mockResolvedValue({ status: 'success' }) },
} as unknown as ToolSet
const filtered = filterToolsByOptInLevel(mockTools, optInLevel as any)
@@ -61,7 +61,7 @@ describe('tool allowance by opt-in level', () => {
expect(tools).not.toContain('list_extensions')
expect(tools).not.toContain('list_edge_functions')
expect(tools).not.toContain('list_branches')
expect(tools).not.toContain('get_logs')
expect(tools).not.toContain('query_logs')
expect(tools).not.toContain('get_advisors')
})
@@ -77,7 +77,7 @@ describe('tool allowance by opt-in level', () => {
expect(tools).toContain('list_policies')
expect(tools).toContain('search_docs')
expect(tools).not.toContain('get_advisors')
expect(tools).not.toContain('get_logs')
expect(tools).not.toContain('query_logs')
})
it('should return UI, schema and log tools for schema_and_log opt-in level', () => {
@@ -92,7 +92,7 @@ describe('tool allowance by opt-in level', () => {
expect(tools).toContain('list_policies')
expect(tools).toContain('search_docs')
expect(tools).toContain('get_advisors')
expect(tools).toContain('get_logs')
expect(tools).toContain('query_logs')
})
it('should return all tools for schema_and_log_and_data opt-in level', () => {
@@ -107,7 +107,7 @@ describe('tool allowance by opt-in level', () => {
expect(tools).toContain('list_policies')
expect(tools).toContain('search_docs')
expect(tools).toContain('get_advisors')
expect(tools).toContain('get_logs')
expect(tools).toContain('query_logs')
})
})
@@ -126,7 +126,7 @@ describe('filterToolsByOptInLevel', () => {
search_docs: { execute: vitest.fn().mockResolvedValue({ status: 'success' }) },
// Log tools
get_advisors: { execute: vitest.fn().mockResolvedValue({ status: 'success' }) },
get_logs: { execute: vitest.fn().mockResolvedValue({ status: 'success' }) },
query_logs: { execute: vitest.fn().mockResolvedValue({ status: 'success' }) },
// Unknown tool - should be filtered out entirely
some_other_tool: { execute: vitest.fn().mockResolvedValue({ status: 'success' }) },
} as unknown as ToolSet
@@ -182,7 +182,7 @@ describe('filterToolsByOptInLevel', () => {
'list_branches',
'list_policies',
'get_advisors',
'get_logs',
'query_logs',
])
})
@@ -196,14 +196,14 @@ describe('filterToolsByOptInLevel', () => {
'list_branches',
'list_policies',
'get_advisors',
'get_logs',
'query_logs',
])
})
it('should stub log tools for schema opt-in level', async () => {
const tools = filterToolsByOptInLevel(mockTools, 'schema')
await expectStubsFor(tools, ['get_advisors', 'get_logs'])
await expectStubsFor(tools, ['get_advisors', 'query_logs'])
})
// No execute_sql tool, so nothing additional to stub for schema_and_log opt-in level
@@ -276,7 +276,7 @@ describe('toolSetValidationSchema', () => {
execute_sql: { inputSchema: z.object({}), execute: vitest.fn() },
deploy_edge_function: { inputSchema: z.object({}), execute: vitest.fn() },
rename_chat: { inputSchema: z.object({}), execute: vitest.fn() },
get_logs: { inputSchema: z.object({}), execute: vitest.fn() },
query_logs: { inputSchema: z.object({}), execute: vitest.fn() },
}
const validationResult = toolSetValidationSchema.safeParse(allExpectedTools)
+2 -2
View File
@@ -26,7 +26,7 @@ export const toolSetValidationSchema = z.record(
'list_branches',
'search_docs',
'get_advisors',
'get_logs',
'query_logs',
// Local tools
'execute_sql',
@@ -101,7 +101,7 @@ export const TOOL_CATEGORY_MAP: Record<string, ToolCategory> = {
// Log tools - MCP and local
get_advisors: TOOL_CATEGORIES.LOG,
get_logs: TOOL_CATEGORIES.LOG,
query_logs: TOOL_CATEGORIES.LOG,
}
/**
+2 -2
View File
@@ -24,7 +24,7 @@ const FULL_REMOTE_TOOLS = {
list_edge_functions: { description: 'edge functions' },
list_branches: { description: 'branches' },
get_advisors: { description: 'advisors' },
get_logs: { description: 'get logs' },
query_logs: { description: 'query logs' },
execute_sql: { description: 'execute sql' },
deploy_edge_function: { description: 'deploy' },
}
@@ -53,7 +53,7 @@ describe('ai/tools/mcp-tools getMcpTools', () => {
const result = await getMcpTools(BASE_PARAMS)
expect(result).toHaveProperty('list_tables')
expect(result).toHaveProperty('get_logs')
expect(result).toHaveProperty('query_logs')
expect(result).not.toHaveProperty('execute_sql')
expect(result).not.toHaveProperty('deploy_edge_function')
})
+1 -1
View File
@@ -34,7 +34,7 @@ const EXPECTED_MCP_TOOLS = [
'list_edge_functions',
'list_branches',
'get_advisors',
'get_logs',
'query_logs',
] as const satisfies readonly SupabaseMcpToolName[]
export const getMcpTools = async ({
+1 -1
View File
@@ -31,7 +31,7 @@ describe('ai/tools/mock-tools getMockTools', () => {
expect(result).toHaveProperty('search_docs', SEARCH_DOCS)
// A couple of the deterministic mocks, to confirm the merge
expect(result).toHaveProperty('list_tables')
expect(result).toHaveProperty('get_logs')
expect(result).toHaveProperty('query_logs')
})
// This is the regression guard: if the eval's MCP wiring breaks (contract
+11 -39
View File
@@ -13,11 +13,10 @@ const getAdvisorsInputSchema = z.object({
type: z.enum(['security', 'performance']).optional(),
})
const getLogsInputSchema = z.object({
limit: z.number().min(1).max(100).optional(),
level: z.enum(['debug', 'info', 'warning', 'error']).optional(),
source: z.enum(['postgres', 'auth', 'storage', 'edge_function']).optional(),
search: z.string().optional(),
const queryLogsInputSchema = z.object({
sql: z.string().min(1),
iso_timestamp_start: z.string().optional(),
iso_timestamp_end: z.string().optional(),
})
const listPoliciesInputSchema = z.object({
@@ -218,40 +217,13 @@ function createMockGetAdvisorsTool() {
})
}
function createMockGetLogsTool() {
function createMockQueryLogsTool() {
return tool({
description: 'Fetches recent project logs for debugging or health checks (mocked).',
inputSchema: getLogsInputSchema,
execute: async ({
limit = 10,
level,
source,
search,
}: {
limit?: number
level?: 'debug' | 'info' | 'warning' | 'error'
source?: 'postgres' | 'auth' | 'storage' | 'edge_function'
search?: string
}) => {
let filtered = MOCK_LOGS_DATA
if (level) {
filtered = filtered.filter((entry) => entry.level === level)
}
if (source) {
filtered = filtered.filter((entry) => entry.source === source)
}
if (search) {
const needle = search.toLowerCase()
filtered = filtered.filter((entry) =>
`${entry.message} ${entry.target}`.toLowerCase().includes(needle)
)
}
return filtered.slice(0, limit)
},
description:
'Runs a read-only SQL query against recent project logs for debugging or health checks (mocked).',
inputSchema: queryLogsInputSchema,
// Deterministic mock: returns static log data regardless of the SQL passed.
execute: async () => MOCK_LOGS_DATA,
})
}
@@ -335,7 +307,7 @@ export async function getMockTools(overrides: MockToolOverrides | undefined, sig
list_extensions: createMockListExtensionsTool(),
list_edge_functions: createMockListEdgeFunctionsTool(),
get_advisors: createMockGetAdvisorsTool(),
get_logs: createMockGetLogsTool(),
query_logs: createMockQueryLogsTool(),
list_policies: createMockListPoliciesTool(),
}
}
-66
View File
@@ -1,6 +1,4 @@
import assert from 'node:assert'
import { LogsService } from '@supabase/mcp-server-supabase/platform'
import { stripIndent } from 'common-tags'
import { WrappedResult } from './types'
import { assertSelfHosted } from './util'
@@ -71,67 +69,3 @@ export async function retrieveAnalyticsData({
throw error
}
}
export function getLogQuery(service: LogsService, limit: number = 100): string {
assertSelfHosted()
switch (service) {
case 'api': {
return stripIndent`
select id, edge_logs.timestamp, event_message, request.method, request.path, request.search, response.status_code
from edge_logs
cross join unnest(metadata) as m
cross join unnest(m.request) as request
cross join unnest(m.response) as response
order by timestamp desc
limit ${limit};
`
}
case 'branch-action': {
throw new Error('Branching is only supported in the hosted Supabase platform')
}
case 'postgres': {
return stripIndent`
select postgres_logs.timestamp, id, event_message, parsed.error_severity, parsed.detail, parsed.hint
from postgres_logs
cross join unnest(metadata) as m
cross join unnest(m.parsed) as parsed
order by timestamp desc
limit ${limit};
`
}
case 'edge-function': {
return stripIndent`
select id, function_edge_logs.timestamp, event_message
from function_edge_logs
order by timestamp desc
limit ${limit}
`
}
case 'auth': {
return stripIndent`
select id, auth_logs.timestamp, event_message, metadata.level, metadata.status, metadata.path, metadata.msg as msg, metadata.error from auth_logs
cross join unnest(metadata) as metadata
order by timestamp desc
limit ${limit};
`
}
case 'storage': {
return stripIndent`
select id, storage_logs.timestamp, event_message from storage_logs
order by timestamp desc
limit ${limit};
`
}
case 'realtime': {
return stripIndent`
select id, realtime_logs.timestamp, event_message from realtime_logs
order by timestamp desc
limit ${limit};
`
}
default: {
throw new Error(`Unsupported log service: ${service}`)
}
}
}
+60 -1
View File
@@ -1,6 +1,6 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { getDevelopmentOperations } from './mcp'
import { getDebuggingOperations, getDevelopmentOperations } from './mcp'
vi.mock('./settings', () => ({
getProjectSettings: vi.fn(),
@@ -10,6 +10,14 @@ vi.mock('./generate-types', () => ({
generateTypescriptTypes: vi.fn(),
}))
vi.mock('./logs', () => ({
retrieveAnalyticsData: vi.fn(),
}))
vi.mock('./lints', () => ({
getLints: vi.fn(),
}))
describe('api/self-hosted/mcp', () => {
describe('getDevelopmentOperations.getPublishableKeys', () => {
let getProjectSettingsMock: ReturnType<typeof vi.fn>
@@ -78,4 +86,55 @@ describe('api/self-hosted/mcp', () => {
)
})
})
describe('getDebuggingOperations', () => {
let retrieveAnalyticsDataMock: ReturnType<typeof vi.fn>
beforeEach(async () => {
vi.clearAllMocks()
vi.unstubAllEnvs()
const logs = await import('./logs')
retrieveAnalyticsDataMock = vi.mocked(logs.retrieveAnalyticsData)
})
afterEach(() => {
vi.unstubAllEnvs()
})
it('getLogs is not supported on self-hosted (query_logs supersedes it)', async () => {
const ops = getDebuggingOperations({})
// `get_logs` is hidden by the MCP server whenever `queryLogs` is present,
// so this method is unreachable over MCP and throws defensively.
await expect(ops.getLogs('default', { service: 'api' })).rejects.toThrow(
'get_logs is not supported on self-hosted'
)
expect(retrieveAnalyticsDataMock).not.toHaveBeenCalled()
})
it('queryLogs throws when logs are disabled (self-hosted default)', async () => {
vi.stubEnv('ENABLED_FEATURES_LOGS_ALL', 'false')
const ops = getDebuggingOperations({})
await expect(ops.queryLogs!('default', { sql: 'select 1' })).rejects.toThrow(
'Logs are disabled on this instance'
)
expect(retrieveAnalyticsDataMock).not.toHaveBeenCalled()
})
it('queryLogs passes the model-provided SQL straight through when logs are enabled', async () => {
vi.stubEnv('ENABLED_FEATURES_LOGS_ALL', 'true')
retrieveAnalyticsDataMock.mockResolvedValue({ data: ['log entry'], error: null })
const ops = getDebuggingOperations({})
await ops.queryLogs!('default', { sql: 'select * from edge_logs' })
expect(retrieveAnalyticsDataMock).toHaveBeenCalledWith(
expect.objectContaining({
params: expect.objectContaining({ sql: 'select * from edge_logs' }),
})
)
})
})
})
+31 -5
View File
@@ -6,13 +6,15 @@ import {
DebuggingOperations,
DevelopmentOperations,
ExecuteSqlOptions,
GetLogsOptions,
QueryLogsOptions,
} from '@supabase/mcp-server-supabase/platform'
import { isFeatureEnabled, type Feature } from 'common/enabled-features'
import { getEnabledFeaturesOverrideDisabledList } from 'common/enabled-features/overrides'
import { DEFAULT_EXPOSED_SCHEMAS } from './constants'
import { generateTypescriptTypes } from './generate-types'
import { getLints } from './lints'
import { getLogQuery, retrieveAnalyticsData } from './logs'
import { retrieveAnalyticsData } from './logs'
import { applyAndTrackMigrations, listMigrationVersions } from './migrations'
import { executeQuery } from './query'
import { getProjectSettings } from './settings'
@@ -113,18 +115,42 @@ export function getDevelopmentOperations({
}
}
// Logs are disabled by default for self-hosted; enabled via the
// `docker-compose.logs.yml` override, which sets ENABLED_FEATURES_LOGS_ALL=true.
function assertLogsEnabled() {
const disabledFeatures = getEnabledFeaturesOverrideDisabledList(process.env) as Feature[]
if (!isFeatureEnabled('logs:all', disabledFeatures)) {
throw new Error(
'Logs are disabled on this instance. Enable the `docker-compose.logs.yml` override to query logs.'
)
}
}
export function getDebuggingOperations({
headers,
}: GetDebuggingOperationsOptions): DebuggingOperations {
return {
async getLogs(projectRef: string, options: GetLogsOptions) {
const sql = getLogQuery(options.service)
// Self-hosted logs are served by Logflare, which speaks BigQuery SQL.
logsDialect: 'bigquery',
// `query_logs` replaces `get_logs` on self-hosted. Declaring `queryLogs`
// makes the MCP server hide `get_logs` from clients (see `getDebuggingTools`
// in @supabase/mcp-server-supabase), so this method is never reached over
// MCP. The `DebuggingOperations` interface still requires it, so it throws
// defensively rather than serving logs.
async getLogs() {
throw new Error('get_logs is not supported on self-hosted; use query_logs instead.')
},
async queryLogs(projectRef: string, options: QueryLogsOptions) {
assertLogsEnabled()
// Pass the model's SQL straight through to the Logflare `logs.all`
// endpoint, which accepts an arbitrary `sql` param.
const { data, error } = await retrieveAnalyticsData({
name: 'logs.all',
projectRef,
params: {
sql,
sql: options.sql,
iso_timestamp_start: options.iso_timestamp_start,
iso_timestamp_end: options.iso_timestamp_end,
},
+1 -1
View File
@@ -72,7 +72,7 @@
"@stripe/stripe-js": "9.1.0",
"@stripe/sync-engine": "1.0.32",
"@supabase/auth-js": "catalog:",
"@supabase/mcp-server-supabase": "^0.7.0",
"@supabase/mcp-server-supabase": "^0.10.0",
"@supabase/pg-meta": "workspace:*",
"@supabase/realtime-js": "catalog:",
"@supabase/shared-types": "0.1.91",
+12 -26
View File
@@ -985,8 +985,8 @@ importers:
specifier: 'catalog:'
version: 2.112.3
'@supabase/mcp-server-supabase':
specifier: ^0.7.0
version: 0.7.0(@modelcontextprotocol/sdk@1.29.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)
specifier: ^0.10.0
version: 0.10.0(@modelcontextprotocol/sdk@1.29.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)
'@supabase/pg-meta':
specifier: workspace:*
version: link:../../packages/pg-meta
@@ -3864,10 +3864,6 @@ packages:
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
'@eslint-community/regexpp@4.12.1':
resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
'@eslint-community/regexpp@4.12.2':
resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
@@ -7719,15 +7715,15 @@ packages:
resolution: {integrity: sha512-gfv481mTOVWtZIJgXupxZpni2V2UWPf6jeF/jOK7HdMHdH+mt6sU0sHHwf0POsPip8ltlulu9OUHgwVzl5ddRw==}
engines: {node: '>=22.0.0'}
'@supabase/mcp-server-supabase@0.7.0':
resolution: {integrity: sha512-t0sOS27T5mDxp6jUYSh3zuyjWhYZarbXCPUO7HTVSyPq2smY6d5UM4Lko81eawYCSRDE8qwDZOKnVkXwCS4RSg==}
'@supabase/mcp-server-supabase@0.10.0':
resolution: {integrity: sha512-CVnB+4wBFsQeYwr5phNZyG33nNPUVBAJFB99vn55Z5Zn5+sxopybBPeYtrz8J9rqLkXad/xb7Xow4sz0JMq/XQ==}
hasBin: true
peerDependencies:
'@modelcontextprotocol/sdk': ^1.25.2
zod: ^3.25.0 || ^4.0.0
'@supabase/mcp-utils@0.4.0':
resolution: {integrity: sha512-mJ06GYLLZGW4zfz4yl08P2wrx0ORqW5iIAFyqvWJAInIjoa3w7EfJs/h+RbvCE+x7UYuSQeDUXpLJc4lJWDBKA==}
'@supabase/mcp-utils@0.6.0':
resolution: {integrity: sha512-4r7RTEMZgFw4VqTgsQrM0KUWXdEOASPHEjIfuBaGb0SXPHIIe6W8xBnocidjtfQnKagxMJb0RXY4rqwwShJ2zw==}
peerDependencies:
'@modelcontextprotocol/sdk': ^1.25.2
zod: ^3.25.0 || ^4.0.0
@@ -11303,10 +11299,6 @@ packages:
engines: {node: '>=4'}
hasBin: true
esquery@1.5.0:
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
engines: {node: '>=0.10'}
esquery@1.7.0:
resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
engines: {node: '>=0.10'}
@@ -19382,8 +19374,6 @@ snapshots:
eslint: 9.37.0(jiti@2.7.0)(supports-color@8.1.1)
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.1': {}
'@eslint-community/regexpp@4.12.2': {}
'@eslint/compat@2.1.0(eslint@9.37.0(jiti@2.7.0)(supports-color@8.1.1))':
@@ -23731,18 +23721,18 @@ snapshots:
dependencies:
tslib: 2.8.1
'@supabase/mcp-server-supabase@0.7.0(@modelcontextprotocol/sdk@1.29.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)':
'@supabase/mcp-server-supabase@0.10.0(@modelcontextprotocol/sdk@1.29.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)':
dependencies:
'@mjackson/multipart-parser': 0.10.1
'@modelcontextprotocol/sdk': 1.29.0(supports-color@8.1.1)(zod@3.25.76)
'@supabase/mcp-utils': 0.4.0(@modelcontextprotocol/sdk@1.29.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)
'@supabase/mcp-utils': 0.6.0(@modelcontextprotocol/sdk@1.29.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)
common-tags: 1.8.2
gqlmin: 0.3.1
graphql: 16.11.0
openapi-fetch: 0.13.8
zod: 3.25.76
'@supabase/mcp-utils@0.4.0(@modelcontextprotocol/sdk@1.29.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)':
'@supabase/mcp-utils@0.6.0(@modelcontextprotocol/sdk@1.29.0(supports-color@8.1.1)(zod@3.25.76))(zod@3.25.76)':
dependencies:
'@modelcontextprotocol/sdk': 1.29.0(supports-color@8.1.1)(zod@3.25.76)
zod: 3.25.76
@@ -27722,8 +27712,8 @@ snapshots:
eslint@9.37.0(jiti@2.7.0)(supports-color@8.1.1):
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.37.0(jiti@2.7.0)(supports-color@8.1.1))
'@eslint-community/regexpp': 4.12.1
'@eslint-community/eslint-utils': 4.10.1(eslint@9.37.0(jiti@2.7.0)(supports-color@8.1.1))
'@eslint-community/regexpp': 4.12.2
'@eslint/config-array': 0.21.0(supports-color@8.1.1)
'@eslint/config-helpers': 0.4.0
'@eslint/core': 0.16.0
@@ -27743,7 +27733,7 @@ snapshots:
eslint-scope: 8.4.0
eslint-visitor-keys: 4.2.1
espree: 10.4.0
esquery: 1.5.0
esquery: 1.7.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 8.0.0
@@ -27777,10 +27767,6 @@ snapshots:
esprima@4.0.1: {}
esquery@1.5.0:
dependencies:
estraverse: 5.3.0
esquery@1.7.0:
dependencies:
estraverse: 5.3.0