Skip to content

fix(mcp): add ClickHouse safety settings (max_execution_time, max_result_rows, readonly) - #2427

Merged
kodiakhq[bot] merged 3 commits into
mainfrom
brandon/brandon-mcp-sql-tweaks
Jun 9, 2026
Merged

kodiakhq[bot] merged 3 commits into
mainfrom
brandon/brandon-mcp-sql-tweaks

Conversation

@brandon-pereira

Copy link
Copy Markdown
Member

Summary

MCP query tools (clickstack_sql, clickstack_timeseries, clickstack_table, clickstack_search, clickstack_query_tile) now enforce ClickHouse safety limits that were previously missing. A runaway agent-supplied query could hold a connection for up to 1 hour (the default requestTimeout) with no row cap and no protection against DDL/DML injection.

Closes HDX-4476

What changed

A single constant governs all MCP query execution in runConfigTile():

Setting Value Purpose
max_execution_time 30s Kills long-running queries — matches eventDeltas, eventPatterns, Prometheus
max_result_rows 100,000 Prevents serialization OOM on the Node process — matches Prometheus
readonly 1 Blocks CREATE, INSERT, ALTER, DROP — matches trace tools
requestTimeout 32s HTTP timeout = 30s + 2s buffer for clean ClickHouse error — matches external API pattern

Applied to both the builder config path and the raw SQL path. The settings constant is shared so they can't drift.

Tests

Integration tests against real ClickHouse verify actual enforcement:

  • readonly — CREATE TABLE, INSERT, and DROP TABLE via clickstack_sql are rejected with a readonly error; SELECT still works
  • max_execution_time — sleep(3) with max_execution_time: 1 throws TIMEOUT_EXCEEDED

Add max_execution_time, max_result_rows, and readonly to all MCP
query-tool ClickHouse executions. Previously, MCP raw SQL queries
could run for up to 1 hour with no row limits and no DDL/DML
protection. Other MCP tools (eventDeltas, eventPatterns, trace)
already set these limits — this brings the core query path into
alignment.
@changeset-bot

changeset-bot Bot commented Jun 8, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 02c4fc6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@hyperdx/api Patch
@hyperdx/app Patch
@hyperdx/otel-collector Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Jun 8, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview, Comment Jun 8, 2026 11:36pm
hyperdx-storybook Ready Ready Preview, Comment Jun 8, 2026 11:36pm

Request Review

@github-actions github-actions Bot added the review/tier-2 Low risk — AI review + quick human skim label Jun 8, 2026
@github-actions

github-actions Bot commented Jun 8, 2026 •

Copy link
Copy Markdown
Contributor

🔵 Tier 2 — Low Risk

Small, isolated change with no API route or data model modifications.

Why this tier:

  • Standard feature/fix — introduces new logic or modifies core functionality

Review process: AI review + quick human skim (target: 5–15 min). Reviewer validates AI assessment and checks for domain-specific concerns.
SLA: Resolve within 4 business hours.

Stats
  • Production files changed: 1
  • Production lines changed: 26 (+ 120 in test files, excluded from tier calculation)
  • Branch: brandon/brandon-mcp-sql-tweaks
  • Author: brandon-pereira

To override this classification, remove the review/tier-2 label and apply a different review/tier-* label. Manual overrides are preserved on subsequent pushes.

@github-actions

github-actions Bot commented Jun 8, 2026 •

Copy link
Copy Markdown
Contributor

E2E Test Results

✅ All tests passed • 197 passed • 3 skipped • 1289s

Status Count
✅ Passed 197
❌ Failed 0
⚠️ Flaky 5
⏭️ Skipped 3

Tests ran across 4 shards in parallel.

View full report →

@greptile-apps

greptile-apps Bot commented Jun 8, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds ClickHouse safety guardrails (max_execution_time: 30, max_result_rows: 100000, readonly: 1) and a matching requestTimeout to all MCP query-tool executions, preventing runaway queries, serialization OOM, and DDL/DML injection from agent-supplied SQL.

  • helpers.ts: A single MCP_CLICKHOUSE_SETTINGS constant is applied to both the builder-config and raw-SQL code paths inside runConfigTile, plus a requestTimeout (32 s) on each ClickhouseClient construction; new errorHint branches cover RESULT_IS_TOO_LARGE and TOO_MANY_ROWS_OR_BYTES.
  • queryTool.test.ts: End-to-end integration tests verify readonly rejection for CREATE/INSERT/DROP and that getSetting() queries confirm all three safety settings are propagated through the full clickstack_sql MCP path.
  • query.test.ts: Unit tests cover the two new errorHint patterns.

Confidence Score: 5/5

Safe to merge — the safety settings are correctly applied to both execution paths and verified by end-to-end integration tests.

The change is well-scoped: a single constant governs both code paths, processClickhouseSettings confirms the external settings take precedence over defaults, and the new propagation tests cover the full MCP round-trip. The only nit is max_result_rows being typed as a string literal rather than a number, which has no runtime impact.

No files require special attention.

Important Files Changed

Filename Overview
packages/api/src/mcp/tools/query/helpers.ts Adds MCP_CLICKHOUSE_SETTINGS constant and MCP_REQUEST_TIMEOUT, applies them to both builder-config and raw-SQL code paths, and adds RESULT_IS_TOO_LARGE / TOO_MANY_ROWS_OR_BYTES error hints. Minor: max_result_rows is typed as a string literal while the other two settings are numbers.
packages/api/src/mcp/tests/queryTool.test.ts Adds end-to-end integration tests for readonly enforcement (CREATE/INSERT/DROP rejected, SELECT passes) and settings-propagation tests for all three MCP_CLICKHOUSE_SETTINGS values via getSetting() queries through the full clickstack_sql path.
packages/api/src/mcp/tests/query.test.ts Adds unit tests for the two new errorHint patterns (RESULT_IS_TOO_LARGE and TOO_MANY_ROWS_OR_BYTES); straightforward additions.
.changeset/nasty-crews-shop.md Patch-level changeset entry for the MCP safety-settings fix; description is accurate.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[MCP Tool Call\nclickstack_sql / clickstack_timeseries / etc.] --> B[runConfigTile]
    B --> C{Builder or Raw SQL?}

    C -- Builder --> D[new ClickhouseClient\nrequestTimeout: 32s]
    C -- Raw SQL --> E[new ClickhouseClient\nrequestTimeout: 32s]

    D --> F[queryChartConfig\nopts: clickhouse_settings]
    E --> G[queryChartConfig\nopts: clickhouse_settings]

    F --> H[MCP_CLICKHOUSE_SETTINGS\nmax_execution_time: 30\nmax_result_rows: 100000\nreadonly: 1]
    G --> H

    H --> I[processClickhouseSettings\nmerge with defaults]
    I --> J[ClickHouse HTTP query]

    J -- success --> K[formatQueryResult]
    J -- error --> L[clickHouseErrorResult]
    L --> M{errorHint match?}
    M -- DateTime64 / AS syntax\nV8 string / RESULT_IS_TOO_LARGE --> N[Append actionable HINT]
    M -- no match --> O[raw error message]
Loading

Fix All in Claude Code Fix All in Conductor Fix All in Cursor Fix All in Codex

Reviews (2): Last reviewed commit: "fix(mcp): add RESULT_IS_TOO_LARGE errorH..." | Re-trigger Greptile

…tests

- Add errorHint for RESULT_IS_TOO_LARGE / TOO_MANY_ROWS_OR_BYTES so
  agents get actionable guidance when hitting the 100k row limit.
- Add integration tests that use getSetting() to verify
  max_execution_time, max_result_rows, and readonly are propagated
  through the full MCP tool path to ClickHouse.
@brandon-pereira

Copy link
Copy Markdown
Member Author

Addressed both Greptile findings:

Issue 1 (max_execution_time test bypasses MCP path): Added getSetting() integration tests that go through the full clickstack_sql → runConfigTile → queryChartConfig → ClickHouse path and verify the actual setting values (max_execution_time=30, max_result_rows=100000, readonly=1) are applied to the running query. The direct ClickhouseClient test is kept alongside as a behavioral test (proves ClickHouse actually kills slow queries).

Issue 2 (Missing errorHint for RESULT_IS_TOO_LARGE): Added hint matching both RESULT_IS_TOO_LARGE and TOO_MANY_ROWS_OR_BYTES with actionable guidance to add LIMIT / narrow time range / add filters.

@kodiakhq
kodiakhq Bot merged commit f113ea3 into main Jun 9, 2026
20 checks passed
@kodiakhq
kodiakhq Bot deleted the brandon/brandon-mcp-sql-tweaks branch June 9, 2026 17:04

This branch was successfully deployed

2 active deployments
Preview – hyperdx-oss — 02c4fc63 Deployed Jun 8, 2026 by vercel[bot]
Preview – hyperdx-storybook — 02c4fc63 Deployed Jun 8, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automerge review/tier-2 Low risk — AI review + quick human skim

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants