You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Let a connected app anchor a chat post to a quoted sentence #351
A connected app can post in a heading chat, but its post cannot point at a sentence. A Comment made in docs.plus carries a quote, and its jump button scrolls the pad to that quote. This issue adds an optional quote to post_chat_message, so the post becomes a Comment on that sentence. An owner can then ask their AI app to leave questions beside the text they are about.
Build it only after the maintainer opens the usage gate and rules whether the MCP server may create a heading chat.
Acceptance criteria
The maintainer has posted on this issue that the usage gate is open.
The maintainer has posted the heading-chat ruling on this issue: may the MCP server create a heading chat, yes or no.
post_chat_message with a valid quote stores a Comment. In the pad, its jump button scrolls to the quoted sentence, on desktop and phone.
A post without quote behaves exactly as today.
Each of these quotes is refused, with a next step:
a quote the pad cannot find;
a quote that appears more than once in the pad;
a quote outside the section of section_id;
a quote over the length cap.
The quote is stored exactly as given. @, < and > are removed from text only.
The tool reply names the heading title and the quote.
The tool description says that heading chat in a public document is public.
docs/mcp/reference.md and docs/mcp/README.md describe quote, its length cap, and the heading-chat rule from the ruling.
Type: HITL — the maintainer posts two answers on this issue. (1) Gate: post_chat_message:ok reaches 20 posts a week for four weeks on the admin dashboard page /mcp, then one owner asks for this. (2) The heading-chat ruling: may the MCP server create a heading chat? The maintainer may change the gate numbers.
Category: enhancement
Current behavior:
post_chat_message refuses a heading with no chat yet (openChatRoom in apps/hocuspocus.server/src/modules/mcp/tools/chatTools.ts:59-67, text in noRoomText at :29-30). A heading chat starts only when a signed-in person opens it in docs.plus (syncChannel in apps/webapp/src/components/chatroom/hooks/useChannelMetadata.ts).
The insert sets no type and no metadata (postMessage in apps/hocuspocus.server/src/modules/mcp/infra/chatStore.ts:100-115; its input type is ChatStore in apps/hocuspocus.server/src/modules/mcp/types.ts).
The webapp stores a Comment as type: 'comment' with metadata: { comment } (apps/webapp/src/api/messages/sendCommentMessage.ts:20-30). A text anchor is { v: 1, heading_id, section_title?, kind: 'text', content } (TextCommentAnchor in apps/webapp/src/types/comment.ts).
toChatPost removes @, < and > (apps/hocuspocus.server/src/modules/mcp/domain/toChatPost.ts:7).
The unread count skips the sender (increment_unread_count_on_new_message in packages/supabase/scripts/10-func-notifications.sql). The owner who asked the agent gets no badge for its posts.
Desired behavior:
Add an optional plain-text quote to the post_chat_message input. Cap it at 500 characters, as a named constant beside MAX_CHAT_POST_CHARS. State the cap in docs/mcp/reference.md.
Check the quote against the live document JSON (loadContent) with the pad's own unit. The quote sits inside one textblock, appears once in the whole pad, and holds no line break. That textblock lies inside the section of section_id (the findSection range). Refuse otherwise with: "quote: copy plain text from one paragraph under this heading, with no Markdown, that appears once in the document."
Put the check in one pure function under apps/hocuspocus.server/src/modules/mcp/domain/.
Heading chat creation follows the heading-chat ruling. On "no": keep the refusal. On "yes": create it with the same row shape as syncChannel, and say so in the docs.
Where to start:post_chat_message and openChatRoom in apps/hocuspocus.server/src/modules/mcp/tools/chatTools.ts; postMessage in apps/hocuspocus.server/src/modules/mcp/infra/chatStore.ts; ChatStore in apps/hocuspocus.server/src/modules/mcp/types.ts; findSection in apps/hocuspocus.server/src/modules/document-content/domain/sections.ts; focusTextAnchor in apps/webapp/src/utils/scrollToCommentAnchor.ts. Line numbers are hints as of 2026-09-28; the agent searches by symbol.
Rules that apply:
apps/hocuspocus.server/CLAUDE.md §MCP Connector (owner-only posts, the workspace_id filter on every chat query, the caller as user_id).
apps/webapp/CLAUDE.md §Document Comments.
AGENTS.md §Test Policy.
Doc prose follows .cursor/skills/tech-writer/SKILL.md §Simplified English (house standard).
Verify:
The quote check is parsing logic with several branches, so AGENTS.md §Test Policy case (c) allows one unit test, in apps/hocuspocus.server/src/modules/mcp/__tests__/unit/. Cover: a quote inside one run, a quote across a bold word (accepted), a repeated quote, a quote under another heading, and a line break. Prove it by sabotage: make the check always pass, and the test must fail.
cd apps/hocuspocus.server && bun test src/modules/mcp && bun run typecheck, then bun run lint from the repo root.
Local end to end: run make dev-local, then claude mcp add --transport http docs-plus-local http://localhost:4000/api/mcp, and sign in when the browser opens. In a pad you own, open one heading's chat once. Ask Claude to post a question about one sentence under that heading, with a quote. In the pad, open the chat and press the Comment's jump button. The pad scrolls to the sentence. Check desktop and phone (mobile user agent), light and dark.
Parent
#328. Related: #228
What to build
A connected app can post in a heading chat, but its post cannot point at a sentence. A Comment made in docs.plus carries a quote, and its jump button scrolls the pad to that quote. This issue adds an optional
quotetopost_chat_message, so the post becomes a Comment on that sentence. An owner can then ask their AI app to leave questions beside the text they are about.Build it only after the maintainer opens the usage gate and rules whether the MCP server may create a heading chat.
Acceptance criteria
post_chat_messagewith a validquotestores a Comment. In the pad, its jump button scrolls to the quoted sentence, on desktop and phone.quotebehaves exactly as today.section_id;@,<and>are removed fromtextonly.docs/mcp/reference.mdanddocs/mcp/README.mddescribequote, its length cap, and the heading-chat rule from the ruling.Blocked by
Agent brief
Type: HITL — the maintainer posts two answers on this issue. (1) Gate:
post_chat_message:okreaches 20 posts a week for four weeks on the admin dashboard page/mcp, then one owner asks for this. (2) The heading-chat ruling: may the MCP server create a heading chat? The maintainer may change the gate numbers.Category: enhancement
Current behavior:
post_chat_messagerefuses a heading with no chat yet (openChatRoominapps/hocuspocus.server/src/modules/mcp/tools/chatTools.ts:59-67, text innoRoomTextat:29-30). A heading chat starts only when a signed-in person opens it in docs.plus (syncChannelinapps/webapp/src/components/chatroom/hooks/useChannelMetadata.ts).typeand nometadata(postMessageinapps/hocuspocus.server/src/modules/mcp/infra/chatStore.ts:100-115; its input type isChatStoreinapps/hocuspocus.server/src/modules/mcp/types.ts).type: 'comment'withmetadata: { comment }(apps/webapp/src/api/messages/sendCommentMessage.ts:20-30). A text anchor is{ v: 1, heading_id, section_title?, kind: 'text', content }(TextCommentAnchorinapps/webapp/src/types/comment.ts).focusTextAnchor(apps/webapp/src/utils/scrollToCommentAnchor.ts) and takes the first match in the whole pad. After Jump a Comment to its text when the quoted text crosses bold or a link #341, it matches inside one textblock, across marks.toChatPostremoves@,<and>(apps/hocuspocus.server/src/modules/mcp/domain/toChatPost.ts:7).increment_unread_count_on_new_messageinpackages/supabase/scripts/10-func-notifications.sql). The owner who asked the agent gets no badge for its posts.Desired behavior:
quoteto thepost_chat_messageinput. Cap it at 500 characters, as a named constant besideMAX_CHAT_POST_CHARS. State the cap indocs/mcp/reference.md.loadContent) with the pad's own unit. The quote sits inside one textblock, appears once in the whole pad, and holds no line break. That textblock lies inside the section ofsection_id(thefindSectionrange). Refuse otherwise with: "quote: copy plain text from one paragraph under this heading, with no Markdown, that appears once in the document."apps/hocuspocus.server/src/modules/mcp/domain/.type: 'comment'andmetadata.commentwithv: 1,kind: 'text',heading_idset to thesection_id,section_titleset to the heading text, andcontentset to the quote. Keep theviakey that Mark MCP chat posts with a fixed connected-app metadata key #336 adds (it lands before Show a "via connected app" label on chat posts from a connected app #344).syncChannel, and say so in the docs.Where to start:
post_chat_messageandopenChatRoominapps/hocuspocus.server/src/modules/mcp/tools/chatTools.ts;postMessageinapps/hocuspocus.server/src/modules/mcp/infra/chatStore.ts;ChatStoreinapps/hocuspocus.server/src/modules/mcp/types.ts;findSectioninapps/hocuspocus.server/src/modules/document-content/domain/sections.ts;focusTextAnchorinapps/webapp/src/utils/scrollToCommentAnchor.ts. Line numbers are hints as of 2026-09-28; the agent searches by symbol.Rules that apply:
apps/hocuspocus.server/CLAUDE.md§MCP Connector (owner-only posts, theworkspace_idfilter on every chat query, the caller asuser_id).apps/webapp/CLAUDE.md§Document Comments.AGENTS.md§Test Policy..cursor/skills/tech-writer/SKILL.md§Simplified English (house standard).Verify:
AGENTS.md§Test Policy case (c) allows one unit test, inapps/hocuspocus.server/src/modules/mcp/__tests__/unit/. Cover: a quote inside one run, a quote across a bold word (accepted), a repeated quote, a quote under another heading, and a line break. Prove it by sabotage: make the check always pass, and the test must fail.cd apps/hocuspocus.server && bun test src/modules/mcp && bun run typecheck, thenbun run lintfrom the repo root.make dev-local, thenclaude mcp add --transport http docs-plus-local http://localhost:4000/api/mcp, and sign in when the browser opens. In a pad you own, open one heading's chat once. Ask Claude to post a question about one sentence under that heading, with a quote. In the pad, open the chat and press the Comment's jump button. The pad scrolls to the sentence. Check desktop and phone (mobile user agent), light and dark.Out of scope
read_chat_thread— Add links and Comment quotes to MCP reads #343.@mentions from connected apps.@stays stripped fromtext.add_commenttool. One optional field onpost_chat_messagecovers it.