Labsco
alyiox logo

mcp-clickhousex

from alyiox

A read-only MCP server for ClickHouse that supports metadata discovery, parameterized queries, and query analysis.

πŸ”₯πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedFreeQuick setup

MCP ClickHouse Tool

A read-only Model Context Protocol (MCP) server for ClickHouse that supports metadata discovery, resources, parameterized SELECT queries, SHOW introspection, query analysis, and snapshot mode for large result sets, with profile-based configuration and strict no-DML/DDL enforcement.

Requirements: Python 3.13+, a running ClickHouse instance, and connection details via environment variables or a config file.

Tools

Tool descriptions match server.py tool docstrings except the [ClickHouse] prefix is omitted here (it remains in MCP-exposed metadata). Parameter text matches each Field(description=…) on the same tool.

ToolDescriptionKey params
list_profilesList configured profiles. Each entry includes name and optional description.β€”
get_cluster_propertiesGet cluster properties and execution limits. Returns ClickHouse server version plus enforced limits (max rows, timeouts) for the profile.profile β€” Profile name; uses default profile when omitted. Src: profiles.
run_queryExecute read-only SELECT or WITH … SELECT. One statement; DML, DDL, SET, SYSTEM, and similar are rejected. Returns {data, row_count} where data is an RFC 4180 CSV string. Pass snapshot=true to persist the result to disk and receive {snapshot_uri, row_count} instead; fetch the CSV via the snapshot resource URI. Max-rows cap; overflow sets truncated and row_limit. Same SQL validation as analyze_query.sql (required) β€” Read-only SELECT or WITH … SELECT. One statement; use qualified db.table or database. Driver placeholder syntax for parameters. parameters β€” Named parameters for driver placeholders (e.g. %(name)s or {name:Type}). database β€” Session default database for unqualified names. Src: databases. profile β€” Profile name; uses default profile when omitted. Src: profiles. snapshot β€” When true, persist the full result as a CSV file and return a resource URI (chx://snapshots/{id}) instead of inline data. Use for queries that may exceed the interactive row limit (1 000). Snapshot limits apply (default 10 000 rows, hard ceiling 50 000). Entries expire after 7 days.
run_showExecute SHOW introspection statement. One statement per call; INTO OUTFILE rejected. Interactive row limits apply (default 500, hard ceiling 1 000). Same timeout as run_query.sql (required) β€” Single SHOW statement (e.g. SHOW DATABASES, SHOW CREATE TABLE). No INTO OUTFILE. parameters β€” Named parameters for driver placeholders (e.g. %(name)s or {name:Type}). database β€” Session default database for unqualified names. Src: databases. profile β€” Profile name; uses default profile when omitted. Src: profiles.
analyze_queryExplain read-only SELECT or WITH … SELECT. Returns plan, pipeline, and/or syntax text. Default types plan and pipeline. Uses query timeout and optional database; no max-rows cap unlike run_query.sql (required) β€” Read-only SELECT or WITH … SELECT for EXPLAIN. One statement; same validation as run_query. parameters β€” Named parameters for driver placeholders (e.g. %(name)s or {name:Type}). database β€” Session default database for unqualified names. Src: databases. profile β€” Profile name; uses default profile when omitted. Src: profiles. types β€” EXPLAIN variants: plan (indexes), pipeline, syntax. Default plan and pipeline if omitted.
list_databasesList databases. Rows from system.databases visible to the connection.profile β€” Profile name; uses default profile when omitted. Src: profiles.
list_tablesList tables and views in a database. Rows from system.tables: name, engine, primary_key, sorting_key, partition_key, total_rows, total_bytes for query planning.database β€” Database to list; client default when omitted. Src: databases. profile β€” Profile name; uses default profile when omitted. Src: profiles.
list_columnsList columns for a table or view. Rows from system.columns for the resolved database and table.table (required) β€” Table or view name, or database.table. Src: tables. database β€” Database when table is unqualified; ignored if table contains a dot. Client default when omitted. Src: databases. profile β€” Profile name; uses default profile when omitted. Src: profiles.

Resources

The server exposes the same discovery and metadata as the tools above via URI-addressable resources (profile-first hierarchy). Each resource’s description matches the corresponding tool (list_profiles, get_cluster_properties, list_databases, list_tables, list_columns), plus Src: tags for URI path parameters. All resource content is JSON (application/json) except snapshots which return CSV (text/csv). Use path segment default for the default profile or database.

Resource descriptions match description=… on @mcp.resource in server.py (same prefix omission as above).

URIDescription
chx://profilesList configured profiles. Each entry includes name and optional description.
chx://profiles/{profile}/cluster-propertiesGet cluster properties and execution limits. Returns ClickHouse server version plus enforced limits (max rows, timeouts) for the profile. Src: profiles.
chx://profiles/{profile}/databasesList databases. Rows from system.databases visible to the connection. Src: profiles.
chx://profiles/{profile}/databases/{database}/tablesList tables and views in a database. Rows from system.tables: name, engine, primary_key, sorting_key, partition_key, total_rows, total_bytes for query planning. Src: profiles, dbs.
chx://profiles/{profile}/databases/{database}/tables/{table}/columnsList columns for a table or view. Rows from system.columns for the resolved database and table. Src: profiles, dbs, tables.
chx://snapshots/{id}Fetch a query result snapshot by ID. Returns the full result as a CSV string (header row + data rows). Entries expire after 7 days. Src: run_query with snapshot=true.

Security

Read-only SQL only: run_query allows SELECT / WITH … SELECT; run_show allows a single SHOW statement per call. INTO OUTFILE is not allowed on run_show. Interactive queries enforce a tight row cap (default 500, hard ceiling 1 000); for larger extracts use snapshot=true (default 10 000, hard ceiling 50 000). Parameterized queries are supported where the driver allows (%(name)s or {name:Type} syntax). Use environment variables for connection credentials β€” never commit secrets.

MCP host examples

Snippets for common MCP clients using uvx mcp-clickhousex (no clone required; ensure uv is on your PATH). Replace connection details as needed.

Cursor

{
  "mcpServers": {
    "clickhouse": {
      "command": "uvx",
      "args": ["mcp-clickhousex"],
      "env": {
        "MCP_CLICKHOUSE_DSN": "http://default:@localhost:8123/default"
      }
    }
  }
}

Codex

[mcp_servers.clickhouse]
command = "uvx"
args = ["mcp-clickhousex"]

[mcp_servers.clickhouse.env]
MCP_CLICKHOUSE_DSN = "http://default:@localhost:8123/default"

OpenCode

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "clickhouse": {
      "type": "local",
      "enabled": true,
      "command": ["uvx", "mcp-clickhousex"],
      "environment": {
        "MCP_CLICKHOUSE_DSN": "http://default:@localhost:8123/default"
      }
    }
  }
}

Claude Code

{
  "mcpServers": {
    "clickhouse": {
      "command": "uvx",
      "args": ["mcp-clickhousex"],
      "env": {
        "MCP_CLICKHOUSE_DSN": "http://default:@localhost:8123/default"
      }
    }
  }
}

Copilot

{
  "inputs": [],
  "servers": {
    "clickhouse": {
      "type": "stdio",
      "command": "uvx",
      "args": ["mcp-clickhousex"],
      "env": {
        "MCP_CLICKHOUSE_DSN": "http://default:@localhost:8123/default"
      }
    }
  }
}

Config file locations: Cursor .cursor/mcp.json, Codex/Copilot/OpenCode vary by client; see your client's MCP docs.

Tests

Tests require a running ClickHouse instance. The test suite creates a sample table in the default database, seeds it, and drops it after.

# Run all tests (unit + functional + e2e)
uv run pytest tests/ -v

The test harness uses MCP_TEST_CLICKHOUSE_DSN to locate the ClickHouse instance. If unset, it falls back to http://admin:password123@localhost:8123/default. Set the variable to point tests at a different server without affecting your production MCP_CLICKHOUSE_DSN:

export MCP_TEST_CLICKHOUSE_DSN="http://user:pass@testhost:8123/default"
uv run pytest tests/ -v

Roadmap

No planned features at this time. Open an issue to suggest improvements.