DocuHand
by H-Mon
README.md
# DocuHand ποΈ
**Give your AI agent hands to operate real Word & WPS documents on Windows.**
DocuHand is a Model Context Protocol (MCP) server that lets AI agents
(Claude Desktop, Hermes, Cursor, any MCP client) actually *drive* Microsoft
Word and WPS Office via COM β not just read docx XML, but automate the real
applications: legacy `.doc` binaries, documents currently open on screen,
and print-fidelity PDF export through the word processor's own layout engine.
Works on **both** Microsoft Word and WPS Office β when Word is absent or
crashes mid-batch, the WPS engine takes over transparently. (WPS support is
believed to be unique among Office MCP servers.)
```bash
uvx docuhand serve
```
Security posture: **zero network code** (audited β see
[THREAT-MODEL.md](THREAT-MODEL.md)): no telemetry, no update checks, a
local JSONL audit log, and an explicit non-goals section.
## Why DocuHand exists
Most Office MCP servers are built on `python-docx` β they manipulate XML in
idealized files. Real-world documents are not idealized:
- 20-year-old `.doc` binaries that XML libraries cannot touch
- Files currently **open and locked** in Word/WPS right now
- WPS Office β the default suite for hundreds of millions of users
- CJK fonts that silently reset when text is replaced (the `NameFarEast` trap)
- Password-protected and corrupt files that pop **modal dialogs** and hang
headless servers
DocuHand drives the real applications, hardened by a year of production use
in government document processing. Every pitfall in
[docs/pitfalls.md](docs/pitfalls.md) cost real debugging time β you get them
pre-solved.
## Tools
| Tool | What it does |
|------|--------------|
| `inspect_document` | Pre-flight health check: real format vs extension, lock state, page/word counts, corruption & password detection, bookmarks, field codes |
| `convert_documents` | Batch `.doc β .docx` for a whole directory in one call, WordβWPS failover, per-file fault isolation, sources never deleted |
| `fill_template` | Bookmarks / `{{placeholders}}` / content controls, CJK fonts protected through save |
| `export_pdf` | Print-fidelity PDF via the real layout engine, optional page range |
| `extract_content` | Text / tables (as JSON grids) / heading outline from legacy `.doc` |
| `edit_open_document` | Edit a document the user **has open right now** β changes appear in their window |
| `merge_documents` | Mail-merge style batch generation: one template Γ N data rows |
Every tool returns structured JSON. Every error carries
`{error_code, human_message, llm_hint}` β errors are data the agent reads to
self-correct, not tracebacks it drowns in.
## Quick start
Install from PyPI:
```bash
# with pip
pip install docuhand
# or with uv (also gives you the `uvx docuhand serve` one-liner)
uv tool install docuhand
```
Requirements: **Windows** with either Microsoft Word or WPS Office installed
(either one is enough β the engine probes `Word.Application` first, then
`KWPS.Application`, overridable with `DOCUHAND_ENGINE=wps|word`).
Add to your MCP client (Claude Desktop example):
```json
{
"mcpServers": {
"docuhand": {
"command": "docuhand",
"args": ["serve"]
}
}
}
```
Then ask your agent: *"Convert every .doc in D:\\Reports to PDF"* β see
[Examples](#examples).
## Examples
**Examples of what to ask your agent**
Batch conversion β one call converts the whole folder:
> "Convert every .doc file in D:\Reports to .docx"
Template fill with CJK font safety β layout and East-Asian fonts survive:
> "Fill D:\Templates\notice.docx with name=Zhang San, amount=426, save it to my desktop"
Edit a document that's open on screen β the agent works in the user's
live Word/WPS window:
> "In the contract I have open right now, replace every 2023 with 2024 β don't save yet"
Mail-merge batch:
> "Generate one offer letter per row in data.json from the offer.docx template"
A synthetic demo document lives in
[examples/demo-files/](examples/demo-files/) (generated by
`scripts/make_demo_docs.py`, no real/personal data), and
[examples/](examples/) has MCP client config snippets.
## Security model (read before granting file access)
- **100% local execution** β your documents never leave your machine
- **No telemetry**, ever
- **Explicit path allowlist** β set `DOCUHAND_ALLOWLIST` to a
`os.pathsep`-separated list of directories; when unset, the fact that you
launched the server yourself is the consent
- **Read-only mode** β set `DOCUHAND_READONLY=1` to block every mutating
tool; only `inspect_document` / `extract_content` / `export_pdf` remain
- **JSONL audit log** β every operation is appended to
`%LOCALAPPDATA%\docuhand\audit.jsonl` (disable: `DOCUHAND_AUDIT=off`,
relocate: `DOCUHAND_AUDIT_PATH`)
- **Pre-COM container gates** β broken/encrypted files are rejected in pure
Python *before* the engine opens them, so a corrupt file can never pop a
modal dialog on your desktop or hang the server (the #1 killer of headless
Office automation)
Environment variables (`DOCUHAND_ENGINE`, `DOCUHAND_ALLOWLIST`,
`DOCUHAND_READONLY`, `DOCUHAND_AUDIT*`, `DOCUHAND_COM_TIMEOUT`) must be
declared in your MCP client's server config β hosts pass stdio servers a
filtered environment.
## Why not just use Copilot in Word / WPS AI?
Those are copilots β they serve the *person sitting in front of the
document*, through a closed, human-driven interface with no public API.
DocuHand is ground crew: it serves *agents working unattended* β batch jobs
at 3 AM, pipelines, any MCP client. Different buyer, different mode of
operation.
**"Why operate legacy .doc files at all?"**
Nobody *chooses* legacy formats. Archives of millions of `.doc` files in
government, healthcare, legal and banking systems are locked by compliance
(retain-original requirements), ecosystem inertia (counterparties still
sending `.doc`), and sheer scale. Converting them *is* one of our tools.
Copilot can't touch them; python-docx can't either. Manual clerical work or
DocuHand β those are the options.
## DocuHand vs. XML-level Office tools
| | python-docx based | DocuHand |
|---|---|---|
| Legacy `.doc` binaries | β | β
(real app required) |
| Open/locked files | β | β
`edit_open_document` |
| WPS Office | β | β
dedicated engine |
| CJK font safety | β οΈ n/a or silent corruption | β
hardened (`NameFarEast` re-assertion) |
| PDF fidelity | β οΈ re-layout | β
print-engine export |
| Corrupt/password files | β οΈ crash or hang | β
pre-COM gates, structured errors |
## Architecture notes
The short version of the six decisions that make this survive real machines
(full rationale in [docs/pitfalls.md](docs/pitfalls.md)):
- **One dedicated STA thread** owns all COM β the asyncio event loop must
never touch COM directly (`RPC_E_WRONG_THREAD`), and one serial queue
means no WINWORD.EXE instance explosion. A stuck call times out and the
thread is abandoned wholesale.
- **Word β WPS failover** β an engine that dies mid-call is discarded and
the next one takes over; probe order is configurable.
- **Errors are structured data** for the calling agent, not stack traces.
- **Safety is registration-time middleware**, not "remember to check".
## Roadmap
- v0.2: `track_changes`, `compare_documents`, protect/unprotect, Excel family
- Pro (separate, later): batch queue/concurrency, service mode, priority support
The free core stays free (MIT).
## Development
```bash
git clone <this repo> && cd docuhand
uv sync
# CI-safe unit tests (no Office needed)
uv run pytest tests/unit
# COM integration tests (local machine with Word/WPS only, never CI)
uv run pytest tests -m com
```
## License
MIT β free core, forever. Pro is a separate commercial license, later.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues