Editing .docx Files with Safe-DOCX
Safe-DOCX is a local MCP server for surgically editing existing .docx files. It preserves formatting, generates tracked-changes redlines, and — once installed — runs entirely on the local filesystem with zero network activity.
Source Code and Audit
Safe-DOCX is fully open source (MIT license). Review the complete source before installing:
- - GitHub: https://github.com/UseJunior/safe-docx
- npm registry: https://www.npmjs.com/package/@usejunior/safe-docx
- Code coverage: Published via Codecov on every release
- Conformance harness: Automated spec coverage tests run in CI on every commit
- No postinstall scripts — verify:
npm view @usejunior/safe-docx scripts shows no postinstall or install hooks
All security claims below are verifiable by reading the source.
Runtime Requirements
Safe-DOCX requires these binaries to be available on the host:
| Binary | Minimum version | Why |
|---|
| INLINECODE4 | 18.0.0 | Authoritative version from packages/safe-docx/package.json engines field |
| INLINECODE6 |
Bundled with npm | Used by the recommended MCP connector to launch the server |
If you prefer not to use npx, see Offline / Pinned Installation below for alternatives.
Safety Model
Safe-DOCX's safety model has two distinct phases: install time (when the package is fetched) and runtime (when the MCP server is running).
Install-Time Behavior (network required, one-time)
- - npm registry fetch — the recommended connector command
npx -y @usejunior/safe-docx downloads the package from registry.npmjs.org on first run. Subsequent runs use the cached copy unless the cache is cleared. - No postinstall scripts — the package declares no
postinstall, preinstall, or install hooks. Verify with npm view @usejunior/safe-docx scripts. - Provenance — releases are published with npm provenance (
--provenance), so you can verify the package was built from the public GitHub repo via GitHub Actions. - If you need guaranteed offline install — pin a specific version and vendor it locally. See the next section.
Runtime Behavior (zero network)
- - Local-only stdio runtime — the MCP server runs as a child process, never binds a port. Verify: the entry point (
src/server.ts) uses StdioServerTransport with no HTTP listener. (source) - No outbound network calls — at runtime, the package makes zero outbound HTTP requests. Verify:
grep -r "fetch\|http\.\|https\.\|net\." packages/safe-docx/src/ returns no matches in application code (test fixtures excluded). - Path policy — only files under
~/ (home directory) and system temp directories are accessible. Symlinks must resolve to allowed roots. - Archive guardrails — zip bomb detection and hostile payload rejection protect against malformed
.docx inputs.
Offline / Pinned Installation
For high-security environments where npx auto-fetch is unacceptable, install the package manually and pin the version:
CODEBLOCK0
After any of these, your MCP client config becomes:
CODEBLOCK1
Using command: "safe-docx" (the installed binary) instead of command: "npx" eliminates the install-time network fetch on every invocation.
Always pin the version
Even with npx, you can pin the version to prevent unexpected updates:
CODEBLOCK2
Before upgrading, review the changelog: https://github.com/UseJunior/safe-docx/blob/main/CHANGELOG.md
When to Use This Skill
Use Safe-DOCX when you need to:
- - Change clauses or paragraphs in an existing INLINECODE24
- Insert or delete content with formatting preservation
- Add comments or footnotes for reviewers
- Produce a tracked-changes redline from edits
- Compare two
.docx files into a redline - Extract revisions to structured JSON
- Apply layout formatting (spacing, row heights, cell padding)
Not for From-Scratch Generation
Safe-DOCX edits already-existing .docx files — it does not create documents from blank. For new document generation, use a template-filling workflow (e.g. OpenAgreements). Safe-DOCX can refine generated docs downstream.
Quick Start
CODEBLOCK3
Core Workflow: Read, Locate, Edit, Save
Step 1 — Read. Call read_file with format: "toon" (token-efficient table) to see paragraphs and their stable _bk_* IDs.
Step 2 — Locate. Use grep with regex patterns to find target paragraphs. It returns paragraph IDs with surrounding context.
Step 3 — Edit. Use replace_text to swap text within a paragraph, or insert_paragraph to add new paragraphs before/after an anchor.
Step 4 — Save. Call save to write output. Default is save_format: "both" which produces a clean copy and a tracked-changes redline.
Gotchas That Will Bite You
Unique match required
INLINECODE35 needs old_string to match exactly one location in the target paragraph. If the text appears multiple times, you get MULTIPLE_MATCHES. Fix: include more surrounding context in old_string.
CODEBLOCK4
Footnote markers are display-only
INLINECODE39 shows footnotes as [^1], [^2], etc., but these markers are not part of the editable text. You cannot search for or replace [^1] via replace_text. To modify footnotes, use the dedicated add_footnote, update_footnote, and delete_footnote tools.
Hyperlinks are read-only
INLINECODE47 shows links as <a href="...">text</a>, but you cannot create new hyperlinks via replace_text or insert_paragraph. The <a> tag is stripped from new text. Existing hyperlinks are preserved when surrounding text is edited.
Paragraph IDs are session-scoped
The _bk_* bookmark IDs are generated when a document is opened and are tied to that session. Do not store or reuse IDs across sessions. Always re-read the document to get fresh IDs.
Smart text matching
INLINECODE53 is tolerant of:
- - Quote variants: straight
", curly \u201c\u201d, angle \u00ab\u00bb all match each other - Whitespace differences: multiple spaces, tabs, and line breaks are normalized
This means you can copy text from read_file output and use it in old_string even if the underlying XML uses different quote characters.
Formatting Tags
When writing new_string in replace_text or insert_paragraph, use inline tags to apply formatting:
| Tag | Effect |
|---|
| INLINECODE62 | Bold |
| INLINECODE63 |
Italic |
|
<u>text</u> | Underline |
|
<highlighting>text</highlighting> | Yellow highlight |
Tags can be nested: <b><i>bold italic</i></b>. Formatting from the original matched text is preserved for untagged replacement text.
Batch Edits with apply_plan
For 3+ edits on one document, prefer apply_plan over sequential replace_text calls. It validates all steps before applying any, so you get all-or-nothing transactional semantics.
CODEBLOCK5
Insert Paragraphs
INLINECODE69 adds new content before or after an anchor paragraph.
- -
position: "BEFORE" or "AFTER" (default "AFTER") - INLINECODE74 : optional
_bk_* ID of a paragraph whose formatting you want to clone - Multi-paragraph: separate with
\n\n in new_string (each becomes its own paragraph)
Comments and Footnotes
Comments: add_comment anchors to a paragraph (optionally to a text span via anchor_text). Use get_comments to list, delete_comment to remove. Supports threaded replies via parent_comment_id.
Footnotes: add_footnote inserts a footnote marker in a paragraph (optionally after specific text via after_text). Use get_footnotes, update_footnote, delete_footnote to manage.
Comparing Documents
Two modes:
- - Two files:
compare_documents(original_file_path, revised_file_path, save_to_local_path) — produces a redline - Session edits:
compare_documents(session_id) — compares current session state against the original
Use extract_revisions on any document with tracked changes to get structured JSON diffs.
Accepting Tracked Changes
Call accept_changes(session_id) to flatten all tracked changes into a clean document. This removes all revision markup.
Session Behavior
- - Sessions auto-create when you first use
file_path with any tool - Sessions expire after 1 hour of inactivity (each tool call resets the timer)
- Call
clear_session to clean up when done - Documents are normalized on open: format-identical runs are merged and proof-error markers removed, which improves text matching reliability
Layout Formatting
INLINECODE94 applies paragraph spacing, table row height, and cell padding without touching text content. Units are in twips (1/20 of a point) or DXA (1/635 of an inch).
Path Restrictions
By default, only files under ~/ (home directory) and system temp directories are accessible. Symlinks must resolve to allowed roots.
Related Skills
- - Open Agreements (
open-agreements) — fill standard legal templates (NDAs, SAFEs, cloud service agreements) and produce signable DOCX files: INLINECODE97 - Outlook Email Management (
outlook-email-management) — manage Outlook email with AI agents: INLINECODE99
Connectors
For MCP server setup instructions (Claude Desktop, Cursor, Claude Code), see CONNECTORS.md.
Feedback
If this skill helped, star us on GitHub: https://github.com/UseJunior/safe-docx
On ClawHub: INLINECODE100
使用 Safe-DOCX 编辑 .docx 文件
Safe-DOCX 是一个本地 MCP 服务器,用于对现有 .docx 文件进行精准编辑。它能保留格式、生成修订标记,并且一旦安装完成,完全在本地文件系统上运行,零网络活动。
源代码与审计
Safe-DOCX 完全开源(MIT 许可证)。安装前请审查完整源代码:
- - GitHub:https://github.com/UseJunior/safe-docx
- npm 仓库:https://www.npmjs.com/package/@usejunior/safe-docx
- 代码覆盖率:每次发布均通过 Codecov 发布
- 合规性测试框架:每次提交均在 CI 中运行自动化规范覆盖率测试
- 无安装后脚本——验证:npm view @usejunior/safe-docx scripts 显示无 postinstall 或 install 钩子
以下所有安全声明均可通过阅读源代码验证。
运行时要求
Safe-DOCX 需要在主机上提供以下二进制文件:
| 二进制文件 | 最低版本 | 原因 |
|---|
| node | 18.0.0 | 来自 packages/safe-docx/package.json engines 字段的权威版本 |
| npx |
与 npm 捆绑 | 由推荐的 MCP 连接器用于启动服务器 |
如果您不想使用 npx,请参阅下面的离线/固定版本安装部分了解替代方案。
安全模型
Safe-DOCX 的安全模型分为两个不同阶段:安装时(获取包时)和运行时(MCP 服务器运行时)。
安装时行为(需要网络,一次性)
- - npm 仓库获取——推荐的连接器命令 npx -y @usejunior/safe-docx 在首次运行时从 registry.npmjs.org 下载包。后续运行使用缓存副本,除非清除缓存。
- 无安装后脚本——该包声明无 postinstall、preinstall 或 install 钩子。使用 npm view @usejunior/safe-docx scripts 验证。
- 来源验证——发布时使用 npm 来源验证(--provenance),因此您可以验证该包是通过 GitHub Actions 从公共 GitHub 仓库构建的。
- 如果您需要保证离线安装——固定特定版本并在本地提供。请参阅下一节。
运行时行为(零网络)
- - 仅本地 stdio 运行时——MCP 服务器作为子进程运行,从不绑定端口。验证:入口点(src/server.ts)使用 StdioServerTransport,无 HTTP 监听器。(源代码)
- 无出站网络调用——运行时,该包发出零次出站 HTTP 请求。验证:grep -r fetch\|http\.\|https\.\|net\. packages/safe-docx/src/ 在应用程序代码中无匹配项(测试夹具除外)。
- 路径策略——仅可访问 ~/(主目录)和系统临时目录下的文件。符号链接必须解析到允许的根目录。
- 存档防护——压缩炸弹检测和恶意负载拒绝机制可防止格式错误的 .docx 输入。
离线/固定版本安装
对于 npx 自动获取不可接受的高安全环境,请手动安装包并固定版本:
bash
选项 1:全局固定特定版本
npm install -g @usejunior/safe-docx@0.9.0
然后配置您的 MCP 客户端通过路径调用它:
command: safe-docx
args: []
选项 2:将包供应商到您的项目中
npm pack @usejunior/safe-docx@0.9.0
检查 tarball,然后从磁盘安装:
npm install -g ./usejunior-safe-docx-0.9.0.tgz
选项 3:从源代码构建(最可审计)
git clone https://github.com/UseJunior/safe-docx.git
cd safe-docx
git checkout
npm ci
npm run build
npm link packages/safe-docx
完成上述任一操作后,您的 MCP 客户端配置变为:
json
{
mcpServers: {
safe-docx: {
command: safe-docx,
args: []
}
}
}
使用 command: safe-docx(已安装的二进制文件)而不是 command: npx 可消除每次调用时的安装时网络获取。
始终固定版本
即使使用 npx,您也可以固定版本以防止意外更新:
json
{
mcpServers: {
safe-docx: {
command: npx,
args: [-y, @usejunior/safe-docx@0.9.0]
}
}
}
升级前,请查看变更日志:https://github.com/UseJunior/safe-docx/blob/main/CHANGELOG.md
何时使用此技能
在以下情况下使用 Safe-DOCX:
- - 更改现有 .docx 中的条款或段落
- 插入或删除内容并保留格式
- 为审阅者添加批注或脚注
- 从编辑内容生成修订标记
- 比较两个 .docx 文件生成修订标记
- 提取修订内容为结构化 JSON
- 应用布局格式(间距、行高、单元格内边距)
不适用于从头生成
Safe-DOCX 编辑已有的 .docx 文件——它不会从空白创建文档。对于新文档生成,请使用模板填充工作流程(例如 OpenAgreements)。Safe-DOCX 可以在下游优化生成的文档。
快速入门
- 1. readfile(filepath=~/doc.docx) → 查看段落 + bk* ID
- grep(filepath=~/doc.docx, patterns=[目标短语]) → 查找段落 ID
- replacetext(sessionid, targetparagraphid, oldstring, newstring, instruction)
- save(sessionid, savetolocal_path=~/doc-edited.docx)
核心工作流程:读取、定位、编辑、保存
步骤 1 — 读取。 使用 format: toon(令牌高效表格)调用 readfile 查看段落及其稳定的 bk_* ID。
步骤 2 — 定位。 使用带正则表达式的 grep 查找目标段落。它返回段落 ID 及周围上下文。
步骤 3 — 编辑。 使用 replacetext 交换段落内的文本,或使用 insertparagraph 在锚点前后添加新段落。
步骤 4 — 保存。 调用 save 写入输出。默认为 save_format: both,生成一份干净副本和一份修订标记副本。
容易踩坑的地方
需要唯一匹配
replacetext 需要 oldstring 在目标段落中恰好匹配一个位置。如果文本出现多次,您将得到 MULTIPLEMATCHES。解决方法:在 oldstring 中包含更多周围上下文。
错误:old_string: the Company → 5 个匹配,失败
正确:old_string: the Company shall indemnify → 1 个匹配,成功
脚注标记仅用于显示
readfile 将脚注显示为 [^1]、[^2] 等,但这些标记不是可编辑文本的一部分。您不能通过 replacetext 搜索或替换 [^1]。要修改脚注,请使用专用的 addfootnote、updatefootnote 和 delete_footnote 工具。
超链接为只读
readfile 将链接显示为 text,但您不能通过 replacetext 或 insert_paragraph 创建新的超链接。 标签会从新文本中剥离。编辑周围文本时,现有超链接会被保留。
段落 ID 与会话绑定
bk* 书签 ID 在打开文档时生成,并且绑定到该会话。请勿跨会话存储或重用 ID。始终重新读取文档以获取新的 ID。
智能文本匹配
replace_text 对以下情况具有容错性:
- - 引号变体:直引号 、弯引号 \u201c\u201d、尖引号 \u00ab\u00bb 均可互相匹配
- 空白差异:多个空格、制表符和换行符会被规范化
这意味着您可以从 read_file