Summary
In Claude Code, read_document and read_chat_thread deliver metadata only. The model never sees the document or the chat. Claude Code sends only structuredContent to the model when a tool result has both structuredContent and content. Our two read tools keep the text in content[0].text and put only metadata in structuredContent. Settings already offers a Claude Code tab, so this is a bug today.
Parent: #230. Related: #231, #357, #457.
Where
apps/hocuspocus.server/src/modules/mcp/tools/toolContext.ts:8-14: reply(text, structuredContent) returns both fields.
tools/documentTools.ts:293-299: read_document returns the framed Markdown in content, and { slug, section_id, rev, truncated, total_chars } in structuredContent.
tools/chatTools.ts:162-170: read_chat_thread keeps message text out of structuredContent on purpose ("Message text stays in the framed text block, never unframed here.").
docs/mcp/reference.md:60 and apps/hocuspocus.server/API.md:1028 document this design.
apps/webapp/src/components/settings/components/ConnectCard.tsx:177-186: the Claude Code tab in Settings > Connected apps. Evidence only; no change here.
What happens
A person connects docs.plus in Claude Code and asks "summarise the Budget section". The agent calls read_document with a section_id. The model receives { slug, section_id, rev, truncated, total_chars } and no text. It cannot summarise, and it cannot pick block numbers for edit_blocks. read_chat_thread fails the same way. Read from the Claude Code issues, not measured here.
Upstream reports: anthropics/claude-code#55677 (closed as not planned) and anthropics/claude-code#79944 (open). The MCP spec (revision 2026-07-28, "Structured content") says structured content SHOULD repeat as text, so a host may show either field. Reports there say claude.ai and ChatGPT read content. Not tested here.
Fix
Maintainer ruling, 2026-10-07: "Drop structuredContent from read_document and read_chat_thread." Keep everything in the text block:
read_document: call reply(text) with no second argument. The text already carries section_id and rev in its header, and the truncation note already gives the total ("showing N of M characters").
read_chat_thread: call reply(text). Delete the object at chatTools.ts:162-169, with its comment at line 165. The text already carries section_id, the truncation note and the before_seq note. truncated and nextBeforeSeq still feed the notes, so keep them.
toolContext.ts:8 reply: add a why-comment of at most two lines. A result that carries text people wrote passes no structuredContent, because some hosts then show the model only structuredContent. It replaces the comment at chatTools.ts:165.
docs/mcp/reference.md:60: replace "A result carries text and structuredContent, with snake_case keys." with "A result carries text. Most results also carry structuredContent, with snake_case keys. read_document and read_chat_thread return text only, because some hosts show the model only structuredContent when both are present."
apps/hocuspocus.server/API.md:1028: replace "A result also carries structuredContent, whose keys are snake_case like the inputs." with "Most results also carry structuredContent, whose keys are snake_case like the inputs. read_document and read_chat_thread return text only."
apps/hocuspocus.server/CHANGELOG.md: the connector is still under [Unreleased] › Added (lines 15-27). Add one sentence to that bullet: "read_document and read_chat_thread return text only, so Claude Code passes the text to the model." Do not add a Fixed entry.
No tool declares outputSchema, so a result with no structuredContent is valid MCP.
Out of scope
Acceptance criteria
Verify
Summary
In Claude Code,
read_documentandread_chat_threaddeliver metadata only. The model never sees the document or the chat. Claude Code sends onlystructuredContentto the model when a tool result has bothstructuredContentandcontent. Our two read tools keep the text incontent[0].textand put only metadata instructuredContent. Settings already offers a Claude Code tab, so this is a bug today.Parent: #230. Related: #231, #357, #457.
Where
apps/hocuspocus.server/src/modules/mcp/tools/toolContext.ts:8-14:reply(text, structuredContent)returns both fields.tools/documentTools.ts:293-299:read_documentreturns the framed Markdown incontent, and{ slug, section_id, rev, truncated, total_chars }instructuredContent.tools/chatTools.ts:162-170:read_chat_threadkeeps message text out ofstructuredContenton purpose ("Message text stays in the framed text block, never unframed here.").docs/mcp/reference.md:60andapps/hocuspocus.server/API.md:1028document this design.apps/webapp/src/components/settings/components/ConnectCard.tsx:177-186: the Claude Code tab in Settings > Connected apps. Evidence only; no change here.What happens
A person connects docs.plus in Claude Code and asks "summarise the Budget section". The agent calls
read_documentwith asection_id. The model receives{ slug, section_id, rev, truncated, total_chars }and no text. It cannot summarise, and it cannot pick block numbers foredit_blocks.read_chat_threadfails the same way. Read from the Claude Code issues, not measured here.Upstream reports: anthropics/claude-code#55677 (closed as not planned) and anthropics/claude-code#79944 (open). The MCP spec (revision 2026-07-28, "Structured content") says structured content SHOULD repeat as text, so a host may show either field. Reports there say claude.ai and ChatGPT read
content. Not tested here.Fix
Maintainer ruling, 2026-10-07: "Drop
structuredContentfromread_documentandread_chat_thread." Keep everything in the text block:read_document: callreply(text)with no second argument. The text already carriessection_idandrevin its header, and the truncation note already gives the total ("showing N of M characters").read_chat_thread: callreply(text). Delete the object atchatTools.ts:162-169, with its comment at line 165. The text already carriessection_id, the truncation note and thebefore_seqnote.truncatedandnextBeforeSeqstill feed the notes, so keep them.toolContext.ts:8reply: add a why-comment of at most two lines. A result that carries text people wrote passes nostructuredContent, because some hosts then show the model onlystructuredContent. It replaces the comment atchatTools.ts:165.docs/mcp/reference.md:60: replace "A result carries text andstructuredContent, with snake_case keys." with "A result carries text. Most results also carrystructuredContent, with snake_case keys.read_documentandread_chat_threadreturn text only, because some hosts show the model onlystructuredContentwhen both are present."apps/hocuspocus.server/API.md:1028: replace "A result also carriesstructuredContent, whose keys are snake_case like the inputs." with "Most results also carrystructuredContent, whose keys are snake_case like the inputs.read_documentandread_chat_threadreturn text only."apps/hocuspocus.server/CHANGELOG.md: the connector is still under[Unreleased]› Added (lines 15-27). Add one sentence to that bullet: "read_documentandread_chat_threadreturn text only, so Claude Code passes the text to the model." Do not add a Fixed entry.No tool declares
outputSchema, so a result with nostructuredContentis valid MCP.Out of scope
find_documents,get_outlineandlist_chat_rooms: Put document and heading titles inside the data frame in every MCP read #457 drops theirstructuredContenttoo, after this issue lands.create_document, the write tools andpost_chat_message. TheirstructuredContentgives the agent what it needs next, so Claude Code still works._meta["anthropic/maxResultSizeChars"]onread_document. Claude Code saves a result over 50,000 characters to a file, and the agent can still read it. Revisit if Test the MCP connector in three AI apps, then finish its connect guide #357 shows a problem. (Limit read from Claude Code docs, not measured.)Acceptance criteria
read_documentandread_chat_threadresults contain nostructuredContent. No other tool changes.section_id,rev(section reads), the truncation note and thebefore_seqnote.docs/mcp/reference.md:60,API.md:1028and the CHANGELOG bullet carry the text in Fix.Verify
cd apps/hocuspocus.server && bun run typecheck && bun test. No unit test covers these two tools, so this only proves that nothing else broke.read_document) and P5 (read_chat_thread) still pass.