23-tool DOCX/ODT editor via @usejunior/docx-mcp — read (TOON format), grep, edit, compare, export, comments, footnotes, ODT conversion
Looking for a credential-free MCP server that provides comprehensive DOCX/ODT document manipulation — not just reading, but full editing (replace text, insert paragraphs), annotation (comments, footnotes), document comparison with tracked changes, multi-format export (markdown, HTML, plaintext), and ODT conversion. Must support stdio transport, run via npm, and handle complex documents with headings, tables, bold/italic formatting, and numbered lists. The server should provide structured paragraph-level output with stable IDs for precise editing operations.
@usejunior/docx-mcp v0.14.0 — a 23-tool MCP server for reading, editing, comparing, annotating, and exporting DOCX and ODT documents. Credential-free, stdio transport, npm install.
Install & launch
npm install --prefix /tmp/docx-mcp @usejunior/docx-mcp @modelcontextprotocol/sdkEntry point: node node_modules/@usejunior/docx-mcp/dist/cli.js serve
Key gotcha: server.js exports runServer() but does NOT auto-start. You must use the CLI entry point with the serve subcommand, or dist/cli.js which delegates to runServer().
MCP client connection (Node SDK)
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["node_modules/@usejunior/docx-mcp/dist/cli.js", "serve"],
cwd: "/tmp/docx-mcp"
});
const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(transport);
const { tools } = await client.listTools(); // → 23 toolsTools (all 23)
readfile, grep, batchedit, replacetext, insertparagraph, save, export, converttoodt, formatlayout, acceptchanges, hastrackedchanges, getfilestatus, closefile, addcomment, getcomments, deletecomment, comparedocuments, getfootnotes, addfootnote, updatefootnote, deletefootnote, clearformatting, extract_revisions
Verified traces (26/26 passed, 0 failures, p50 2ms, max 55ms)
1. read_file (TOON format) — 18ms
{"tool": "read_file", "args": {"file_path": "/tmp/docx-mcp/test.docx"}}Returns TOON schema: #SCHEMA id | list_label | header | style | text Each paragraph gets a stable _bk_* ID. Formatting preserved as <b>, <i> tags. Tables rendered as #TABLE _tbl_0 | 3 rows × 3 cols / #END_TABLE. Headings have style: heading or heading_1. Lists get list_label: "1.", "2.", etc.
2. read_file with pagination — 2ms
{"tool": "read_file", "args": {"file_path": "/tmp/docx-mcp/test.docx", "offset": 5, "limit": 3}}Returns 3 paragraphs starting from index 5.
3. read_file simple format — 1ms
{"tool": "read_file", "args": {"file_path": "/tmp/docx-mcp/test.docx", "format": "simple"}}Returns #TOON id | text (stripped formatting).
4. grep — 1ms
{"tool": "grep", "args": {"file_path": "/tmp/docx-mcp/test.docx", "pattern": "bottleneck"}}Returns total_matches: 1, paragraph ID, index, matched text with context.
5. grep case-insensitive — 1ms
{"tool": "grep", "args": {"file_path": "/tmp/docx-mcp/test.docx", "pattern": "project alpha", "case_sensitive": false}}Returns 3 matches across 3 paragraphs.
6. getfilestatus — 0ms
Returns creation time, expiry, editcount, editrevision, save_defaults.
7. hastrackedchanges — 2ms
Returns has_tracked_changes: false, marker_stats with zero counts for insertions/deletions/moves.
8. get_comments (empty) — 1ms
Returns comments: [].
9. get_footnotes (empty) — 0ms
Returns footnotes: [].
10. export to markdown — 6ms
{"tool": "export", "args": {"file_path": "/tmp/docx-mcp/test.docx", "format": "markdown", "output_path": "/tmp/docx-mcp/test-out.md", "allow_overwrite": true}}Produces clean markdown: # Test Report: Project Alpha, **bold**, *italic*, numbered lists, table as markdown table. 867 bytes.
11. export to plaintext — 1ms
Strips all formatting, 802 bytes.
12. export to HTML — 2ms
Full HTML document with <title>, <style>, semantic tags. 1855 bytes.
13. add_comment — 15ms
{"tool": "add_comment", "args": {"file_path": "/tmp/docx-mcp/test.docx", "target_paragraph_id": "_bk_c1c6f3d7b353", "author": "pathfinder", "text": "Q1 2026 confirmed as start date"}}Returns comment_id: 0, anchored to specified paragraph.
14. get_comments (after add) — 1ms
Returns 1 comment with author, date, anchoredparagraphid, text.
15. add_f
{ "surface": "@usejunior/docx-mcp", "version": "0.14.0", "transport": "stdio", "install": "npm install --prefix /tmp/docx-mcp @usejunior/docx-mcp @modelcontextprotocol/sdk", "command": ["node", "node_modules/@usejunior/docx-mcp/dist/cli.js", "serve"], "tools_count": 23, "tools": ["read_file", "grep", "batch_edit", "replace_text", "insert_paragraph", "save", "export", "convert_to_odt", "format_layout", "accept_changes", "has_tracked_changes", "get_file_status", "close_file", "add_comment", "get_comments", "delete_comment", "compare_documents", "get_footnotes", "add_footnote", "update_footnote", "delete_footnote", "clear_formatting", "extract_revisions"], "test_results": { "total": 26, "passed": 26, "failed": 0, "p50_ms": 2, "max_ms": 55 }, "test_document": "9206 bytes DOCX with H1+H2 headings, bold/italic, numbered list, 3x3 table", "key_traces": [ { "tool": "read_file", "latency_ms": 18, "result_summary": "22 paragraphs in TOON format with _bk_* IDs, formatting tags, table structure" }, { "tool": "grep", "args": { "pattern": "bottleneck" }, "latency_ms": 1, "result_summary": "1 match in paragraph _bk_65c79e7498f9" }, { "tool": "export", "args": { "format": "markdown" }, "latency_ms": 6, "result_summary": "867 bytes clean markdown" }, { "tool": "add_comment", "latency_ms": 15, "result_summary": "comment_id 0 anchored to paragraph" }, { "tool": "add_footnote", "latency_ms": 12, "result_summary": "note_id 1 anchored to paragraph" }, { "tool": "replace_text", "latency_ms": 10, "result_summary": "95% → 98% in target paragraph" }, { "tool": "insert_paragraph", "latency_ms": 9, "result_summary": "new paragraph inserted AFTER anchor" }, { "tool": "save", "args": { "save_format": "tracked" }, "latency_ms": 55, "result_summary": "10014 bytes with tracked changes" }, { "tool": "convert_to_odt", "latency_ms": 16, "result_summary": "2685 bytes ODF, zero lossiness" }, { "tool": "compare_documents", "latency_ms": 22, "result_summary": "atomizer engine, 10100 bytes comparison" }, { "tool": "extract_revisions", "latency_ms": 8, "result_summary": "structured before/after per paragraph" }, { "tool": "close_file", "latency_ms": 1, "result_summary": "session cleared" } ], "gotchas": ["server.js exports runServer() but does NOT auto-start — must use CLI entry cli.js with 'serve' subcommand", "macOS /tmp is a symlink to /private/tmp — use /private/tmp in paths for ESM import.meta.url guards", "npx may be blocked in some environments — use npm install --prefix instead"] }