{
  "markdown": "# MCP ClickHouse Tool\n\n<!-- mcp-name: io.github.alyiox/mcp-clickhousex -->\n\n[![CI](https://github.com/alyiox/mcp-walmart-ads/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/alyiox/mcp-walmart-ads/actions/workflows/ci.yml)\n[![PyPI](https://img.shields.io/pypi/v/mcp-walmart-ads.svg)](https://pypi.org/project/mcp-walmart-ads/)\n[![Python 3.13+](https://img.shields.io/badge/python-3.13%2B-blue.svg)](https://www.python.org/downloads/)\n[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n\nA read-only [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for ClickHouse that supports metadata discovery, resources, parameterized `SELECT` queries, [`SHOW`](https://clickhouse.com/docs/sql-reference/statements/show) introspection, query analysis, and snapshot mode for large result sets, with profile-based configuration and strict no-DML/DDL enforcement.\n\n**Requirements:** Python 3.13+, a running ClickHouse instance, and connection details via environment variables or a config file.\n\n## Quick start\n\nSet a DSN and run the server with MCP Inspector:\n\n```bash\n# Option 1: Run directly with uvx (no clone needed)\nexport MCP_CLICKHOUSE_DSN=\"http://default:@localhost:8123/default\"\nnpx -y @modelcontextprotocol/inspector uvx mcp-clickhousex\n```\n\n```bash\n# Option 2: Run from source (clone repo, then)\nexport MCP_CLICKHOUSE_DSN=\"http://default:@localhost:8123/default\"\nnpx -y @modelcontextprotocol/inspector uv run main.py\n```\n\n## Configuration\n\nAll settings use the **MCP_CLICKHOUSE** prefix. **Flat** environment variables (e.g. `MCP_CLICKHOUSE_DSN`) are the straightforward way to configure the **default** profile when you have a single connection. For multiple profiles, the user-scoped `config.json` file is recommended.\n\n**Single connection:** Configure via environment variables.\n\n```bash\n# Connection DSN (required).\nexport MCP_CLICKHOUSE_DSN=\"http://user:password@host:8123/database\"\n\n# Optional description for the default profile (tooling/AI discovery).\nexport MCP_CLICKHOUSE_DESCRIPTION=\"Primary cluster\"\n\n# Optional max rows per interactive query (default 500; hard ceiling 1000).\nexport MCP_CLICKHOUSE_QUERY_MAX_ROWS=\"500\"\n\n# Optional interactive query timeout in seconds (default 30; hard ceiling 300).\nexport MCP_CLICKHOUSE_QUERY_COMMAND_TIMEOUT_SECONDS=\"30\"\n\n# Optional max rows for snapshot queries (default 10000; hard ceiling 50000).\nexport MCP_CLICKHOUSE_SNAPSHOT_MAX_ROWS=\"10000\"\n\n# Optional snapshot query timeout in seconds (default 120; hard ceiling 300).\nexport MCP_CLICKHOUSE_SNAPSHOT_COMMAND_TIMEOUT_SECONDS=\"120\"\n```\n\n**Multiple connections:** Use the user-scoped `config.json` file (recommended). Env vars also work via the `MCP_CLICKHOUSE_PROFILES_<NAME>_` prefix (e.g. `MCP_CLICKHOUSE_PROFILES_WAREHOUSE_DSN`).\n\n- Unix-like: `~/.config/mcp-clickhousex/config.json`\n- Windows: `%USERPROFILE%\\.config\\mcp-clickhousex\\config.json`\n\nExample (`config.json`):\n\n```json\n{\n  \"profiles\": {\n    \"default\": {\n      \"dsn\": \"http://default:@localhost:8123/default\",\n      \"description\": \"Primary\",\n      \"query_max_rows\": 500,\n      \"query_command_timeout_seconds\": 60,\n      \"snapshot_max_rows\": 10000,\n      \"snapshot_command_timeout_seconds\": 120\n    },\n    \"warehouse\": {\n      \"dsn\": \"http://user:pass@warehouse:8123/analytics\",\n      \"description\": \"Warehouse\"\n    }\n  }\n}\n```\n\n**Special characters in credentials:** If the username or password contains URL-reserved characters, percent-encode them in the DSN:\n\n| Character | Encoding |\n|-----------|----------|\n| `#` | `%23` |\n| `?` | `%3F` |\n| `/` | `%2F` |\n| `@` | `%40` |\n| `%` | `%25` |\n\nFor example, username `admin@org` and password `p#ss?` become `admin%40org:p%23ss%3F` in the DSN: `http://admin%40org:p%23ss%3F@host:8123/database`.\n\n## Tools\n\nTool 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.\n\n| Tool | Description | Key params |\n|---|---|---|\n| **`list_profiles`** | List configured profiles. Each entry includes name and optional description. | — |\n| **`get_cluster_properties`** | Get 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. |\n| **`run_query`** | Execute 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. |\n| **`run_show`** | Execute 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. |\n| **`analyze_query`** | Explain 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. |\n| **`list_databases`** | List databases. Rows from system.databases visible to the connection. | **`profile`** — Profile name; uses default profile when omitted. Src: profiles. |\n| **`list_tables`** | List 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. |\n| **`list_columns`** | List 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. |\n\n## Resources\n\nThe 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.\n\nResource descriptions match `description=…` on `@mcp.resource` in `server.py` (same prefix omission as above).\n\n| URI | Description |\n|-----|-------------|\n| `chx://profiles` | List configured profiles. Each entry includes name and optional description. |\n| `chx://profiles/{profile}/cluster-properties` | Get cluster properties and execution limits. Returns ClickHouse server version plus enforced limits (max rows, timeouts) for the profile. Src: profiles. |\n| `chx://profiles/{profile}/databases` | List databases. Rows from system.databases visible to the connection. Src: profiles. |\n| `chx://profiles/{profile}/databases/{database}/tables` | List 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. |\n| `chx://profiles/{profile}/databases/{database}/tables/{table}/columns` | List columns for a table or view. Rows from system.columns for the resolved database and table. Src: profiles, dbs, tables. |\n| `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. |\n\n\n## Security\n\nRead-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.\n\n## MCP host examples\n\nSnippets for common MCP clients using `uvx mcp-clickhousex` (no clone required; ensure `uv` is on your PATH). Replace connection details as needed.\n\n### Cursor\n\n```json\n{\n  \"mcpServers\": {\n    \"clickhouse\": {\n      \"command\": \"uvx\",\n      \"args\": [\"mcp-clickhousex\"],\n      \"env\": {\n        \"MCP_CLICKHOUSE_DSN\": \"http://default:@localhost:8123/default\"\n      }\n    }\n  }\n}\n```\n\n### Codex\n\n```toml\n[mcp_servers.clickhouse]\ncommand = \"uvx\"\nargs = [\"mcp-clickhousex\"]\n\n[mcp_servers.clickhouse.env]\nMCP_CLICKHOUSE_DSN = \"http://default:@localhost:8123/default\"\n```\n\n### OpenCode\n\n```json\n{\n  \"$schema\": \"https://opencode.ai/config.json\",\n  \"mcp\": {\n    \"clickhouse\": {\n      \"type\": \"local\",\n      \"enabled\": true,\n      \"command\": [\"uvx\", \"mcp-clickhousex\"],\n      \"environment\": {\n        \"MCP_CLICKHOUSE_DSN\": \"http://default:@localhost:8123/default\"\n      }\n    }\n  }\n}\n```\n\n### Claude Code\n\n```json\n{\n  \"mcpServers\": {\n    \"clickhouse\": {\n      \"command\": \"uvx\",\n      \"args\": [\"mcp-clickhousex\"],\n      \"env\": {\n        \"MCP_CLICKHOUSE_DSN\": \"http://default:@localhost:8123/default\"\n      }\n    }\n  }\n}\n```\n\n### Copilot\n\n```json\n{\n  \"inputs\": [],\n  \"servers\": {\n    \"clickhouse\": {\n      \"type\": \"stdio\",\n      \"command\": \"uvx\",\n      \"args\": [\"mcp-clickhousex\"],\n      \"env\": {\n        \"MCP_CLICKHOUSE_DSN\": \"http://default:@localhost:8123/default\"\n      }\n    }\n  }\n}\n```\n\n**Config file locations:** Cursor `.cursor/mcp.json`, Codex/Copilot/OpenCode vary by client; see your client's MCP docs.\n\n## Tests\n\nTests require a running ClickHouse instance. The test suite creates a sample table in the default database, seeds it, and drops it after.\n\n```bash\n# Run all tests (unit + functional + e2e)\nuv run pytest tests/ -v\n```\n\nThe 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`:\n\n```bash\nexport MCP_TEST_CLICKHOUSE_DSN=\"http://user:pass@testhost:8123/default\"\nuv run pytest tests/ -v\n```\n\n## Roadmap\n\nNo planned features at this time. Open an issue to suggest improvements.\n\n## Contributing\n\nOpen issues or PRs; follow existing style and add tests where appropriate.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n",
  "bytes": 12347,
  "sha": "fcc4dd2ccbcfaf3cec50f06923d9fb13f9041fc320a671445864a2fa9f6d1f5e",
  "repo_slug": "alyiox/mcp-clickhousex",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_alyiox_mcp_clickhousex_d23aca7c/readme"
}