Skip to main content
ClaudeWave

Deterministic tool for AI agents to edit Word documents: every change a tracked change the writer can reject.

MCP ServersRegistry oficial0 estrellas0 forks● PythonApache-2.0Actualizado today
ClaudeWave Trust Score
95/100
✓ Verified
Passed
  • ✓Open-source license (Apache-2.0)
  • ✓Actively maintained (<30d)
  • ✓Clear description
  • ✓Topics declared
  • ✓Documented (README)
Last scanned: 10/15/2026
Install in Claude Code / Claude Desktop
Method: UVX (Python) · doc-control
Claude Code CLI
claude mcp add doc-control -- uvx doc-control
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "doc-control": {
      "command": "uvx",
      "args": ["doc-control"]
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
Casos de uso

Resumen de MCP Servers

# <img src="https://raw.githubusercontent.com/nuncaeslupus/doc-control/main/docs/logo.png" width="40" height="40" alt="" align="top"> doc-control

<!-- mcp-name: io.github.nuncaeslupus/doc-control -->

<!-- claude-arsenal:attribution: added by claude-arsenal's /init. Delete this block to drop it (it is not put back), or set `attribution = false` in the arsenal config.toml. -->
[![Built with claude-arsenal](https://img.shields.io/badge/built%20with-claude--arsenal-d97756)](https://github.com/nuncaeslupus/claude-arsenal)
<!-- /claude-arsenal:attribution -->

<p align="center">
  <img src="https://raw.githubusercontent.com/nuncaeslupus/doc-control/main/docs/hero.png" width="100%" alt="doc-control: an agent sends one JSON batch that replaces a word and adds a comment; the open Word page shows the replacement as a tracked deletion and insertion with Accept and Reject buttons, and the comment in a margin balloon">
</p>

> Status: **file engine working** (pre-1.0; the API may still change). The live engine
> drives LibreOffice Writer and Microsoft Word (Windows). See `status/specification.md` and `status/plan.md`.

A deterministic tool that lets AI agents work on Word documents quickly,
precisely and safely, ideally live in the Word window the writer has open.
Every content change is a tracked change the writer can accept or reject.

For anyone — writers and editors first — who wants an AI agent's help inside a
Word document without a single silent change.

## Usage

Install with `pip install doc-control` (or run it without installing: `uvx doc-control`).
Python 3.11+, no other dependencies. To drive the Word that is open on Windows, install
`doc-control[live]` (it adds pywin32); LibreOffice needs no extra package.

Command line, JSON in and JSON out:

```bash
doc-control outline --json '{"doc": "Novela.docx"}'
doc-control find --json '{"doc": "Novela.docx", "query": "lluvia"}'
doc-control batch --json '{"doc": "Novela.docx", "ops": [
  {"op": "text.replace", "at": "p12#a7b2a7b2:4-10", "text": "nieve"},
  {"op": "comment.add", "at": "p40#c0ffee00", "text": "¿Seguro?"}]}'
doc-control help batch          # the JSON Schema of any operation
```

Every write is a tracked change by `DOC_CONTROL_AUTHOR` (default `Claude`), made after a
backup and verified, with `undo` and `history.*` to go back. Addresses like
`p12#a7b2a7b2` come from read results and fail loudly if the paragraph changed.

From Python, a document can be held open for many reads, with whole results:

```python
from doc_control import api

with api.open("Novela.docx") as doc:
    for p in doc.paragraphs(normalized=True, pages=True):
        print(p["at"], p["style_name"], p["page"], p["text"][:40])
    chapters = doc.run("segment", {"unit": "chapters"})["chapters"]
```

Recipes propose batches of fixes (Spanish typography, quotes, dashes, spacing, empty
paragraphs and more): `recipe.list`, then `recipe.run` returns a batch to review and apply.

### Notes, headers, footers and tables

Reads cover the body only unless asked; `stories` opts in to the rest (`"notes"` for
footnotes and endnotes, `"headers"` for headers and footers) on `paragraphs.list`,
`find`, `locate`, `para.get`, `outline`, `stats` and `revisions.list`. Their paragraphs
carry an address with a prefix (`fn3/p1#0c9e0c9e`, `en2/…`, `hdr1.default/…`,
`ftr1.first/…`) that the edit operations accept, so a tracked edit inside a footnote or a
running header works like one in the body. A body read stays as fast as before.

```bash
doc-control paragraphs.list --json '{"doc": "Tesis.docx", "stories": ["body", "notes"]}'
doc-control text.replace --json '{"doc": "Tesis.docx", "at": "fn3/p1#0c9e0c9e:4-10", "text": "2019"}'
doc-control note.add --json '{"doc": "Tesis.docx", "at": "p40#c0ffee00:17", "kind": "footnote", "text": "Ver el cap. 2."}'
doc-control sections.list --json '{"doc": "Tesis.docx"}'
doc-control table.get --json '{"doc": "Tesis.docx", "table": 1}'
doc-control table.row.insert --json '{"doc": "Tesis.docx", "table": 1, "after_row": 2, "cells": ["a", "b"]}'
doc-control table.row.delete --json '{"doc": "Tesis.docx", "table": 1, "row": 4}'
```

`note.add` inserts the reference mark and the note as tracked insertions (rejecting them
removes both); the row operations write tracked row insertions and deletions. All of it is
backed up, verified and undoable like any other write. `scripts/real_word_stories.py`
checks it in real Word (see [docs/real-word-check.md](docs/real-word-check.md)).

### Page layout: front matter, numbering, headers and fields

`layout.get` returns the document's page plan: per section where it starts (`from`), its
break, its page numbering and its header and footer text per kind (`default`, `first`,
`even`; `null` inherits the previous section's). `layout.apply` takes a plan in the same
shape and brings the document to it. This one gives a novel an unnumbered title page,
then starts chapter 1 on a right-hand page numbered 1, with the chapter title in the odd
headers and the book title in the even ones:

```bash
doc-control layout.get --json '{"doc": "Novela.docx"}'
doc-control layout.apply --json '{"doc": "Novela.docx", "untracked": true, "plan": {
  "version": 1, "two_sided": true, "mirror_margins": true,
  "sections": [
    {"from": "p1#ea7412aa", "break": "nextPage",
     "numbering": {"shown": false, "start": 1, "format": "lowerRoman"},
     "header": {"default": "", "even": ""}, "footer": {"default": "", "even": ""}},
    {"from": "p2#5fac7aad", "break": "oddPage",
     "numbering": {"shown": true, "start": 1, "format": "decimal"},
     "header": {"default": "{chapter}", "even": "La casa del río"},
     "footer": {"default": "{PAGE}", "even": "{PAGE}"}}]}}'
```

Each `from` is the address of the paragraph the section starts at (from `outline` or
`paragraphs.list`). `{PAGE}`, `{NUMPAGES}` and `{chapter}` (the current Heading 1) become
fields. Keys left out stay as they are. Breaks and numbering go in as tracked changes;
a new header or footer part and the two-sided and mirror settings cannot be tracked in
Word, so the plan needs `untracked: true` (without it the answer names what needs it).
Run it with `"dry_run": true` first to see the changes; nothing is written unless the
plan read back from the result equals the request. A new section break adds a paragraph
to carry it, so the addresses after it renumber: read them again with `layout.get`.

Fields: `fields.list` shows every field (TOC, PAGE, SEQ, REF, citations) and whether its
result is stale; `toc.insert`, `caption.add`, `xref.add`, `index.mark` and
`index.insert` add them as tracked insertions; `fields.update` refreshes the TOC, page,
sequence and reference results through headless LibreOffice (`ENGINE_UNAVAILABLE`
without it; `set_update_on_open` asks Word to refresh them on open instead). An index is
built by Word (F9); citation fields are never changed. `scripts/real_word_layout.py` checks the
result in real Word (see [docs/real-word-check.md](docs/real-word-check.md)).

### Live: the document the writer has open

With LibreOffice Writer installed, the same front doors work on the open window: the
writer sees each comment and tracked change appear, and saves when they choose.

```bash
doc-control live.open --json '{"doc": "Novela.docx"}'
doc-control live.select --json '{"doc": "Novela.docx", "find_phrase": "lluvia fina"}'
doc-control batch --json '{"doc": "Novela.docx", "engine": "live", "ops": [
  {"op": "comment.add", "at": "p40#c0ffee00", "text": "¿Seguro?"}]}'
doc-control live.close --json '{"doc": "Novela.docx", "save": true}'
```

Live `batch` takes `comment.add`, `text.replace` and `para.insert`; anything else, or a
machine with no app to drive, answers `ENGINE_UNAVAILABLE` with the reason
(`live.status` lists the apps found). LibreOffice needs a Python its own bridge was
built for: the system Python with `python3-uno` for a distribution's package, the
Python version the snap bundles for the snap (`live.status` names it). Closing never
drops unsaved work: a changed document needs `save` or `discard`.

References: [operations](docs/operations.md) · [errors](docs/errors.md).

## Planned shape

- **One core, two engines, one API**
  - *File engine*: edits a closed `.docx` with the Python standard library only,
    rewriting only the parts it touches. Read operations also take a `.txt`, `.md` or
    `.odt` file (hard-wrapped text detected; Markdown `#` headings and OpenDocument
    headings become Heading styles); writes refuse it.
  - *Live engine*: controls the open document (LibreOffice Writer, and Word on
    Windows over COM; Mac later).
- **Two front doors**: a CLI with JSON in/out, and an MCP server
  (`doc-control mcp`, stdio) for Claude Desktop / Cowork and other MCP clients.
- **Safety first**: lock-file and on-disk change detection, backup before every
  write, verification, automatic restore, operation log with undo, and
  `unintended_changes == 0` as a gate.
- **No AI inside.** Judgment belongs to the agent; approval belongs to the writer.

It will replace `docx-fixer`, whose rules become packs built on this tool, and
serve `literary-critic` as its first downstream consumer.

## MCP server

`doc-control mcp` serves every operation as an MCP tool over stdio, one tool per
operation (`para.move` becomes `para_move`), with the same JSON Schemas and the
same response envelope as the CLI. It needs nothing beyond the package itself:

```json
{
  "mcpServers": {
    "doc-control": { "command": "uvx", "args": ["doc-control", "mcp"] }
  }
}
```

To drive the Word a writer has open on Windows, the server needs the `live` extra:
`"args": ["--from", "doc-control[live]", "doc-control", "mcp"]`.

## Documents

- [Operation reference](docs/operations.md) and [error reference](docs/errors.md), generated from the code
- [Initial research: tooling and risks](docs/research/01-tooling-and-risks.md)

## Development

This repo uses [claude-arsenal](https://github.com/nuncaeslupus/claude-arsenal)
(spec-driven workflow, g
ai-agentsclaudeclaude-codedocument-automationdocxllm-toolsmcpmcp-servermicrosoft-wordooxmlpythontracked-changes

Lo que la gente pregunta sobre doc-control

¿Qué es nuncaeslupus/doc-control?

+

nuncaeslupus/doc-control es mcp servers para el ecosistema de Claude AI. Deterministic tool for AI agents to edit Word documents: every change a tracked change the writer can reject. Tiene 0 estrellas en GitHub y su última actualización registrada es del 2026-10-15.

¿Cómo se instala doc-control?

+

Puedes instalar doc-control clonando el repositorio (https://github.com/nuncaeslupus/doc-control) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.

¿Es seguro usar nuncaeslupus/doc-control?

+

Nuestro agente de seguridad ha analizado nuncaeslupus/doc-control y le ha asignado un Trust Score de 95/100 (tier: Verified). Revisa el desglose completo de comprobaciones superadas y flags en esta página.

¿Quién mantiene nuncaeslupus/doc-control?

+

nuncaeslupus/doc-control es mantenido por nuncaeslupus. La última actividad registrada en GitHub es del 2026-10-15, con 24 issues abiertos.

¿Hay alternativas a doc-control?

+

Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.

Despliega doc-control en tu cloud

Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.

¿Mantienes este repo? Añade un badge a tu README

Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.

Featured on ClaudeWave: nuncaeslupus/doc-control
[![Featured on ClaudeWave](https://claudewave.com/api/badge/nuncaeslupus-doc-control)](https://claudewave.com/repo/nuncaeslupus-doc-control)
<a href="https://claudewave.com/repo/nuncaeslupus-doc-control"><img src="https://claudewave.com/api/badge/nuncaeslupus-doc-control" alt="Featured on ClaudeWave: nuncaeslupus/doc-control" width="320" height="64" /></a>

Más MCP Servers

Alternativas a doc-control