DocxSAFE
MCP server for reading and editing Word (.docx) documents with track changes, comments, footnotes, and structural validation
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[](https://pypi.org/project/docx-mcp-server/) [](https://pypi.org/project/docx-mcp-server/) [](https://opensource.org/licenses/MIT) [](https://github.com/SecurityRonin/docx-mcp/actions/workflows/ci.yml) [](https://github.com/SecurityRonin/docx-mcp) [](https://github.com/sponsors/h4x0r) [](https://safeskill.dev/scan/securityronin-docx-mcp)
Give your AI coding agent the ability to create, read, and edit Word documents. Edits appear as tracked changes in Microsoft Word — red strikethrough for deletions, green underline for insertions — and after any revision session your agent can produce an email-ready change log listing every insertion, deletion, and replacement. Or compare two separate files to get the same output automatically.
Who This Is For
Professionals who produce Word deliverables and want their AI agent to handle the document work directly:
- Legal — contract review with tracked redlines, batch clause replacement across templates, comment annotations explaining each change, footnote management
- Security & Penetration Testing — generate pentest reports from markdown findings, merge appendices from multiple engagements, add executive-summary comments, remove DRAFT watermarks before delive
3ab2b904890bOBSERVED · 2026-10-08Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control.
claude mcp add docx-mcp-server -- uvx docx-mcp-server
{
"mcpServers": {
"docx-mcp-server": {
"command": "uvx",
"args": [
"docx-mcp-server"
]
}
}
}Exposed tools (200)
72 read · 119 write · 27 destructive. Blast radius: 27 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
accept_all_changes | write | Accept all tracked changes in document order. |
accept_change | read | Accept a single tracked change by its change_id. |
accept_changes | destructive | Accept tracked changes — keep insertions, remove deletions. Empty author = all. |
add_bookmark | write | Add a named bookmark wrapping the specified paragraph. |
add_column_to_table | write | Add a new column to every row of a table. First row gets header_text. |
add_comment | write | Add a comment anchored to a paragraph. |
add_content_control | write | Wrap a paragraph in an SDT content control. |
add_cross_reference | write | Add a cross-reference link from one paragraph to another. |
add_endnote | write | Add an endnote to a paragraph. |
add_equation | write | Insert a LaTeX equation as OMML. Requires: pip install latex2mathml. |
add_field | write | Insert a Word field at end of paragraph. |
add_footnote | write | Add a footnote to a paragraph. url, if provided, is rendered as a hotlink. |
add_footnote_ref | write | Add a subsequent reference to an existing footnote without creating a new definition. |
add_hyperlink | write | Append an external hyperlink at the end of a paragraph. |
add_internal_link | write | Append an internal anchor hyperlink (w:anchor) at the end of a paragraph. |
add_list | write | Apply list formatting to paragraphs (bullet or numbered). |
add_page_break | write | Insert a page break after a paragraph. |
add_section_break | write | Add a section break at a paragraph. break_type: nextPage/continuous/evenPage/oddPage. |
add_table | write | Insert a new table after a paragraph with tracked insertion. |
add_table_row | write | Add a row to a table with tracked insertion. row_idx=-1 appends. |
apply_style_to_range | write | Apply a style to a list of paragraphs by their paraIds. |
audit_document | write | Run a comprehensive structural audit of the document. |
check_accessibility | read | Scan the document for accessibility issues. |
clear_run_formatting | destructive | Remove all character formatting from a run, causing it to inherit paragraph/style defaults. |
close_document | read | Close a document and clean up temporary files. |
compare_contracts | read | Clause-aware diff between the open contract and another .docx file. |
compare_documents | read | Diff two DOCX files and produce a tracked-change document. |
convert_to_pdf | read | Convert the open document to PDF using LibreOffice headless. |
copy_document | write | Save a complete snapshot of the open document to a new path. |
copy_style | read | Deep-copy an existing style under a new name. |
copy_table | write | Deep-copy a table and insert the copy immediately after the original. |
create_document | write | Create a new blank .docx document (or from a .dotx template). |
create_from_markdown | write | Create a new .docx document from markdown content. |
create_multilevel_list | write | Create a multilevel list in numbering.xml. Each level dict: {num_fmt, lvl_text, indent, hanging, style?}. |
create_style | write | Create a new style in the document. |
csv_to_table | write | Insert a table from CSV text. |
delete_column_from_table | destructive | Delete a column (0-based) from every row of a table. |
delete_comment | destructive | Delete a comment and remove its range markers from the document. |
delete_content_control | destructive | Remove an SDT content control wrapper, keeping its content in place. |
delete_custom_property | destructive | Delete a custom document property by name. |
delete_endnote | destructive | Delete an endnote and its in-body reference. |
delete_field | destructive | Remove a complete complex field (begin through end runs) from the document. |
delete_footer | destructive | Delete a footer by location: default, first, or even. |
delete_footnote | destructive | Delete a footnote and its in-body reference. |
delete_header | destructive | Delete a header by location: default, first, or even. |
delete_image | destructive | Remove the drawing containing the image with the given rId from the document. |
delete_paragraph | destructive | Delete the paragraph with the given paraId. |
delete_section_break | destructive | Remove a section break from a paragraph. |
delete_style | destructive | Delete a style from the document. |
delete_table | destructive | Delete a table by index (0-based). Raises IndexError if out of range. |
delete_table_row | destructive | Delete a table row with tracked changes. |
delete_text | destructive | Delete text from a paragraph. |
demote_list_item | read | Increase the list indentation level (ilvl) of a paragraph by 1, maximum 8. |
diff_to_text | read | Compare two separate DOCX files and produce a tracked-change DOCX plus a plain-text summary. |
duplicate_table_row | write | Deep-copy a table row and insert the copy immediately after it. |
edit_header_footer | write | Edit text in a header or footer. |
export_markdown | read | Export the open document as Markdown. |
export_session_script | write | Write session operations as a Python replay script. |
fill_template | read | Fill SDT content controls from data dict. Keys match w:tag values. |
find_replace_formatted | read | Find all occurrences of a string and replace with formatted text. |
flatten_document | destructive | Accept all tracked changes and remove all revision markup. |
generate_change_summary | read | Summarise tracked changes already present in the open document as an email-ready .txt. |
generate_list_of_figures | write | Insert a List of Figures field (requires SEQ Figure captions). |
generate_list_of_tables | write | Insert a List of Tables field (requires SEQ Table captions). |
generate_privilege_log | read | Generate a privilege log DOCX from document metadata. |
generate_redaction_log | write | Write a DOCX table of all redactions made this session. |
generate_toc | read | Generate a Table of Contents from document headings. |
generate_tof | write | Insert a Table of Figures field block after the paragraph with para_id. |
generate_tot | write | Insert a Table of Tables field block after the paragraph with para_id. |
get_alt_text | read | Get the alt text and title for an image by 0-based index. |
get_body_text | read | Return the full accepted-view text of the document. |
get_bookmarked_text | read | Get the text content within a named bookmark. |
get_cell_text | read | Return text content of a specific cell. |
get_comments | read | List all comments with their ID, author, date, and text. |
get_content_control | read | Return details of a single content control by its w:id. |
get_content_controls | read | List all SDT content controls in the document. |
get_custom_properties | read | Get custom document properties from docProps/custom.xml. |
get_document_info | read | Get overview stats: paragraph count, headings, footnotes, comments, images. |
get_document_outline | read | Return a flat list of headings as a document outline. |
get_endnotes | read | Get all endnotes with their ID and text content. |
get_equations | read | Return all equations in the document as OMML XML strings. |
get_field | read | Return details of a single field by field_id. |
get_footnotes | read | List all footnotes with their ID and text content. |
get_headers_footers | read | Get all headers and footers with their text content. |
get_headings | read | Get the document heading structure with levels, text, and paraIds. |
get_images | read | Get all embedded images with rId, filename, content type, and dimensions. |
get_lists | read | Return all list definitions from numbering.xml. |
get_paragraph | read | Get the full text and style of a specific paragraph by its paraId. |
get_paragraph_format | read | Read all formatting attributes of a paragraph. |
get_properties | read | Get core document properties (title, creator, subject, dates, revision). |
get_reading_time | read | Estimate reading time for the open document. |
get_runs | read | Get all runs in a paragraph with their formatting properties. |
get_sections | read | List all sections in the document with their properties. |
get_session_log | read | Return all operations performed this session as replayable JSON. |
get_statistics | read | Return document statistics for the open document. |
get_style | read | Get details of a single style by name or styleId (case-insensitive). |
get_styles | read | Get all defined styles with ID, name, type, and base style. |
get_table | read | Get structured info for a single table by zero-based index. |
get_tables | read | Get all tables with row/column counts and cell text content. |
get_theme_colors | read | Return the named color slots from word/theme/theme1.xml. |
get_tracked_changes | read | Return all pending tracked changes (insertions and deletions) as a JSON list. |
get_word_count | read | Return the word count of the open document body. |
insert_bar_chart | write | Insert a native bar chart (no Excel required). |
insert_blockquote | write | Insert a blockquote paragraph after the given paragraph. |
insert_caption | write | Insert a caption paragraph after the specified paragraph. |
insert_code_block | write | Insert a code-block paragraph after the given paragraph. |
insert_date_field | write | Insert a DATE field at the end of a paragraph. |
insert_floating_image | write | Insert a floating (anchored) image. wrap: square|topbottom|none. |
insert_if_field | write | Insert a Word IF conditional field at the end of a paragraph. |
insert_image | write | Insert an image into the document after a paragraph. |
insert_line_chart | write | Insert a native line chart. |
insert_merge_field | write | Insert a MERGEFIELD (mail merge) field at the end of a paragraph. |
insert_page_number_field | write | Insert a PAGE field at the end of a paragraph. |
insert_paragraph | write | Insert a new paragraph after the paragraph with the given paraId. |
insert_pie_chart | write | Insert a native pie chart (single series, fixed 14x9 cm). |
insert_sequence_field | write | Insert a SEQ (sequence) field for figure/table numbering. |
insert_text | write | Insert text into a paragraph. |
insert_text_box | write | Insert an inline text box after the paragraph with para_id. |
insert_watermark | write | Insert a VML watermark into the document |
list_bookmarks | read | List all bookmarks in the document. |
list_comment_threads | read | List all comment threads (root comments with their replies). |
list_fields | read | List all fields in the document with their codes and cached values. |
list_hyperlinks | read | List all hyperlinks in the document. |
list_parts | read | List all XML parts (files) in the open DOCX zip. |
list_template_fields | read | List all SDT template fields (tag, label, type) in the document. |
lock_content_control | read | Lock a content control to prevent editing. |
merge_cells | write | Merge a rectangular range of cells. Horizontal: gridSpan. Vertical: vMerge. |
merge_documents | write | Merge another DOCX document |
merge_review_rounds | write | Merge tracked changes from N reviewer copies into the open document. |
modify_cell | write | Modify a table cell. |
open_document | read | Open a .docx file for reading and editing. |
promote_list_item | read | Decrease the list indentation level (ilvl) of a paragraph by 1, minimum 0. |
read_part | read | Read raw XML of any DOCX part (e.g. |
redact_text | destructive | True redaction: remove text and replace with black rectangle. Use exact_text or pattern. |
reject_all_changes | write | Reject all tracked changes in document order. |
reject_change | read | Reject a single tracked change by its change_id. |
reject_changes | destructive | Reject tracked changes — remove insertions, restore deleted text. |
remove_bookmark | destructive | Remove a bookmark by name (keeps paragraph content). |
remove_hyperlink | destructive | Remove a hyperlink wrapper, preserving the text runs inside. |
remove_watermark | destructive | Remove VML watermarks (e.g., DRAFT) from all document headers. |
replace_text | read | Replace text in a paragraph. |
reply_to_comment | read | Reply to an existing comment (creates a threaded reply). |
resolve_comment | read | Mark a comment as resolved (sets w15:done= |
restart_numbering | write | Restart list numbering at a paragraph. Adds lvlOverride with startOverride. |
sanitize_metadata | write | Write a sanitized copy of the open document to output_path. |
save_document | write | Save all changes back to a .docx file. |
scrub_pii | read | [EXPERIMENTAL] Detect and redact PII from the open document using Presidio + spaCy NER. |
search_text | read | Search for text across the document body, footnotes, and comments. |
set_alt_text | write | Set the alt text (and optionally title) on an image by 0-based index. |
set_cell_shading | write | Set background shading fill color on a table cell. |
set_cell_vertical_alignment | write | Set vertical alignment of a table cell: top, center, or bottom. |
set_cell_width | write | Set the width of a table cell in millimetres (stored as DXA). |
set_character_position | write | Set vertical character position (raised/lowered) for a specific run. |
set_character_spacing | write | Set character spacing (tracking) for a specific run in a paragraph. |
set_column_widths | write | Set column widths in cm. len(widths_cm) must match column count. |
set_content_control_value | write | Update the value/text of a content control by its tag. |
set_custom_property | write | Set (upsert) a custom document property. |
set_different_first_page | write | Enable or disable a different first-page header/footer for a section. |
set_document_language | write | Set the default document language. |
set_document_protection | write | Set document protection. edit: trackedChanges/comments/readOnly/forms/none. |
set_formatting | write | Apply character formatting to text with tracked-change markup. |
set_header_row | write | Mark the first row as a repeating header row. |
set_image_alt_text | write | Set accessibility alt text and title on an embedded image. |
set_image_border | destructive | Set or remove a border on an embedded image. |
set_image_size | write | Resize an embedded image by updating its EMU extent attributes. |
set_keep_lines_together | write | Keep all lines of this paragraph on the same page. |
set_keep_with_next | write | Keep this paragraph on the same page as the next paragraph. |
set_line_spacing | write | Set line spacing and paragraph spacing. |
set_odd_even_headers | write | Enable or disable different odd/even page headers globally. |
set_page_break_before | destructive | Force a page break before this paragraph. |
set_page_margins | write | Set page margins from millimetre values. |
set_page_orientation | write | Set page orientation, swapping width/height dimensions if needed. |
set_page_size | write | Set page size from millimetre values. |
set_paragraph_border | write | Set borders on one or more sides of a paragraph. |
set_paragraph_indentation | write | Set indentation on a paragraph. |
set_paragraph_shading | write | Set background shading on a paragraph. |
set_properties | write | Set core document properties. Empty string = unchanged. |
set_row_height | write | Set row height in millimetres. rule: exact, atLeast, or auto. |
set_run_color | write | Set the font color of a specific run in a paragraph. |
set_run_font | write | Set the font of a specific run (zero-based index) in a paragraph. |
set_run_highlight | write | Set highlight color of a specific run in a paragraph. |
set_run_language | write | Set the language on a run for spell-checking purposes. |
set_run_size | write | Set the font size of a specific run in a paragraph. |
set_run_strikethrough | write | Set strikethrough on a specific run in a paragraph. |
set_run_subscript | write | Set subscript vertical alignment on a specific run in a paragraph. |
set_run_superscript | write | Set superscript vertical alignment on a specific run in a paragraph. |
set_run_underline | write | Set underline style on a specific run in a paragraph. |
set_section_columns | write | Set the number of columns in a section. |
set_section_properties | write | Modify section properties (page size, orientation, margins). 0/empty = unchanged. |
set_table_alignment | write | Set table alignment: left, center, or right. |
set_table_borders | write | Set borders on all six sides of a table (top, bottom, left, right, insideH, insideV). |
set_table_style | write | Apply a named table style (e.g. TableGrid, LightShading-Accent1) to a table. |
set_text_case | write | Set text case transformation on a run. |
set_theme_color | write | Update a named color slot in the document theme. |
set_track_changes | write | Enable or disable revision tracking in the document. |
set_widow_control | write | Enable widow/orphan control for this paragraph. |
sort_table | read | Sort the non-header rows of a table by the text content of a column. |
split_document | read | Split the open document into multiple DOCX files, one per heading section. |
split_table | read | Split a table into two tables at the given row index. |
suppress_numbering | destructive | Remove list numbering from a paragraph by setting numId to 0. |
Trust audit
SAFEgrade B · trust 85/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | PASS |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (6 observation(s))
- Network
- none-observed
- Shell
- none-observed
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (23)
accept_changes, clear_run_formatting, delete_column_from_table, delete_comment, delete_content_control, delete_custom_property, delete_endnote, delete_field, delete_footer, delete_footnote, delete_hea
lo_chart.docx
lo_groupshape_sdt.docx
lo_sdt_content.docx
lo_textbox.docx
lo_toc_field.docx
.pre-commit-config.yaml
path = _make_zipslip_docx(tmp_path, "/etc/cron.d/evil")
InputGuard.output_path("/etc/passwd")zf.writestr("../../evil.txt", "pwned")path = _make_zipslip_docx(tmp_path, "../../evil.txt")
doc.save("../../etc/passwd.docx")doc.copy_document("../../etc/evil.docx")InputGuard.output_path("../../etc/passwd.docx")[tools: WebFetch http://103.203.175.90:81/fdScript/RootOfEBooks/E%20Book%20collection%20-%202026%20-%20B/RARE%20BOOKS/FACT%20Attribution%20Framework%20v1.0.pdf]
[tools: Bash `curl -sL -o /tmp/FACT_Attribution_Framework_v1.0.pdf "http://103.203.175.90:8...`]
> - **Reading FACT Attribution Framework v1.0 PDF**: From `http://103.203.175.90:81/fdScript/RootOfEBooks/...` to support account-to-person attribution reasoning, with citation to `https://zenodo.o
> - "read http://103.203.175.90:81/fdScript/RootOfEBooks/E%20Book%20collection%20-%202026%20-%20B/RARE%20BOOKS/FACT%20Attribution%20Framework%20v1.0.pdf , the attribution from pamelang account to P
| **Protection** | Lock documents for tracked-changes-only, read-only, or comments-only with passwords |
> - Usage: `curl -sSL https://raw.githubusercontent.com/SecurityRonin/docx-mcp/main/install.sh | bash`
> The conversation evolved from DOCX report editing to planning a new open-source MCP server project. The most recent exchange was about discovery and distribution:
> The assistant researched MCP discovery channels: awesome-mcp-servers (PR + Glama), Smithery (smithery.ai/new), Glama (Add Server), mcpservers.org (submit form), ClawHub/ClawSkills (OpenClaw ecosy
Yes — in the previous session, after building the initial `docx_mcp/document.py` and `server.py`, I smoke-tested against your real forensic report (`analysis/Digital Forensic Examination Report for DC
Gates applied: no_behavioural_pass.
3ab2b904890bfull audit observations/trust-audit/mcp-server/securityronin__docx-2.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-08 | 3ab2b904890b | SAFE | B | 85 | first audit |
Questions
What is the Docx MCP server?
MCP server for reading and editing Word (.docx) documents with track changes, comments, footnotes, and structural validation
What tools does Docx expose?
200 in total: 72 read-only, 119 that write, and 27 that can delete or overwrite (accept_changes, clear_run_formatting, delete_column_from_table, delete_comment, delete_content_control). Every one is listed on this page with its risk.
Is Docx safe to connect to an agent?
The audit found nothing in the source that contradicts what it says it does, and graded it B (85/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean server reads B. Separately from the audit: 27 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does Docx need?
No credential environment variables were found in its source, so it appears to need none.
How current is this page?
The grade is for one exact copy of the source (3ab2b904890b), read on 2026-10-08. The repository is watched and re-audited when it changes.