Parent
#328. Related: #230, #344
What to build
post_chat_message posts in a heading chat as the document owner. Nothing in the stored row says a connected app wrote it. Past posts can never be marked, because no record ties a chat row to MCP.
After this change, every MCP chat post stores metadata.via = 'connected_app'. read_chat_thread reads the key back and tags those posts. So a connected app can tell its own posts from the owner's. The visible label in the pad is #344.
Acceptance criteria
Blocked by
None — can start now.
Agent brief
Type: AFK.
postMessage in apps/hocuspocus.server/src/modules/mcp/infra/chatStore.ts adds metadata: { via: CONNECTED_APP_VIA }. The store owns the constant, so no tool can pass another value.
readThread adds the path via:metadata->>via. ChatMessage gets a viaConnectedApp flag. renderChatMessage adds the tag inside frameChatText.
- No migration and no
apps/webapp/src/types/supabase.ts change: messages.metadata is an existing jsonb column. No insert trigger rewrites NEW.metadata.
Rules: apps/hocuspocus.server/CLAUDE.md §MCP Connector. AGENTS.md §Test Policy: no new test.
Verify: typecheck, bun test src/modules/mcp, lint and format. On the local stack, post with post_chat_message and check the row in Supabase Studio. Pin, unpin and reply, then call read_chat_thread.
Out of scope
Parent
#328. Related: #230, #344
What to build
post_chat_messageposts in a heading chat as the document owner. Nothing in the stored row says a connected app wrote it. Past posts can never be marked, because no record ties a chat row to MCP.After this change, every MCP chat post stores
metadata.via = 'connected_app'.read_chat_threadreads the key back and tags those posts. So a connected app can tell its own posts from the owner's. The visible label in the pad is #344.Acceptance criteria
post_chat_messagehasmetadataequal to{"via":"connected_app"}inpublic.messages.CONNECTED_APP_VIA, inapps/hocuspocus.server/src/modules/mcp/types.ts. Noclient_idor app name is stored.read_chat_threadshowsvia connected appin the head line of such a post.metadata,readThreadselects only named paths, never the whole object.viakey. The pad renders an MCP post as before.metadata.viais still there.apps/hocuspocus.server/API.md§MCP connector,docs/mcp/reference.mdand the MCP entry under## [Unreleased]inapps/hocuspocus.server/CHANGELOG.mdeach state the key in one line.Blocked by
None — can start now.
Agent brief
Type: AFK.
postMessageinapps/hocuspocus.server/src/modules/mcp/infra/chatStore.tsaddsmetadata: { via: CONNECTED_APP_VIA }. The store owns the constant, so no tool can pass another value.readThreadadds the pathvia:metadata->>via.ChatMessagegets aviaConnectedAppflag.renderChatMessageadds the tag insideframeChatText.apps/webapp/src/types/supabase.tschange:messages.metadatais an existingjsonbcolumn. No insert trigger rewritesNEW.metadata.Rules:
apps/hocuspocus.server/CLAUDE.md§MCP Connector.AGENTS.md§Test Policy: no new test.Verify: typecheck,
bun test src/modules/mcp, lint and format. On the local stack, post withpost_chat_messageand check the row in Supabase Studio. Pin, unpin and reply, then callread_chat_thread.Out of scope