Skip to content

Add the chat tools to the MCP server #228

Description

@HMarzban

Problem

Three document read tools make a document reader, and nobody adds a connector for that. The chat room per heading is the one docs.plus feature no competitor has, and the connector cannot reach it.

There is no chat route in apps/hocuspocus.server. The OpenAPI spec carries 49 paths and zero chat paths.

The address already exists, so no schema change is needed. channel_id is the heading toc-id (apps/webapp/src/services/openHeadingChatroom.ts:142), and channels.workspace_id is the documentId. So one messages row names both a document and a section.

What to do

Add three chat tools to the MCP server:

  • list_chat_rooms — the rooms in a document.
  • read_chat_thread — the messages under one heading.
  • post_chat_message — a reply in one room, posted as the signed-in person.

Each reads from an existing Supabase table or RPC, but none of them may call Supabase first. A chat room carries no document-privacy rule, so each tool must resolve the slug to its document row and run resolvePrivateAccess in the application tier BEFORE it touches Supabase. That gate is new server work. Treat Row Level Security as the second gate, never the only one.

Acceptance

  • list_chat_rooms returns the rooms of a document the caller can read.
  • read_chat_thread returns messages for one heading, newest last, and truncates at the same limit Mount a stateless MCP server at /api/mcp with the document read tools #226 sets. It says in its result that it truncated, and returns a seq cursor for the next call.
  • post_chat_message posts under the caller's own identity, never a shared one.
  • A private document the caller cannot open returns a refusal, not an empty list.
  • The application-tier document gate runs before any Supabase query, on all three tools, including post_chat_message.
  • read_chat_thread marks its result as untrusted content, because anyone who can open the document can write into the room.

Notes

Chat rooms are created lazily. A heading nobody has opened chat on has no channels row. So a room list is always a subset of the outline, never a superset. A tool that treats them as interchangeable reports rooms as missing when they are merely unborn. Say this in the tool description.

messages already carries a unique client_id index, so a retried post is safe. It also carries a monotonic seq, which is a resume cursor.

Chat content is untrusted text from anyone who can open the document, and it flows into the model. Mark these tools accordingly, and do not let a chat message drive a write in this issue.

Promote the shared gate from denyRead and denyWrite at apps/hocuspocus.server/src/modules/document-conversion/http/controller.ts:47-71, which already run resolvePrivateAccess correctly.

Blocked by #226.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ChatRelated to chat featuresFeatureenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions