Repository navigation
Description
Summary
Dynamic read tools (view_regexp) get first-class descriptor handling: a JSON COMMENT on the view is parsed into the MCP tool's title, description, and per-param docs (parseDynamicToolComment / applyCommentParamOverrides, covered by server_dynamic_tools_test.go).
Dynamic write tools (table_regexp + mode: insert) handle the same convention only halfway: with a JSON COMMENT on the target table,
- the
paramsdocs from the JSON are applied to the tool's input schema (each column parameter shows its description from the JSONparamsmap), but - the tool description is the raw, unparsed JSON text verbatim — braces, quotes,
"annotations"block and all.
Feature request: run the same COMMENT-JSON parse on the write-tool path, with the same fallback (invalid JSON → raw text as description) so plain-text comments keep working.
Observed behavior
Table (26.3, Null engine — the standard raw-write-target shape):
CREATE TABLE mcp.entries_raw (source_db String, facts String)
ENGINE = Null
COMMENT '{
"title": "Save Memory",
"description": "Save this session verified findings ... (long usage contract)",
"params": {
"source_db": "Which dataset these facts describe, e.g. eth. ...",
"facts": "JSON array of fact objects (see description for the object shape). ..."
},
"annotations": {"openWorldHint": false}
}';Tools rule:
- type: write
name: save_memory
table_regexp: "^mcp\\.entries_raw$"
mode: insertReflected tool as seen by a real MCP client (claude.ai connector, multicluster deployment):
save_memory.description= the entire raw JSON string above, newlines included;save_memoryinput schema paramssource_db/facts= the parsed descriptions from the JSONparamsmap (so part of the pipeline clearly runs).
A sibling view with the identical COMMENT convention on the same deployment reflects cleanly: parsed description, parsed param docs, no JSON wrapper.
Why this matters (reasoning)
- For write tools, the description is the usage contract. A read tool that's slightly under-described degrades gracefully — the model can inspect the result shape. A write tool can't be probed safely: everything the agent must know before calling (payload object shape, id/slug conventions, update-vs-create semantics, atomicity of batches, what's rejected and why) has to travel in the description. In our deployment (
save_memoryfor a shared agent-memory store, companion to Add dynamic SQL-view tools for schema discovery:search_schemaandinspect_table#151) that contract is ~1,400 chars of load-bearing text. - It's the only guaranteed channel to connector-only clients. Server
instructionsisn't configurable today, and third-party clients (claude.ai, ChatGPT) show exactly what the tool list carries. The COMMENT is the right place to author this — it lives next to the schema, versions with DDL, and needs no Go/helm change — which is precisely the design point of the dynamic-tool COMMENT convention for views. - Consistency of the convention. The same JSON
COMMENTdocument is fully honored on a view and half-honored on a table. Authors discover this only after deploying and inspecting a live client's tool list; the halfway state (params parsed, description raw) reads like a bug rather than a choice. - Raw JSON in the description has real costs: it's re-sent to the model in every session's tool list (token overhead for the wrapper/escapes), it's harder for models to read than prose, and it renders as visibly broken in client tool-list UIs.
Suggested behavior
In the write-tool registration path, treat the target table's COMMENT exactly like a view comment:
- valid descriptor JSON →
title/description/paramsoverrides (params keyed by column name, as already happens); - anything else → current behavior (raw comment text as description).
Backward compatible: existing plain-text table comments render unchanged; existing JSON comments start rendering as intended.
Environment
altinity-mcp multicluster (image fix-cimd-grant-types-99f0e05-arm64), ClickHouse 26.3.17.4, tools observed through the claude.ai connector. Related: #151 (dynamic SQL-view schema tools — the read-side counterpart of this deployment).
Activity