Problem
The MCP cat tool splits one logical node read across two response surfaces:
content[] contains the rendered node document.
structuredContent.nodes[] contains node_id and hash, but no document content.
Clients that consume only structured output report that the body is missing. Clients that consume only text see the body but not the precondition hash required by edit. Multi-node reads force clients to correlate a rendered YAML document stream with structured rows by position, which is fragile and unnecessarily client-specific.
This was observed in agent use: one client reported that cat did not return the body or hash, while another had to read both MCP response fields and correlate them manually.
Current implementation
pkg/mcp/tools_read.go already defines:
type nodeReadOutput struct {
NodeID string `json:"node_id"`
Hash string `json:"hash"`
Content string `json:"content,omitempty"`
}
However, registerCat uses:
res.StructuredContent = map[string]any{"nodes": nodeReadOutputs(views, false)}
The false omits Content. Existing precondition tests require the structured hash but do not require structured content.
Simply switching this argument to true may not be sufficient: nodeReadOutputs currently copies NodeView.Content, which is README content only. The default rendered cat document also includes metadata/frontmatter, and that complete document is what an agent needs to round-trip safely through edit.
Proposed response shape
Return each node as one authoritative machine-readable row:
{
"nodes": [
{
"node_id": "541",
"hash": "e0bec87937342270106e4a2d072264e3",
"content": "---\n...metadata...\n---\n# Meeting notes\n..."
}
]
}
Keep the existing text content[] rendering for human-readable output and backward compatibility.
Acceptance criteria
- Every
structuredContent.nodes[] row from cat pairs node_id, hash, and the corresponding node document.
- In default mode, the structured document can be sent back to
edit without dropping metadata.
- Single-node and multi-node reads require no positional correlation between separate response fields.
- The semantics of
content_only, meta_only, and stats_only are explicit and tested in structured output.
- Existing human-readable text output remains compatible.
- Tests assert both the structured hash and structured document content, including a multi-node case.
Why this matters
The hash is a precondition over node state, while the document is the candidate input for the subsequent write. Returning them as a pair makes the read-modify-write contract self-contained and prevents clients from accidentally editing the wrong node version or dropping frontmatter.
Problem
The MCP
cattool splits one logical node read across two response surfaces:content[]contains the rendered node document.structuredContent.nodes[]containsnode_idandhash, but no document content.Clients that consume only structured output report that the body is missing. Clients that consume only text see the body but not the precondition hash required by
edit. Multi-node reads force clients to correlate a rendered YAML document stream with structured rows by position, which is fragile and unnecessarily client-specific.This was observed in agent use: one client reported that
catdid not return the body or hash, while another had to read both MCP response fields and correlate them manually.Current implementation
pkg/mcp/tools_read.goalready defines:However,
registerCatuses:The
falseomitsContent. Existing precondition tests require the structured hash but do not require structured content.Simply switching this argument to
truemay not be sufficient:nodeReadOutputscurrently copiesNodeView.Content, which is README content only. The default renderedcatdocument also includes metadata/frontmatter, and that complete document is what an agent needs to round-trip safely throughedit.Proposed response shape
Return each node as one authoritative machine-readable row:
{ "nodes": [ { "node_id": "541", "hash": "e0bec87937342270106e4a2d072264e3", "content": "---\n...metadata...\n---\n# Meeting notes\n..." } ] }Keep the existing text
content[]rendering for human-readable output and backward compatibility.Acceptance criteria
structuredContent.nodes[]row fromcatpairsnode_id,hash, and the corresponding node document.editwithout dropping metadata.content_only,meta_only, andstats_onlyare explicit and tested in structured output.Why this matters
The hash is a precondition over node state, while the document is the candidate input for the subsequent write. Returning them as a pair makes the read-modify-write contract self-contained and prevents clients from accidentally editing the wrong node version or dropping frontmatter.