Repository navigation
Getting Started
This server needs Python 3.12 or newer, and it installs two dependencies, lxml and the MCP SDK. It needs no model and no API key, and after installation it makes no network calls. It was tested on Windows, and it has not been tested on Linux or macOS. A clean copy went through these steps on 2026-11-06 with Python 3.12.10, and the output shown came from that run.
git clone https://github.com/dboles99/docx-mcp.git
cd docx-mcp
python -m venv .venv
.venv/bin/pip install -e ".[dev]" # Windows: .venv\Scripts\pip install -e ".[dev]"On Windows, replace .venv/bin/ with .venv\Scripts\ in every command below.
The example builds an invented DOCX in a temporary folder, starts the server as a subprocess, and calls it through the MCP client, so it tests the same path a real client uses.
.venv/bin/python examples/call_over_stdio.pytools: check_docx_term_variants, find_docx_term, get_docx_structure_stats, list_docx_paragraph_range, read_docx_accepted_text, scan_docx_meta_notes
stats: {"comment_count": 0, "file_size_kb": 1.1, "has_tracked_changes": true, "paragraph_count": 4, "tracked_change_paragraph_count": 1, "word_count_approx": 31}
accepted: The pilot covered twelve sites and met its target in the first year.
search for deleted word: 0 hits
variants: {"cyber security": 1, "cybersecurity": 1}
notes: TODO: check the figures before this goes out.
.venv/bin/python -m pytest -q67 passed
Most clients take a block like the one in examples/mcp-client-config.json:
{
"mcpServers": {
"docx": {
"command": "docx-mcp",
"args": []
}
}
}The client must be able to find docx-mcp. If the command is not on its PATH, give the full path to the script inside the virtual environment. With Claude Code:
claude mcp add docx -- docx-mcpBefore connecting a client, note that the server reads any path its process can read. Run it under an account that can reach only what the agent should see.
The document logic works as a plain library, with no server:
from docx_mcp import find_term, read_accepted_text
rows = read_accepted_text("report.docx", limit=20)
hits = find_term("report.docx", r"carbon (tax|levy)")To try this on the sample document, build it first:
.venv/bin/python examples/make_sample_docx.py sample.docxEach row from read_accepted_text carries para_index, text, has_tracked_change, and char_count. On the sample, with min_length=0, the second row reads:
{"para_index": 1, "text": "The pilot covered twelve sites and met its target in the first year.", "has_tracked_change": true, "char_count": 68}A failure in this server is an error and never an empty result, so an agent can tell a wrong path from a clean document. A missing file raises FileNotFoundError in Python and arrives as a readable tool error over MCP. A damaged file raises BadZipFile, a ZIP with no word/document.xml raises ValueError, and a bad pattern raises re.error.
Next, How It Works explains what a tracked change looks like inside the file, and Evidence shows how to check these claims in five minutes.
Designed and authored by Daniel Boles; implemented with coding agents. Apache-2.0.