Skip to content

Dynamic write tools: parse COMMENT-JSON descriptors the way view tools do #154

Description

@BorisTyshkevich

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 params docs from the JSON are applied to the tool's input schema (each column parameter shows its description from the JSON params map), 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: insert

Reflected 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_memory input schema params source_db / facts = the parsed descriptions from the JSON params map (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)

  1. 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_memory for a shared agent-memory store, companion to Add dynamic SQL-view tools for schema discovery: search_schema and inspect_table #151) that contract is ~1,400 chars of load-bearing text.
  2. It's the only guaranteed channel to connector-only clients. Server instructions isn'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.
  3. Consistency of the convention. The same JSON COMMENT document 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.
  4. 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 / params overrides (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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions