How DOCX Editing via XML Surgical Edits Works in DesktopCommanderMCP
DesktopCommanderMCP treats DOCX files as ZIP archives and performs precise string replacements on pretty-printed XML parts, enabling surgical text edits without requiring full document parsing libraries.
DesktopCommanderMCP provides a lightweight approach to Word document manipulation by exposing .docx files as editable ZIP archives containing XML parts. The DocxFileHandler class in src/utils/files/docx.ts implements a surgical editing strategy that allows precise modifications to document content, headers, and footers through literal string replacement rather than complex object models.
Understanding the DOCX File Structure
A DOCX file is essentially a ZIP archive containing multiple XML documents and supporting assets. The primary text content resides in word/document.xml, while headers and footers live in separate relationship-based files like header1.xml and footer2.xml. DesktopCommanderMCP leverages the PizZip library to extract these components, maintaining archive integrity while enabling direct XML manipulation. This architecture allows the system to preserve styles, relationships, and media files untouched while modifying only specific text fragments.
Core Operations in DocxFileHandler
The DocxFileHandler class implements three fundamental operations defined in src/utils/files/docx.ts: reading documents with dual-mode output, performing validated string replacements, and extracting document metadata.
Reading DOCX Files (Outline vs. Raw XML)
The read() method (lines 18-33) operates in two distinct modes based on the offset parameter.
When offset is 0 (default), the handler returns a human-readable outline generated by extractOutline, displaying paragraph text, table rows, headings, and image hints extracted from the <w:body> element. This mode facilitates high-level document comprehension for LLM agents.
When offset exceeds 0 (lines 24-31), the method enters raw XML mode, returning pretty-printed XML paginated line-by-line according to the length parameter. This enables clients to request specific structural sections of document.xml for precise editing.
// Retrieve human-readable outline (offset = 0 default)
const outline = await read_file({
path: "/tmp/report.docx",
});
// Returns structured view of paragraphs, tables, and headings
// Retrieve raw XML starting at line 1
const rawXml = await read_file({
path: "/tmp/report.docx",
offset: 1,
length: 200,
});
// Returns first 200 lines of pretty-printed document.xml
Surgical Editing with editRange
The editRange method (lines 118-128) handles edit_block operations by performing literal string replacements on XML content. The workflow follows this sequence:
- Pretty-print the target XML file using
prettyPrintXmlto ensure deterministic formatting - Count occurrences of
old_stringand validate againstexpected_replacements - Execute
String.replace(or single-instance splice) to substitutenew_string - Compact the modified XML via
compactXmlto remove extra whitespace - Write back to the ZIP entry using
zip.file(targetFile, compacted)
This approach ensures that only the intended XML fragments change while the surrounding document structure remains intact.
Header and Footer Support
When old_string is not found in word/document.xml, the handler automatically scans common header and footer parts (lines 62-75). The system checks header1.xml, footer2.xml, and related relationship files, applying the same replacement logic to these ancillary document parts. This enables the edit_block API to modify running headers and footers without requiring explicit XML file targeting.
The XML Surgical Edit Workflow
The architectural flow through src/utils/files/factory.ts and src/utils/files/docx.ts follows a precise pattern:
- Factory Routing:
getFileHandler()checks file extensions and routes.docxfiles toDocxFileHandlerbefore generic text handlers process the request - Deterministic Preparation: The
prettyPrintXmlfunction normalizes XML formatting to create line-stable output that matches exactly between read and edit operations - Validation and Replacement: The system validates fragment occurrences before executing the surgical edit, then regenerates the ZIP archive preserving all non-modified parts (styles, relationships, media)
Practical Code Examples
Retrieving Document Structure
Request the default outline view to understand document organization before editing:
const outline = await read_file({
path: "/tmp/contract.docx",
});
console.log(outline);
// Output shows hierarchical structure:
// - Heading: Introduction
// - Paragraph: This agreement...
// - Table: [2 rows]
// - Image: [image1.png]
Reading Raw XML for Editing
Access the underlying XML to copy exact fragments for surgical editing:
const xmlFragment = await read_file({
file_path: "/tmp/contract.docx",
offset: 150,
length: 50,
});
// Returns lines 150-200 of pretty-printed document.xml
// <w:t>This is the target text for editing</w:t>
Performing Surgical Edits
Replace exact XML fragments using edit_block with old_string and new_string:
await edit_block({
file_path: "/tmp/contract.docx",
old_string: '<w:t>This is the target text for editing</w:t>',
new_string: '<w:t>This text has been surgically replaced</w:t>',
expected_replacements: 1,
});
Editing Headers and Footers
The same API modifies headers and footers when the target text resides outside the main document body:
await edit_block({
file_path: "/tmp/contract.docx",
old_string: '<w:t>Old Company Name</w:t>',
new_string: '<w:t>Acme Corporation</w:t>',
});
// Automatically finds and updates content in header1.xml if not in document.xml
Creating New DOCX Files
Generate new Word documents from Markdown-style content:
await write_file({
path: "/tmp/new.docx",
content: `
# Executive Summary
## Key Findings
The analysis reveals significant improvements in processing speed.
## Recommendations
Implement the surgical editing approach for all document modifications.
`,
});
// Converts # headings to Word headings and lines to paragraphs
Summary
- DesktopCommanderMCP manipulates DOCX files by treating them as ZIP archives containing XML parts rather than binary blobs
- The
DocxFileHandlerinsrc/utils/files/docx.tsprovides dual-mode reading viaread(): human-readable outlines (offset 0) or raw pretty-printed XML (offset > 0) - Surgical editing uses
prettyPrintXmlto normalize whitespace, executes literal string replacement viaeditRange, and compacts results withcompactXmlbefore repackaging - Header and footer editing occurs automatically when
old_stringis not found in the maindocument.xmlfile - The architecture preserves all non-modified document components (styles, relationships, embedded media) during the editing process
Frequently Asked Questions
What makes XML surgical editing different from traditional DOCX libraries?
Traditional DOCX libraries parse documents into complex object models requiring extensive APIs to navigate and modify content. DesktopCommanderMCP uses direct string replacement on pretty-printed XML fragments, eliminating heavy dependencies while providing LLM-friendly interfaces. This approach treats the document as editable text rather than an object hierarchy, simplifying the mental model for automated editing tasks.
How does DesktopCommanderMCP handle formatting consistency across different DOCX generators?
The handler calls prettyPrintXml before any editing operation to normalize XML formatting into a deterministic, line-stable structure. This standardization ensures that old_string values copied from the raw XML output match exactly with the document's internal representation, regardless of whether the DOCX was generated by Microsoft Word, Google Docs, or LibreOffice.
Can this method modify tables and images within DOCX files?
Table text content is fully editable because it exists as text nodes within <w:t> tags in the XML structure. However, image manipulation requires updating relationship files (/_rels/*.rels) and binary data in the word/media/ directory, which falls outside the scope of string-based surgical edits currently implemented in src/utils/files/docx.ts. The getInfo() method (lines 131-140) can report image counts, but modifying them requires additional binary handling not present in the current XML surgical edit workflow.
Why does the system validate expected_replacements before editing?
The editRange method counts occurrences of old_string in the pretty-printed XML and validates this count against the expected_replacements parameter (default 1). This safety mechanism prevents accidental global replacements that could corrupt document structure. By requiring explicit confirmation of replacement scope, the system ensures surgical precision—modifying only the intended instances while leaving similar text elsewhere in the document untouched.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →