Altinity / Altinity/altinity-mcp

Expose ClickHouse-compatible HTTP API alongside MCP/OpenAPI

Open
#87 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
38
Forks
8
Avg merge
6d 14h
Merged PRs (30d)
8

Description

Problem

altinity-mcp with --openapi already looks more like a ClickHouse frontend than a pure MCP server. To make it a drop-in plug-in replacement in front of ClickHouse, it should also speak the native ClickHouse HTTP API documented at https://clickhouse.com/docs/interfaces/http, so existing tools, dashboards, and clients can point at altinity-mcp without changes:

curl 'http://mcp.example.com/?query=SELECT+1'
curl -u alice:pass 'http://mcp.example.com/?query=SELECT+1&database=analytics&default_format=JSONCompact'
curl -X POST 'http://mcp.example.com/' --data-binary 'SELECT 1'

Today any of these hit the MCP streamable-HTTP endpoint and fail.

Feasibility — hook points already exist

The HTTP router is centralized:

  • cmd/altinity-mcp/main.go — mux setup around mcpRoutePatterns (MCP transport) and openAPIRoutePatterns (lines 407-433); a new chHTTPRoutePatterns can be added to the same mux or, better, registered as a catch-all that sniffs ?query= or a POST body before handing off to MCP.
  • pkg/server/server.go:2519 — the OpenAPI dispatcher already routes by path suffix in a switch. Adding a case that matches ?query= is a one-line addition.
  • handleExecuteQueryOpenAPI (pkg/server/server.go) — the core 'parse request → run query → serialize' pipeline already exists. The CH-compat handler can reuse it; the work is input parsing (CH params/headers/body) and output formatting (TSV/JSON-variants), not query execution.
  • GetClickHouseClientFromCtx / GetClickHouseClientWithOAuth — already resolves the right backend connection based on JWE/OAuth/cluster-secret context. The CH-compat handler should funnel through the same path so all three auth modes work identically to MCP/OpenAPI.

Proposed dispatch

In the HTTP mux, before the MCP handler, route to a new handleClickHouseHTTP when any of these is true on the request:

  • Method is GET and ?query= is non-empty
  • Method is POST and Content-Type is text/plain; charset=UTF-8 (CH's native format) or the body starts with SQL keywords
  • Request has X-ClickHouse-User / X-ClickHouse-Key / X-ClickHouse-Database headers (unambiguous CH-client signal)

Otherwise fall through to existing MCP/OpenAPI handlers. This keeps MCP and OpenAPI clients unaffected.

Scope — phase 1 (minimum viable plug-in)

Request parsing
  • ?query= (URL-encoded SQL)
  • ?database= → overrides default database
  • ?default_format= → picks response format
  • POST body as query (when URL has no ?query=)
  • Mixed mode: ?query=SELECT+1+FROM+ + POST body = concatenation (matches CH semantics)
  • HTTP Basic Auth (username:password) → maps to ClickHouse user via cluster-secret / static / JWE / OAuth mode (whichever altinity-mcp is configured for)
  • X-ClickHouse-User / X-ClickHouse-Key / X-ClickHouse-Database headers (higher priority than basic auth, per CH docs)
Response formats (pick the most useful subset first)
  • TabSeparated (CH default — required)
  • TabSeparatedWithNames
  • JSONCompact
  • JSONEachRow
  • FORMAT clause detection in the SQL (CH-compat: trailing FORMAT JSONCompact wins over default_format)
Errors
  • Query errors → HTTP 500 with CH-style plain-text body (Code: 62. DB::Exception: ... (SYNTAX_ERROR))
  • Auth failures → HTTP 401 with WWW-Authenticate: Basic header
  • Unknown user / permission denied → HTTP 403
Preserves
  • Read-only mode flag still enforced
  • clickhouse-limit still applied (or: bypass since a real CH client expects unbounded results?)
  • Cluster-secret impersonation still uses oauthClaims.Email if the request arrives authenticated via OAuth

Scope — phase 2 (nice-to-have, file separate issues as needed)

  • Streaming responses for large result sets (currently we buffer everything in memory in executeSelect)
  • INSERT ... FORMAT with body data (POST to upload TSV/CSV)
  • Additional formats: RowBinary, Native, Values, Pretty*, CSV, CSVWithNames
  • ?param_<name>= query parameters (CH's {name:Type} substitution)
  • Compression (Accept-Encoding: gzip, lz4)
  • X-ClickHouse-Progress, X-ClickHouse-Summary response headers
  • readonly, max_result_rows, max_execution_time and other settings as query params

Out of scope

  • Binary native-protocol HTTP upgrades
  • Replica / cluster discovery endpoints (/replicas_status, /ping etc. — these are trivial to add if asked, but not part of 'query execution' plug-in)
  • TLS termination differences — inherit from existing server TLS

Why this is cleaner than it sounds

The CH HTTP API is substantial but altinity-mcp already has:

  1. Query execution with auth context — handleExecuteQueryOpenAPI path
  2. Per-request ClickHouse client resolution with JWE/OAuth/cluster-secret context
  3. QueryResult { Columns, Types, Rows, Count } internal type — straightforward to serialize to TSV/JSON variants

Phase 1 is mostly a format writer + a request parser + one route case. The heavy lifting (auth, execution, OpenAPI parity) stays untouched.

Acceptance criteria

  • curl 'http://localhost:8080/?query=SELECT+1' returns 1\n with Content-Type: text/tab-separated-values
  • curl -u user:pass 'http://localhost:8080/?query=SELECT+currentUser()' runs as user (cluster-secret / JWE / OAuth mode, whichever is configured)
  • curl 'http://localhost:8080/?query=SELECT+1&default_format=JSONCompact' returns valid JSONCompact
  • Invalid SQL returns HTTP 500 with Code: prefix body
  • Existing MCP clients and /openapi endpoints continue to work unchanged
  • Integration test: point a clickhouse-client --url at altinity-mcp and execute a simple SELECT

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the mux setup in cmd/altinity-mcp/main.go around mcpRoutePatterns and openAPIRoutePatterns, then read the dispatcher at pkg/server/server.go:2519 and handleExecuteQueryOpenAPI. Trace the existing client-resolution helpers and query result handling before running the project’s tests. Done means phase-one ClickHouse HTTP requests, formats, authentication, errors, and the listed curl/integration acceptance checks work without changing MCP or OpenAPI behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
clickhouse, go
Domain
api, authentication, databases
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.