Summary
MCP tool results from stackql mcp currently carry the typed payload in
structuredContent and a markdown rendering in the text content block
(pkg/mcp_server/render). That is spec-correct, but a large class of MCP
clients - LLM hosts, scripting clients, and SDK helpers - only consume the
text content. For those clients the markdown table/KV rendering is lossy
and unparseable, and there is no way to opt into machine-readable text.
Current behavior
tools/call run_select_query returns:
structuredContent: {"rows": [...]} (typed DTO)
content[0].text: a markdown table (RenderTable) or KV records
(RenderKV), e.g. # Pull Result\n\n## Record 1\n...
Proposed enhancement
Either (or both) of:
-
A per-call argument on the query/metadata tools, e.g.
format: "markdown" | "json" (default markdown, preserving current
behavior), where json renders the same DTO as compact JSON into the
text content block:
{
"name": "run_select_query",
"arguments": {"sql": "SELECT 1", "format": "json"}
}
-
A server-level render default in --mcp.config, consistent with the
existing config surface:
{"server": {"render": "json", "audit": {"disabled": true}}}
The per-call argument is the more useful of the two for mixed workloads
(human-facing hosts want markdown, embedded/scripting clients want JSON in
the same session).
Context
Encountered while building the embedded Rust client (stackql-mcp-rs):
clients that follow the MCP spec can and should prefer structuredContent
(that is what we ship), but interop with text-only consumers currently
requires parsing markdown. Observed on stackql v0.10.500, MCP stdio mode.
Summary
MCP tool results from
stackql mcpcurrently carry the typed payload instructuredContentand a markdown rendering in thetextcontent block(
pkg/mcp_server/render). That is spec-correct, but a large class of MCPclients - LLM hosts, scripting clients, and SDK helpers - only consume the
textcontent. For those clients the markdown table/KV rendering is lossyand unparseable, and there is no way to opt into machine-readable text.
Current behavior
tools/call run_select_queryreturns:structuredContent:{"rows": [...]}(typed DTO)content[0].text: a markdown table (RenderTable) or KV records(
RenderKV), e.g.# Pull Result\n\n## Record 1\n...Proposed enhancement
Either (or both) of:
A per-call argument on the query/metadata tools, e.g.
format: "markdown" | "json"(defaultmarkdown, preserving currentbehavior), where
jsonrenders the same DTO as compact JSON into thetext content block:
{ "name": "run_select_query", "arguments": {"sql": "SELECT 1", "format": "json"} }A server-level render default in
--mcp.config, consistent with theexisting config surface:
{"server": {"render": "json", "audit": {"disabled": true}}}The per-call argument is the more useful of the two for mixed workloads
(human-facing hosts want markdown, embedded/scripting clients want JSON in
the same session).
Context
Encountered while building the embedded Rust client (
stackql-mcp-rs):clients that follow the MCP spec can and should prefer
structuredContent(that is what we ship), but interop with text-only consumers currently
requires parsing markdown. Observed on stackql v0.10.500, MCP stdio mode.