write_document
Replace document content with TipTap XML for real-time UI synchronization in Mnemosyne knowledge graphs. Supports collaborative editing with comments and structured formatting.
Instructions
Replaces document content with TipTap XML. Syncs to UI in real-time.
WARNING: This REPLACES all content. For collaborative editing, prefer append_to_document.
Blocks: paragraph, heading (level="1-3"), bulletList, orderedList, blockquote, codeBlock (language="..."), taskList (taskItem checked="true"), horizontalRule Marks (nestable): strong, em, strike, code, mark (highlight), a (href="..."), footnote (data-footnote-content="..."), commentMark (data-comment-id="...") Example: Text with highlight and a note
Comments: Pass a dict mapping comment IDs to metadata. Comment IDs must match data-comment-id attributes in the content. Example comments: {"comment-1": {"text": "Great point!", "author": "Claude"}}
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| graph_id | Yes | ||
| document_id | Yes | ||
| content | Yes | ||
| comments | No |
Implementation Reference
- src/neem/mcp/tools/hocuspocus.py:160-233 (handler)The main handler function that performs the write_document tool logic: authenticates, connects to the document via HocuspocusClient, replaces all content with provided TipTap XML, optionally adds comments, updates the workspace with document title, reads back to confirm, and returns the result.async def write_document_tool( graph_id: str, document_id: str, content: str, comments: Optional[Dict[str, Any]] = None, context: Context | None = None, ) -> dict: """Write TipTap XML content to a document.""" auth = MCPAuthContext.from_context(context) auth.require_auth() try: # 1. Write document content and comments await hp_client.connect_document(graph_id, document_id) def write_content_and_comments(doc: Any) -> None: writer = DocumentWriter(doc) writer.replace_all_content(content) # Write comments if provided if comments: for comment_id, comment_data in comments.items(): writer.set_comment( comment_id=comment_id, text=comment_data.get("text", ""), author=comment_data.get("author", "MCP Agent"), author_id=comment_data.get("authorId", "mcp-agent"), resolved=comment_data.get("resolved", False), quoted_text=comment_data.get("quotedText"), ) await hp_client.transact_document( graph_id, document_id, write_content_and_comments, ) # 2. Update workspace navigation so document appears in file tree # Extract title from first heading, fallback to document_id title = extract_title_from_xml(content) or document_id await hp_client.connect_workspace(graph_id) await hp_client.transact_workspace( graph_id, lambda doc: WorkspaceWriter(doc).upsert_document(document_id, title), ) # 3. Read back document content and comments to confirm channel = hp_client.get_document_channel(graph_id, document_id) if channel is None: raise RuntimeError(f"Document channel not found: {graph_id}/{document_id}") reader = DocumentReader(channel.doc) xml_content = reader.to_xml() result_comments = reader.get_all_comments() result = { "success": True, "graph_id": graph_id, "document_id": document_id, "title": title, "content": xml_content, "comments": result_comments, } return result except Exception as e: logger.error( "Failed to write document", extra_context={ "graph_id": graph_id, "document_id": document_id, "error": str(e), }, ) raise RuntimeError(f"Failed to write document: {e}")
- src/neem/mcp/tools/hocuspocus.py:146-159 (registration)The @server.tool decorator that registers the write_document tool with FastMCP, specifying name, title, and detailed description serving as input/output schema.@server.tool( name="write_document", title="Write Document Content", description="""Replaces document content with TipTap XML. Syncs to UI in real-time. WARNING: This REPLACES all content. For collaborative editing, prefer append_to_document. Blocks: paragraph, heading (level="1-3"), bulletList, orderedList, blockquote, codeBlock (language="..."), taskList (taskItem checked="true"), horizontalRule Marks (nestable): strong, em, strike, code, mark (highlight), a (href="..."), footnote (data-footnote-content="..."), commentMark (data-comment-id="...") Example: <paragraph>Text with <mark>highlight</mark> and a note<footnote data-footnote-content="This is a footnote"/></paragraph> Comments: Pass a dict mapping comment IDs to metadata. Comment IDs must match data-comment-id attributes in the content. Example comments: {"comment-1": {"text": "Great point!", "author": "Claude"}}""", )
- src/neem/mcp/server/standalone_server.py:315-317 (registration)The call to register_hocuspocus_tools(mcp_server) in the create_standalone_mcp_server function, which triggers the definition and registration of all hocuspocus tools including write_document.register_basic_tools(mcp_server) register_graph_ops_tools(mcp_server) register_hocuspocus_tools(mcp_server)