Skip to content

feat!: add query_logs tool for custom log queries - #333

Merged
jordienr merged 19 commits into
supabase:mainfrom
jordienr:claude/mcp-log-query-tool-8372a9
Aug 10, 2026
Merged

feat!: add query_logs tool for custom log queries#333
jordienr merged 19 commits into
supabase:mainfrom
jordienr:claude/mcp-log-query-tool-8372a9

Conversation

@jordienr

@jordienr jordienr commented Jul 16, 2026

Copy link
Copy Markdown
Member

What

Adds a new query_logs tool to the debugging feature group. It runs a custom ClickHouse SQL query against a project's unified logs stream, for cases where the get_logs service presets are too coarse (filtering, aggregating, or joining across log fields).

Tracks AI-701. Builds on the ClickHouse logs endpoint work in O11Y-1813 and the get_logs ClickHouse migration (#326).

Breaking change

This ships as feat!: per team alignment (see PR discussion): on platforms that implement ClickHouse-backed querying (hosted/production), query_logs is the tool discoverable via tools/list, and get_logs is hidden from discovery — though it remains callable via tools/call for any client still holding an older tool list. On platforms without ClickHouse support (CLI/self-hosted), the reverse holds: get_logs stays listed and query_logs is not registered at all.

DebuggingOperations.queryLogs is optional on the SupabasePlatform type (published via the ./platform subpath export). Implementers outside this repo (CLI, studio, the hosted controller) are unaffected if they don't implement it — they simply keep get_logs as their only logs tool.

How it addresses the observability team's concerns

  1. Prompt injection / security — log content is user-controllable (same class of risk as execute_sql), so the result is wrapped in wrapWithUntrustedDataBoundary, the same best-effort guardrail execute_sql uses. Not foolproof, but consistent with the existing arbitrary-query tool.
  2. Cost / scalability — starts conservative: defaults to a 24h window, and both the client (resolveLogWindow) and the analytics endpoint cap the requested range at 24h. No unbounded queries.
  3. ClickHouse, not BigQuery — hits GET /v1/projects/{ref}/analytics/endpoints/logs (ClickHouse / logs.all.otel) and takes raw ClickHouse-dialect SQL. Does not touch the deprecated BigQuery-backed logs.all.
  4. No POST on v1 — uses GET with sql as a query param. No new POST handler.
  5. CLI / self-hostedquery_logs is only registered when the platform implements queryLogs; CLI/self-hosted platforms don't, so they keep get_logs as their only logs tool and never see query_logs at all (see Breaking change above).

Details

  • query_logs params: project_id, sql, optional iso_timestamp_start/iso_timestamp_end.
  • Timestamps are validated as ISO 8601 with an explicit UTC Z suffix or offset (z.iso.datetime({ offset: true })), so the constraint is visible in the tool's JSON schema and offset-less (ambiguous local-time) timestamps are rejected up front.
  • resolveLogWindow (shared by get_logs and query_logs) anchors the default start to 24h before the resolved end, normalizes accepted timestamps to canonical UTC ISO strings, and rejects an inverted/equal window or one exceeding 24h — unit-tested directly in debugging-tools.test.ts.
  • Read-only enforcement of the SQL itself is left to the backend; no client-side SQL parsing.
  • Tool descriptions carry no environment-specific wording (hosted/self-hosted/CLI) — routing is handled structurally via registration/hiding, not prose the model has to reason about.

Verification

  • tsc --noEmit clean, biome ci clean.
  • All unit + integration suites pass (incl. logs.test.ts, server.test.ts, debugging-tools.test.ts). The 5 failing |e2e| checks need live SUPABASE_ACCESS_TOKEN / ANTHROPIC_API_KEY, which this fork PR doesn't receive — confirmed passing on an identical-commit mirror pushed directly to the repo (feat: add query_logs tool for custom log queries (CI mirror of #333) #341).
  • Manually verified query_logs end-to-end against a real staging project (ClickHouse query executed, results returned, untrusted-data wrapping applied).
  • Eval coverage: feat(eval): query_logs tool selection on hosted-shaped platform evals#100 (draft, blocked on this shipping in a released @supabase/mcp-server-supabase version) verifies the agent successfully uses query_logs on a hosted-shaped fixture where it's the only logs tool listed.

Post-merge follow-ups

Per Rodriguespn — this adds a tool and changes get_logs's discoverability, so per CONTRIBUTING's breaking-change guidance:

  • Release a new @supabase/mcp-server-supabase version (automatic via release-please once merged as feat!:)
  • Update the tool list at supabase.com/mcp
  • Bump MCP_SERVER_VERSION in supabase/evals and un-draft evals#100
  • Open a PR on platform to add query_logs to the remote MCP server
  • Update the @supabase/mcp-server-supabase version pin inside studio
  • Resubmit the ChatGPT app to pick up the new tool and reworded get_logs description (frozen fields)

Note

Per CONTRIBUTING, feature PRs should track an accepted issue — this tracks AI-701.

@jordienr
jordienr marked this pull request as ready for review July 17, 2026 08:57
@jordienr
jordienr requested a review from a team as a code owner July 17, 2026 08:57

@barryroodt barryroodt left a comment

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.

Really clean addition, Jordi. It mirrors the merged get_logs sibling almost exactly (same endpoint, same untrusted-data wrapping, same 24h defaulting), and I reproduced the checks against the PR head: tsc --noEmit, biome ci ., and the server.test.ts + logs.test.ts suites (111 tests) all pass. Nothing here blocks merge. A couple of small things worth a look:

The sql description is missing function_edge_logs. The source list guides the model on what to filter by, and right now it lists function_logs (edge-function runtime console output) but not function_edge_logs (the invocation/request logs the get_logs edge-function preset queries, see logs.ts:37). Since that description is effectively the contract the model writes SQL against, a model following it can't reach invocation logs and will filter on the wrong source. Everything else in the list looks right.

query_logs has no execution test yet. The test change adds it to the tool-listing assertion, which is exactly right for registration, but the new timestamp-defaulting / passthrough / wrapping logic in execute is the bug-prone part and it's currently untested (whereas get_logs has three). server.test.ts:1567 is a ready-made template and the existing /endpoints/logs mock already covers it, so no new mock needed. Happy to leave this as a fast-follow if you'd rather not expand scope here.

Tiny nit: sql: z.string() could take .min(1) to match executeSqlOptionsSchema.query, so an empty query gives a clear validation message instead of an opaque backend error. Very much a nice-to-have.

None of this is load-bearing for shipping. The function_edge_logs line is the one I'd genuinely want fixed before merge; the rest are optional.

@jordienr

Copy link
Copy Markdown
Member Author

Thanks for the thorough review! Addressed all three in f37cfc5:

  • function_edge_logs missing from the sql description — added it to the source-hint list, so a model can now reach edge function invocation logs (not just function_logs runtime output).
  • No execution test for query_logs — added three, mirroring the get_logs template at server.test.ts: sql passthrough + timestamp defaulting, custom-window forwarding, and empty-query rejection.
  • sql nit — added .min(1) on both the tool schema and queryLogsOptionsSchema, matching executeSqlOptionsSchema.query.

tsc --noEmit, biome ci ., and the server.test.ts + logs.test.ts suites (114 tests) all pass.

🤖 Addressed by Claude Code

@barryroodt barryroodt left a comment

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.

Thanks for the quick turnaround @jordienr

  • function_edge_logs added to the source list
  • .min(1) on the schema
  • behavioral tests for query_logs

LGTM

@mattrossman, @Rodriguespn - since I'm still the new guy, perhaps a quick scan and thumbs-up from either of you would be advisable 😁

@mattrossman mattrossman added the publish-preview Runs `publish-preview` workflow to publish preview packages via https://pkg.pr.new/ label Jul 17, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jul 17, 2026

Copy link
Copy Markdown

Open in StackBlitz

pnpm add https://pkg.pr.new/@supabase/mcp-server-postgrest@caadd9d
pnpm add https://pkg.pr.new/@supabase/mcp-server-supabase@caadd9d
pnpm add https://pkg.pr.new/@supabase/mcp-utils@caadd9d

commit: caadd9d

Comment thread packages/mcp-server-supabase/src/platform/api-platform.ts
@Ziinc

Ziinc commented Jul 21, 2026

Copy link
Copy Markdown

on further thought, let's leave both tools and potentially deprecate and remove getLogs in favour of queryLogs.
Note that Clickhouse backed querying is only available for production, cli/self-hosted will not have it yet and we need to document that discrepancy as this will break if people try querying against cli. they should use the getLogs tool until full support is provided.

Comment thread packages/mcp-server-supabase/src/tools/debugging-tools.ts
@jordienr

Copy link
Copy Markdown
Member Author

Addressed the deprecation + platform-availability guidance in a4d7228:

  • get_logs is now marked deprecated on hosted (production) projects in favour of query_logs, while remaining the documented path for local (CLI) and self-hosted projects.
  • query_logs description now states it's hosted-only — ClickHouse-backed querying isn't available on CLI/self-hosted yet, and to use get_logs there — so a model won't try it against an unsupported project and break.

🤖 Addressed by Claude Code

@barryroodt

Copy link
Copy Markdown
Contributor

Following up with fresh numbers against the current head (ecc456d)

Rerun of our eval A/B against the new head: passed all 3 eval checks on the first attempt, and the a4d7228 deprecation note fully flipped tool selection, 8 query_logs calls and zero get_logs (previously the model mixed both). The first genuine ClickHouse aggregation (countIf(toInt32OrZero(...))) succeeded as-is. For contrast, the get_logs-only baseline on main had one run die on context length counting raw preset rows, so the deprecation direction looks well supported.

One finding: the 24 hour default still silently widens narrow questions. The eval asks about the last 15 minutes; all 8 query_logs calls in the fresh run passed no timestamps, inheriting the 24 hour window, even though the description now mentions iso_timestamp_start/iso_timestamp_end. Mentioning the window permissively isn't landing; in production that means wrong counts whenever older logs exist.

Suggestion: same mechanism as a4d7228 - make the line directive, something like "when the user asks about a specific time range, always pass iso_timestamp_start/iso_timestamp_end to match it".

Unrelated side effect: this exercise surfaced drift in our own evals fixture, fixed in supabase/evals#99.

@jordienr

Copy link
Copy Markdown
Member Author

Thanks for the fresh eval run — great to see the deprecation note flip selection cleanly, and good catch on the time-range default.

Fixed in ea6d163: the timestamp guidance is now a directive rather than a permissive mention, using the same mechanism as the deprecation line. Both query_logs and get_logs now say:

When the user asks about a specific time range, always pass iso_timestamp_start and iso_timestamp_end to match it; otherwise the query defaults to the last 24 hours and will return results from a wider window than intended.

Applied to get_logs too since it shares the identical 24h defaulting. Whenever you next rerun the A/B I'd be curious whether the 15-minute question now passes an explicit window.

🤖 Addressed by Claude Code

@barryroodt

Copy link
Copy Markdown
Contributor

Nice! Reran the A/B against ea6d163 and the directive line does exactly what we hoped: the model now passes an explicit 15 minute window matching the question on every analytical query_logs call (4 of 4), and the only windowless calls are orientation probes (a now() check and a quick sample of the data), which is the behaviour you'd want. Still 3/3 checks on the first attempt, still 100% query_logs over get_logs on hosted.

Comment thread packages/mcp-server-supabase/src/tools/debugging-tools.ts
Comment thread packages/mcp-server-supabase/src/tools/debugging-tools.ts
Comment thread packages/mcp-server-supabase/src/tools/debugging-tools.ts Outdated
Comment thread packages/mcp-server-supabase/src/tools/debugging-tools.ts Outdated
smeubank added a commit to supabase/supabase that referenced this pull request Jul 24, 2026
…s split

this committ assume we will have merged or should be merged to gether with cahnges on skills and MCP

- supabase/agent-skills#112
- supabase/mcp#333

 query_logs (hosted only, ClickHouse SQL) is now the preferred tool for
  production projects; get_logs remains the only option for local and
  self-hosted. Updates the MCP tools table, log-querying section, and skill
  step 3 in ai-agents.mdx, and the tip admonition in debugging.mdx.
  logs.mdx already had this right at line 321.
jeremenichelli pushed a commit to supabase/supabase that referenced this pull request Jul 30, 2026
…s split

this committ assume we will have merged or should be merged to gether with cahnges on skills and MCP

- supabase/agent-skills#112
- supabase/mcp#333

 query_logs (hosted only, ClickHouse SQL) is now the preferred tool for
  production projects; get_logs remains the only option for local and
  self-hosted. Updates the MCP tools table, log-querying section, and skill
  step 3 in ai-agents.mdx, and the tip admonition in debugging.mdx.
  logs.mdx already had this right at line 321.
jeremenichelli pushed a commit to supabase/supabase that referenced this pull request Jul 31, 2026
…s split

this committ assume we will have merged or should be merged to gether with cahnges on skills and MCP

- supabase/agent-skills#112
- supabase/mcp#333

 query_logs (hosted only, ClickHouse SQL) is now the preferred tool for
  production projects; get_logs remains the only option for local and
  self-hosted. Updates the MCP tools table, log-querying section, and skill
  step 3 in ai-agents.mdx, and the tip admonition in debugging.mdx.
  logs.mdx already had this right at line 321.
Adds a query_logs debugging tool that runs a custom read-only ClickHouse
SQL query against a project's unified logs stream, for cases where the
get_logs service presets are too coarse. Reuses the existing analytics
logs endpoint and validates that queries are SELECT/WITH only.
- add function_edge_logs to the sql source-hint list so models can reach
  edge function invocation logs
- require a non-empty sql query (.min(1)), matching execute_sql
- add execution tests for query_logs: sql passthrough + timestamp
  defaulting, custom window forwarding, and empty-query rejection
The description promises iso_timestamp_start defaults to 24h before the end,
but the handler always computed start from now(), so supplying only
iso_timestamp_end produced an inverted/empty window. Derive the end first
(supplied or now), then default start to end - 24h, shared by get_logs and
query_logs.
resolveLogWindow now rejects a malformed iso_timestamp_start/end with a
clear error instead of throwing a raw "Invalid time value", and rejects a
start at or after the end. Also rebases onto main to pick up the
regenerated management API types.
@jordienr
jordienr force-pushed the claude/mcp-log-query-tool-8372a9 branch from c1bdc7f to 09e521e Compare August 3, 2026 14:52
Both tools currently ship an identical description to every client
regardless of platform (hosted vs local/self-hosted), so labeling get_logs
"Deprecated" risked a client universally hiding or deprioritizing it, which
would break self-hosted users since get_logs is their only working logs
tool. Reframe as environment-scoped preference (prefer query_logs on
hosted, use get_logs on local/self-hosted) instead of an unqualified
deprecation.
Comment thread packages/mcp-server-supabase/src/platform/types.ts Outdated
Comment thread packages/mcp-server-supabase/src/tools/debugging-tools.ts Outdated
Comment thread packages/mcp-server-supabase/src/tools/debugging-tools.ts Outdated
…registration

DebuggingOperations.queryLogs is used by external SupabasePlatform
implementers (CLI, studio, mcp.supabase.com controller) outside this repo.
Making it required would break them on upgrade: a stale implementer still
passes the existing `if (debugging)` group check, so query_logs gets listed
in tools/list and then crashes with "debugging.queryLogs is not a function"
at call time.

Make queryLogs optional and only register the query_logs tool when the
platform actually implements it, so an implementer without ClickHouse
support (self-hosted/CLI today) simply doesn't get the tool listed instead
of erroring. This makes the DebuggingOperations change purely additive.
Comment thread packages/mcp-server-supabase/src/tools/debugging-tools.ts
Comment thread packages/mcp-server-supabase/src/tools/debugging-tools.ts
Comment thread packages/mcp-server-supabase/src/platform/api-platform.ts
Comment thread packages/mcp-server-supabase/src/server.test.ts
resolveLogWindow now:
- enforces the 24h API cap client-side with a clear error, instead of
  relying on an unvalidated description promise
- normalizes accepted timestamps to canonical UTC ISO strings before
  forwarding them, instead of passing the original strings through verbatim
- is exported and unit-tested directly (default anchoring, offset
  normalization, malformed/inverted/oversized-window rejection), covering
  get_logs and query_logs' shared behavior in one place

Also enforces ISO 8601 with an explicit UTC "Z" suffix or offset at the
schema level via z.iso.datetime({ offset: true }), so offset-less
timestamps (ambiguous local-time interpretation) are rejected before
reaching resolveLogWindow, and the constraint shows up in the tool's JSON
schema.
@Rodriguespn

Rodriguespn commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Since this adds a tool and rewords the get_logs description, two post-merge follow-ups from CONTRIBUTING apply and are worth tracking in the PR description:

  1. Updating the tool list at Supabase MCP docs
  2. A ChatGPT app resubmission (tool list and descriptions are frozen fields).

Also linking the eval evidence here: the pkg.pr.new preview build of this branch passed the full supabase/evals regression suite (8/8, identical to the published-version baseline - CI run) and locally against the three debugging evals that exercise the analytics logs endpoint (evals#79, with transcripts showing agents successfully using query_logs with source = 'function_edge_logs' ClickHouse SQL.

Conditions of the run: model claude-sonnet-5 (reasoning effort high)

Thanks for taking care of this @jordienr!

- add an equal-timestamps case to the start-at-or-after-end rejection test
- assert on the actual rejection message (Invalid ISO datetime, must be
  before, min-length) instead of a bare rejects.toThrow()
- assert the exact default window (end near now, start = end - 24h)
  instead of just checking the params are truthy

@Rodriguespn Rodriguespn left a comment

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.

LGTM, thanks for taking another look @jordienr. Could you please address the nit comments I left, whether implementing them or closing them. Up to you 🙁

Important

One last thing before merging, this is also a breaking change as we changed get_logs description and inputSchema.
Can you change the title of this PR to include feat!: and also make sure that the merged commit that lands on main starts with feat!: please?

Check CONTRIBUTING's expand/contract rule for more details.

@Rodriguespn Rodriguespn left a comment

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.

Please check this slack message and the previous ones in that thread for more context on the step back

Rodriguespn pushed a commit to supabase/evals that referenced this pull request Aug 5, 2026
…ts/logs) (#99)

## What

Teaches platform-lite the ClickHouse logs endpoint that current mcp
actually calls: `GET /v1/projects/{ref}/analytics/endpoints/logs`,
taking ClickHouse-dialect SQL over the unified `logs` stream.

## Why

Since supabase/mcp#326, `get_logs` (and the proposed `query_logs` in
supabase/mcp#333) query `/analytics/endpoints/logs` with ClickHouse SQL.
platform-lite only served the legacy BigQuery-era `logs.all`, so **any
logs eval against a locally built mcp 404s at the fixture**. The gap is
masked today because evals pin a published `MCP_SERVER_VERSION`; it
bites the moment anyone points the harness at an mcp checkout (which is
how we validated mcp#333).

## How

- **Unified `logs` VIEW** over the existing seeded tables: a `source`
discriminator plus a jsonb `log_attributes` map built from the flat
columns, with seeded `metadata` as fallback. ClickHouse-shaped SQL runs
against it with minimal translation.
- **Minimal, observed-only dialect translation**
(`compileClickHouseLogsSql`): `log_attributes['k']` to jsonb access
(numeric cast for status/exec-time keys so `>= 500` comparisons work)
and `countIf(...)` to `count(*) FILTER (WHERE ...)`. A small shim family
(`toInt32OrZero`/`toInt64OrZero`/`toUInt32OrZero`/`toString`) covers
casts models genuinely emitted during live runs. Anything else surfaces
the raw SQL error to the model, which is deliberate: the supported
surface is documented and only grows from observed model output.
- **Read-only is enforced by a postgres read-only transaction**, not
regex: mutating SQL, including data-modifying CTEs (`WITH x AS (DELETE
...) SELECT`), is rejected before it can touch shared fixture state.
- **`iso_timestamp_start`/`end` are accepted but ignored**, matching the
legacy route: scenario seeds carry fixed dates while mcp defaults
windows from the current clock, so a faithful filter would empty every
scenario. Documented in-code as a known limitation; window-correctness
needs relative-time seeding and a discriminating eval (follow-up).
- Contract tests use **verbatim SQL captured from live claude-sonnet-5
runs** (the mcp `edge-function` preset, a `countIf` aggregation, and the
exact `toInt32OrZero(toString(...))` query the model emitted), plus the
runtime source and the legacy route untouched.

## Verification

- `pnpm typecheck` clean, `pnpm vitest run
src/management-api/debugging.test.ts` 8/8: five translator/view contract
tests plus three route-level tests at the HTTP boundary (normal
ClickHouse query returns the `{result}` shape; `WITH x AS (DELETE ...
RETURNING *) SELECT` is rejected by the read-only transaction with
fixture rows asserted unchanged; plain non-SELECT hits the 400 prefix
gate).
- Live: `investigate-logs-001-top-error-function` passes against a
locally built mcp `main` (3/3 checks) where it previously 404'd, and
against an mcp checkout of supabase/mcp#333 the model's first genuine
ClickHouse aggregation succeeds end to end.

Found while running an A/B validation of supabase/mcp#333 through the
eval workspace; the run details are in that PR's thread.
Per team alignment: on platforms that support ClickHouse-backed querying
(hosted/production), query_logs is the tool that shows up in tools/list and
get_logs is hidden from discovery (but remains callable via tools/call for
compatibility). On platforms without it (CLI/self-hosted), the reverse
holds: get_logs is listed and query_logs is not registered at all.

Also strips environment-specific wording (hosted, production, self-hosted,
CLI) from both tool descriptions, since the description is a frozen field
for some clients and shouldn't encode environment context the model can't
verify; the routing is now handled structurally via registration/hiding
instead of prose.
@jordienr jordienr changed the title feat: add query_logs tool for custom log queries feat!: add query_logs tool for custom log queries Aug 6, 2026

@Rodriguespn Rodriguespn left a comment

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.

Ran the CI locally and it's green. In general LGTM, thanks for the patience @jordienr. I'm approving this PR to unblock you, but wanted to ask if we can consider implementing the logsDialect + dynamic description approach that Matt suggested.

Seems like a low-hanging fruit to roll out query_logs across all envs without having to juggle multiple conditions depending on the environment. We're not suggesting implementing ClickHouse for logs on self-hosted/CLI for this — self-hosted/CLI would keep using its existing BigQuery-dialect logs endpoint (Logflare logs.all). The idea is just to hide get_logs on all envs and change query_logs's description/behavior depending on the env's dialect, using the strategy Matt described.

Essentially, what I'm suggesting is the following:

1. Add a logsDialect to DebuggingOperations so each platform can declare which SQL its logs endpoint speaks — platform/types.ts#L220-L223:

export type DebuggingOperations = {
  logsDialect?: 'clickhouse' | 'bigquery'; // <- new
  getLogs(projectId: string, options: GetLogsOptions): Promise<unknown>;
  queryLogs?(projectId: string, options: QueryLogsOptions): Promise<unknown>;
  ...
};

2. Each platform hardcodes its dialect and implements queryLogs. Hosted/platform-API already implements queryLogs (ClickHouse) — just add the dialect at platform/api-platform.ts#L255:

const debugging: DebuggingOperations = {
  logsDialect: 'clickhouse', // <- new
  ...
};

Self-hosted/CLI sets logsDialect: 'bigquery' and implements queryLogs by passing the model's SQL straight through to the same BigQuery-backed analytics endpoint getLogs already uses (the endpoint takes an arbitrary sql param), in supabase/apps/studio/lib/api/self-hosted/mcp.ts getDebuggingOperations:

return {
  logsDialect: 'bigquery', // <- new
  async getLogs(projectRef, options) { /* unchanged: getLogQuery(service) */ },
  async queryLogs(projectRef, options) { // <- new, mirrors getLogs
    const { data, error } = await retrieveAnalyticsData({
      name: 'logs.all',
      projectRef,
      params: {
        sql: options.sql, // pass the model's SQL instead of a preset
        iso_timestamp_start: options.iso_timestamp_start,
        iso_timestamp_end: options.iso_timestamp_end,
      },
    })
    if (error) throw error
    return data
  },
  ...
}

3. query_logs's description switches on the dialect — no string juggling, just pick the whole description. When the dialect is bigquery, reuse the existing get_logs description; when it's clickhouse, use the one this PR already writes for query_logs. In getDebuggingTools, at the query_logs registration:

query_logs: injectableTool({
  ...debuggingToolDefs.query_logs,
  description:
    debugging.logsDialect === 'bigquery'
      ? debuggingToolDefs.get_logs.description
      : debuggingToolDefs.query_logs.description,
  inject: { project_id },
  execute: async (...) => { ... },
}),

The same whole-string switch applies to any other dialect-gated copy (e.g. the sql param hint, which today hardcodes the ClickHouse logs table / log_attributes[...] schema).

4. The gating you already wrote does the rest. hidden: Boolean(queryLogs) stays exactly as-is — once every platform implements queryLogs, get_logs is hidden everywhere and query_logs is the single listed logs tool on all envs, each with a dialect-appropriate description. No new environment conditionals beyond the one logsDialect field.

Not blocking on this, happy to ship #333 as-is to keep the ball rolling. Just flagging it now since it looks like a small, self-contained change that removes the hosted-vs-self-hosted split entirely. Wdyt?

@jordienr
jordienr merged commit 798806b into supabase:main Aug 10, 2026
11 of 12 checks passed
@supabase-releaser supabase-releaser Bot mentioned this pull request Jul 30, 2026
Rodriguespn added a commit that referenced this pull request Aug 10, 2026
Adds an optional `logsDialect` (`'clickhouse' | 'bigquery'`) to
`DebuggingOperations` so each platform declares which SQL its logs
endpoint speaks. `query_logs` then picks its whole dialect-appropriate
description and `sql` param hint from a single lookup table, instead of
hardcoding ClickHouse copy — no environment-conditional prose the model
has to reason about. Defaults to `'clickhouse'` when unset, so existing
platform implementers are unaffected.

Implements [Matt's `logsDialect`
suggestion](https://supabase.slack.com/archives/C08N7894QTG/p1784660787397029?thread_ts=1784624411.491679&cid=C08N7894QTG)
raised in the #333 review.

**Why**: it lets `query_logs` roll out across every environment without
env-specific branching. Hosted stays ClickHouse; self-hosted/CLI can
keep its BigQuery-backed logs endpoint and declare `logsDialect:
'bigquery'`. This unblocks shipping the MCP server to self-hosted
(studio) regardless of whether it's on BigQuery or ClickHouse, rather
than holding the studio image back until self-hosted moves to
ClickHouse.

> [!NOTE]
> The comment sketched "reuse the `get_logs` description for `bigquery`"
— I instead give `query_logs` a proper BigQuery-dialect description,
since `get_logs` describes a `service` param while `query_logs` takes
`sql`. The BigQuery `sql` hint mirrors the canonical Logflare
self-hosted schema (`cross join unnest(metadata)`); worth confirming
when studio wires up the platform.

Refs AI-1046

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rodriguespn pushed a commit that referenced this pull request Aug 10, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>mcp-utils: 0.6.0</summary>

##
[0.6.0](mcp-utils-v0.5.1...mcp-utils-v0.6.0)
(2026-08-10)


### Features

* hide tools from tools/list
([#334](#334))
([d80471a](d80471a))
</details>

<details><summary>mcp-server-supabase: 0.10.0</summary>

##
[0.10.0](mcp-server-supabase-v0.9.0...mcp-server-supabase-v0.10.0)
(2026-08-10)


### ⚠ BREAKING CHANGES

* add query_logs tool for custom log queries
([#333](#333))

### Features

* add --content-api-url flag and SUPABASE_CONTENT_API_URL env var
([#343](#343))
([6fcaaa3](6fcaaa3))
* add query_logs tool for custom log queries
([#333](#333))
([798806b](798806b))
* hide tools from tools/list
([#334](#334))
([d80471a](d80471a))


### Bug Fixes

* hide read-only mode
([#349](#349))
([5cda067](5cda067))
* **pg-meta:** pair composite FK columns positionally to avoid cartesi…
([#317](#317))
([10af00b](10af00b))
* select query_logs dialect via logsDialect
([#357](#357))
([80ff453](80ff453))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: supabase-releaser[bot] <223506987+supabase-releaser[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

publish-preview Runs `publish-preview` workflow to publish preview packages via https://pkg.pr.new/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants