Skip to main content
Glama

docx-mcp

Legal document redlining engine. Takes AI-generated changes (structured JSON) and applies them as professional tracked changes with comments inside .docx files. The output is indistinguishable from what a lawyer would produce in Microsoft Word -- proper w:ins/w:del markup, comment annotations with justification text, and preserved formatting.

Installation

Requires Python 3.14+.

uv sync

Related MCP server: word-agent-mcp

Quick start

Python API

from docx_mcp import (
    ParagraphChange, ParagraphChangeType,
    TableChange, TableChangeType,
    RedlineConfig, apply_redlines,
)

changes = [
    # Modify a body paragraph
    ParagraphChange(
        kind="paragraph",
        fragment_id="3",              # ← str (was int in v0.1.0)
        change_type=ParagraphChangeType.MODIFY,
        new_text="The Company **shall** provide written notice.",
        justification="Strengthened obligation language.",
    ),
    # Delete a paragraph
    ParagraphChange(
        kind="paragraph",
        fragment_id="5",
        change_type=ParagraphChangeType.DELETE,
        justification="Removed redundant clause.",
    ),
    # Append a new paragraph
    ParagraphChange(
        kind="paragraph",
        fragment_id="7",
        change_type=ParagraphChangeType.APPEND_AFTER,
        new_text="The foregoing shall survive termination.",
        justification="Added survival provision.",
    ),
    # Modify a header paragraph
    ParagraphChange(
        kind="paragraph",
        fragment_id="header_1.1",
        change_type=ParagraphChangeType.MODIFY,
        new_text="CONFIDENTIAL",
        justification="Updated header text.",
    ),
    # Modify a table cell
    TableChange(
        kind="table",
        table_id=2,
        row=1,
        col=1,
        change_type=TableChangeType.MODIFY_CELL,
        new_text="Updated **cell** content",
        justification="Corrected table entry.",
    ),
    # Clear a table cell
    TableChange(
        kind="table",
        table_id=2,
        row=3,
        col=2,
        change_type=TableChangeType.CLEAR_CELL,
        justification="Removed obsolete data.",
    ),
]

doc = apply_redlines("contract.docx", changes)
doc.save("contract_redlined.docx")

CLI

# Extract fragment text from a document
docx-mcp convert input.docx
docx-mcp convert input.docx --format json

# Apply changes
docx-mcp apply input.docx changes.json -o output.docx

# Validate a redlined document
docx-mcp validate output.docx

# Audit a document for structural issues
docx-mcp audit input.docx
docx-mcp audit input.docx --format json

Note: The CLI convert command extracts body content only (no headers, footers, or tables). For full-document extraction, use the MCP extract_fragments tool or the Python full_to_fragments() function.

MCP server

The library includes an MCP server so that LLM clients (Claude Desktop, Cursor, etc.) can redline .docx files directly.

# Start the server (stdio transport)
docx-mcp-server

Configure in Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "docx-mcp": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/docx-mcp", "docx-mcp-server"]
    }
  }
}

Configure in Cursor (.cursor/mcp.json):

{
  "mcpServers": {
    "docx-mcp": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/docx-mcp", "docx-mcp-server"]
    }
  }
}

Tools

Tool

Description

extract_fragments

Read a .docx and return paragraphs, tables, headers, and footers as tagged text

apply_changes

Apply tracked changes from an inline list and save

apply_changes_from_file

Apply tracked changes from a JSON file on disk

validate_document_tool

Run structural validation checks

diff_fragments

Compare two .docx files paragraph-by-paragraph (full document)

audit_document_tool

Audit a .docx for headers, images, tables, section breaks, and more

Resource

URI

Description

docx-fragments://{document_path}

Browse paragraph fragments (URL-encode the path)

Example workflow

An LLM client would typically:

  1. Call extract_fragments to read the document and get fragment IDs.

  2. Reason about the content and construct a list of changes.

  3. Call apply_changes with the change list to produce a redlined document.

  4. Optionally call diff_fragments to compare original vs. redlined output.

Concepts

Fragments

Documents are decomposed into fragments: paragraphs, tables, headers, and footers, all indexed in document order. Each fragment has a string ID.

Fragment IDs:

Pattern

Meaning

Example

"1", "2", …

Body paragraphs / tables

<f=1>Introduction.</f=1>

"header_P.I"

Header part P, paragraph I

<f=header_1.3>Confidential</f=header_1.3>

"footer_P.I"

Footer part P, paragraph I

<f=footer_2.1>Page 1 of 10</f=footer_2.1>

Tables and body paragraphs share the same ID space (they interleave in document order). Fragment "3" might be a table and fragment "4" a paragraph.

Use extract_fragments (MCP) or full_to_fragments() (Python) to see the fragment map for any document:

<f=1>Introduction paragraph.</f=1>
<f=2>**Definitions.** The following terms shall apply.</f=2>
<table=3 rows=2 cols=3>
<cell=3.1.1 span="2">Merged Header</cell=3.1.1>
<cell=3.1.3>Header C</cell=3.1.3>
<cell=3.2.1>Data 1</cell=3.2.1>
<cell=3.2.2>Data 2</cell=3.2.2>
<cell=3.2.3>Data 3</cell=3.2.3>
</table=3>
<f=4>Closing paragraph. See [Section 2](https://example.com).</f=4>
<f=header_1.1>Confidential</f=header_1.1>
<f=footer_1.1>Page 1 of 10</f=footer_1.1>

Tables

Simple tables

Simple (rectangular) tables are extracted as <table=N> blocks. Each cell has a cell_id in "table_id.row.col" format (e.g., "3.1.2").

Merged-cell tables

Tables with horizontally or vertically merged cells (gridSpan / vMerge) are now supported. Merge spans are shown as attributes:

  • span="2" — cell spans 2 columns (horizontal merge)

  • vspan="3" — cell spans 3 rows (vertical merge)

Spanned-over cells (positions covered by a merge) are omitted from output. For example, if cell=3.1.1 has span="2", then cell=3.1.2 does not appear.

When targeting merged cells with changes, always target the originating cell (the one with the span/vspan attribute). Targeting a spanned-over position raises a ValueError.

Skipped tables

Tables that cannot be processed (nested tables, malformed merges, tables inside headers/footers) appear as:

<table=5 skipped reason="table 5, cell 2.3 contains nested table"/>

Headers and footers

Header and footer paragraphs are extracted with prefixed fragment IDs: header_1.1, footer_2.1, etc. The first number is the 1-based part index (usually 1 for the default header/footer), the second is the 1-based paragraph index within that part.

Header/footer paragraphs can be modified, deleted, and appended to just like body paragraphs. Tables inside headers/footers are not editable and are reported as skipped elements.

Limitation: Comments on header/footer changes are not attached to the output (Word and LibreOffice do not support comment ranges in those parts). They trigger a UserWarning and are dropped.

Hyperlinks are extracted as [link text](url) inline within paragraph text. Formatting inside links is preserved: [**bold link**](url).

When modifying an existing paragraph, [text] without (url) preserves the original hyperlink URL. [text](new_url) creates a new link.

When appending new text, [text](url) creates a hyperlink. [text] without (url) produces plain text — always specify (url) on append if you want a hyperlink.

Tracked changes policy

Documents with pre-existing tracked changes (<w:ins>, <w:del>, <w:moveFrom>, <w:moveTo>) are hard-rejected in both extract_fragments and apply_redlines. Accept or reject all changes in Word before processing.

collapse_empty mode

Optional mode that suppresses empty paragraphs from extraction and redlining. Produces cleaner output for LLM consumption. When enabled, it must be used consistently across extraction and redlining — mismatched values cause fragment ID misalignment.

Change types

Paragraph changes

Type

Description

Requires new_text

modify

Word-level diff applied as tracked changes

Yes

delete

Entire paragraph marked as deleted

No

append_after

New paragraph inserted after the referenced fragment

Yes

Table cell changes

Type

Description

Requires new_text

modify_cell

Modify cell content (single or multi-paragraph)

Yes

clear_cell

Delete all content in a cell (preserves structure)

No

Cell modification uses positional alignment: if the cell has multiple paragraphs, the new text is split on newlines (\n) and each line is applied to the corresponding paragraph in order. Cell content is marked with tracked changes and comments just like paragraph modifications.

Blank line management

When appending new paragraphs, you can control surrounding blank lines:

Change(
    fragment_id=10,
    change_type=ChangeType.APPEND_AFTER,
    new_text="New clause text here.",
    justification="Added new provision.",
    blank_lines_before=1,  # Insert 1 blank line before the new paragraph
    blank_lines_after=1,   # Insert 1 blank line after the new paragraph
)

When deleting paragraphs, you can remove trailing blank lines automatically:

Change(
    fragment_id=15,
    change_type=ChangeType.DELETE,
    justification="Removed obsolete clause.",
    delete_next_blanks=1,  # Also delete the next blank paragraph
)

All blank lines are marked as tracked insertions/deletions and will appear in the redlined document.

Pseudo-Markdown

Text content uses a simplified Markdown-like format for inline formatting:

  • **bold**

  • _italic_

  • __underline__

Unicode characters (smart quotes, em dashes, section symbols, non-breaking spaces) are preserved as-is.

Font inheritance: When appending new paragraphs, the font family, size, and color are automatically copied from the reference paragraph's first text-bearing run. Bold, italic, and underline formatting from the pseudo-Markdown is layered on top of the inherited base formatting.

Changes JSON

The CLI accepts a JSON file containing either a bare array or a {"changes": [...]} wrapper.

Paragraph changes example

[
  {
    "fragment_id": "1",
    "change_type": "modify",
    "new_text": "The Seller agrees to deliver within **sixty** days.",
    "justification": "Extended delivery window."
  },
  {
    "fragment_id": "3",
    "change_type": "delete",
    "justification": "Removed governing law clause.",
    "delete_next_blanks": 1
  },
  {
    "fragment_id": "5",
    "change_type": "append_after",
    "new_text": "This Agreement shall be governed by Delaware law.",
    "justification": "Added Delaware governing law.",
    "blank_lines_before": 1,
    "blank_lines_after": 0
  },
  {
    "fragment_id": "header_1.1",
    "change_type": "modify",
    "new_text": "CONFIDENTIAL",
    "justification": "Updated header marking."
  }
]

Table cell changes example

[
  {
    "cell_id": "2.1.1",
    "change_type": "modify_cell",
    "new_text": "Updated **cell** content",
    "justification": "Corrected cell value."
  },
  {
    "cell_id": "2.3.2",
    "change_type": "clear_cell",
    "justification": "Cleared obsolete data."
  }
]

Cell IDs use the format "table_id.row.col" where rows and columns are 1-based.

Validation

The validate_document() function (and docx-mcp validate CLI) checks:

  • Annotation ID isolation -- tracked-change and comment IDs don't collide across groups

  • Comment integrity -- every <w:comment> has matching range markers in the document body, and vice versa

  • Tracked-change attributes -- every <w:ins> and <w:del> has required w:id, w:author, and w:date

  • Package consistency -- content-type and relationship entries exist for comments.xml

from docx_mcp import validate_document

result = validate_document(doc)
if not result.ok:
    for error in result.errors:
        print(error)

Architecture

The library manipulates OOXML directly via lxml (not python-docx) because python-docx has no tracked-change support. Key design decisions:

  • Word-level diffing via diff-match-patch with a word-to-char mapping for high-quality diffs

  • Conservative mutation -- only changed paragraphs are touched; everything else passes through byte-identical

  • Globally unique annotation IDs via a monotonic IdManager seeded from the document's existing max ID

  • python-docx is used only for test fixture generation, not in the library itself

Module map

src/docx_mcp/
  __init__.py        Public API
  cli.py             CLI entry point (apply, convert, validate)
  models.py          Pydantic data models (Change, ChangeType, RedlineConfig, ...)
  document.py        DocxDocument: ZIP parsing, XML tree access, serialization
  converter.py       Paragraph & table XML -> pseudo-Markdown conversion
  table_utils.py     Table inspection utilities (cell access, simplicity checks)
  tokenizer.py       Word-level tokenization
  differ.py          Word-level diff engine (diff-match-patch wrapper)
  run_ops.py         Diff-to-XML-run mapping, run splitting, element building
  id_manager.py      Monotonic annotation ID allocator
  comments.py        Comment creation and range marker insertion
  redliner.py        Main orchestrator: apply_redlines()
  table_redliner.py  Table cell change application
  audit.py           Document structural audit (headers, images, tables, etc.)
  validator.py       Structural validation checks
  server.py          MCP server (FastMCP 3.x, stdio transport)
  handlers/
    modify.py        Word-level tracked changes on existing paragraphs
    delete.py        Full paragraph deletion markup
    append.py        New paragraph insertion markup

Development

# Run tests
uv run pytest tests/ -v

# Lint
uvx ruff check src/ tests/

# Auto-fix lint issues
uvx ruff check src/ tests/ --fix

# Type check
uvx ty check src/ tests/

431 tests covering all modules, handlers, table operations, headers/footers, hyperlinks, tracked-change rejection, merged-cell tables, section breaks, CLI, validation, and MCP server.

License

MIT

Available Tools

6 tools
apply_changesA
Idempotent

Apply tracked changes to a .docx file and save a new redlined document.

Produces Word-compatible tracked changes (``w:ins`` / ``w:del``) with comments.
Always call ``extract_fragments`` first to get fragment IDs.

Paragraph changes (use ``fragment_id``):
  - ``modify``: Word-level diff. ``new_text`` required.
  - ``delete``: Marks paragraph deleted. Omit ``new_text``.
  - ``append_after``: Insert after target. ``new_text`` required.

Table changes (use ``cell_id`` like ``"2.1.3"``):
  - ``modify_cell``: Replace cell text. ``new_text`` required. Use ``

for multi-paragraph cells. -clear_cell: Delete cell content. Omit new_text``.

Rules:
  - ``delete_next_blanks`` only with ``delete``.
  - ``blank_lines_before`` / ``blank_lines_after`` only with ``append_after``.
  - Header/footer changes work but comments are silently dropped.
  - Documents with pre-existing tracked changes are hard-rejected.

``new_text`` uses pseudo-Markdown: ``**bold**``, ``_italic_``, ``__underline__``.

Example::

    changes = [
        {
            "fragment_id": 1,
            "change_type": "modify",
            "new_text": "**Updated title**",
            "justification": "Fixed typo"
        },
        {
            "cell_id": "2.1.1",
            "change_type": "modify_cell",
            "new_text": "New header",
            "justification": "Clarified"
        }
    ]

Args:
    document_path: Absolute path to the input .docx file.
    changes: List of change objects (paragraph or table cell changes).
    output_path: Where to save the redlined document. Defaults to
        ``<stem>_redlined.docx`` beside the input file.
    author: Author name for tracked changes and comments. Defaults to
        "AI Review".

Returns:
    Summary string with change counts, output path, and validation result.
ParametersJSON Schema
NameRequiredDescriptionDefault
authorNoAI Review
changesYes
output_pathNo
document_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the annotations by disclosing specific behaviors: it produces w:ins/w:del tagged changes, hard-rejects documents with pre-existing tracked changes, silently drops comments in headers/footers, and explains pseudo-Markdown formatting. These are non-obvious traits not captured by readOnlyHint, idempotentHint, or destructiveHint, adding significant value.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-organized with sections, examples, and a clear progression from summary to details. It is appropriately sized for the tool's complexity, though it includes some repetition of information already present in the schema (e.g., pseudo-Markdown rules). The front-loaded summary sentence ensures immediate clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers prerequisites, change types, parameter constraints, edge cases (headers/footers, pre-existing changes), output behavior, and provides multiple examples. It even explains the return value. Despite the tool's complexity and nested schema, the description is sufficiently complete for an agent to select and invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for top-level parameters, so the description must compensate—and it does thoroughly. It defines document_path as an absolute path, output_path's default behavior, author's default, and the structure of changes list. It also explains nested change types, required fields, and validation rules, effectively documenting all parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Apply tracked changes to a .docx file and save a new redlined document.' It clearly distinguishes the tool from siblings like apply_changes_from_file by focusing on in-memory change objects and mentioning the redlining output. The scope is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly instructs 'Always call extract_fragments first to get fragment IDs,' which is a clear prerequisite and differentiates this tool from alternatives. It also provides detailed rules for when to use each change_type and parameter. However, it does not explicitly contrast with apply_changes_from_file, so the exclusion is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

apply_changes_from_fileA
Idempotent

Same as apply_changes but reads the change list from a JSON file.

Useful for large change sets that would exceed token limits in a direct tool call, or for reusing a change set across multiple runs.

The JSON file must contain either a bare array of change objects, or an object with a "changes" key::

 [
   {"fragment_id": 1, "change_type": "modify", "new_text": "..."},
   {"cell_id": "2.1.1", "change_type": "modify_cell", "new_text": "..."}
 ]

See apply_changes for change object schema and rules.

ParametersJSON Schema
NameRequiredDescriptionDefault
authorNoAuthor name for tracked changes and comments. Defaults to "AI Review".AI Review
output_pathNoWhere to save the redlined document. Defaults to ``<stem>_redlined.docx`` beside the input file.
changes_fileYesAbsolute path to the JSON file containing changes.
document_pathYesAbsolute path to the input .docx file.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds valuable context beyond the annotations by detailing the required JSON file format (bare array or object with 'changes' key) and providing an example. It also references apply_changes for rules. Annotations already indicate idempotency and non-destructiveness, so the description complements rather than repeats them. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficient and well-organized: a lead reference to the sibling tool, explicit use cases, and a compact example of the file format. Every sentence earns its place without redundancy or fluff.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the schema covers all parameters and the description provides usage scenarios, file format requirements, and a pointer to apply_changes for the change-object schema, the tool is fully contextualized. The presence of an output schema further reduces the need for the description to explain return values. This is a complete package for a tool of this complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides descriptions for all four parameters (100% coverage), so the description doesn't need to explain them. It adds minimal value for parameters beyond the changes_file example, which illustrates content but not the parameter meaning. The baseline 3 is appropriate since the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool is 'Same as apply_changes but reads the change list from a JSON file,' immediately distinguishing it from the sibling apply_changes. It specifies the action (applying changes) and the resource (document with changes from a file), leaving no ambiguity about its purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly identifies when to use this tool: 'for large change sets that would exceed token limits in a direct tool call, or for reusing a change set across multiple runs.' It also directs users to apply_changes for schema and rules, implicitly providing the alternative context. This is clear usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

audit_document_toolA
Read-onlyIdempotent

Audit a .docx file for structural issues and skipped content.

Reports headers, footers, images, tables, section breaks, tracked changes, comments, and unsupported elements (footnotes, endnotes, text boxes).

ParametersJSON Schema
NameRequiredDescriptionDefault
formatNoOutput format -- ``"text"`` (default) or ``"json"``.text
document_pathYesAbsolute path to the .docx file.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false. The description adds useful context by detailing what the audit reports on (headers, footers, images, tables, tracked changes, comments, unsupported elements), reinforcing its non-mutating nature without contradicting annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two concise sentences with no filler. It front-loads the verb and object, then immediately lists the specific report categories. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity and the presence of a full input schema and output schema, the description fully covers what the tool does and what it reports. The list of auditable elements is sufficiently specific, and the output schema handles return-value documentation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema covers both parameters with full descriptions: document_path requires an absolute path and format enumerates text/json with a default. The description does not add parameter-level detail beyond what the schema already provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Audit') with a clear resource ('.docx file') and scope ('structural issues and skipped content'). It lists concrete report categories, which clearly distinguishes it from sibling tools like apply_changes and validate_document_tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly states when to use the tool: to audit a .docx file for structural issues and skipped content. It does not explicitly mention alternatives or exclusions, but the context is clear enough for an agent to select it over write-oriented or fragment-manipulation tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diff_fragmentsA
Read-onlyIdempotent

Compare two .docx files and show paragraph and table-level text differences.

Extracts the pseudo-Markdown text from each paragraph and table cell in both documents, then produces a word-level diff for each fragment position. This is useful for understanding what changed between two versions of a document.

Use this tool:

  • To compare an original document with its redlined version (see what changes were applied)

  • To verify that apply_changes produced the expected modifications

  • To understand differences between two versions of a document

Important Limitations

Fragments are matched by position (fragment 1 vs fragment 1, fragment 2 vs fragment 2, etc.). This tool does not detect fragment reordering or track moved sections. If the documents have very different structures (different fragment counts, major reordering), the output will show extensive changes.

Best used for comparing documents with the same basic structure where you made local edits (word changes, clause deletions, appended sections, table cell modifications).

Output Format

Each fragment is reported with its change status.

Paragraphs::

Fragment 1: unchanged
Fragment 2: modified
  - shall deliver
  + must deliver immediately
Fragment 3: unchanged
Fragment 5: deleted (only in original)
  - This clause is removed.
Fragment 10: added (only in modified)
  + This is a new clause.

Tables::

Table 56: modified
  Cell 56.2.2: modified
    - Gwendolyn Mahon, M.Sc., Ph.D
    + John H. Smith, Ph.D.
Table 57: unchanged
Table 58: dimensions changed (3x2 → 4x2)

Lines starting with - show deleted text, + shows inserted text. Unchanged fragments are listed but their text is omitted for brevity.

For tables, each modified cell is shown with its cell ID (table_id.row.col) followed by the word-level diff of the cell content.

Difference from extract_fragments

  • extract_fragments shows the plain text of a single document (paragraphs, headers, footers, tables). Pre-existing tracked changes cause a hard rejection.

  • diff_fragments compares two separate documents and computes the differences between their plain text (ignoring any tracked changes)

ParametersJSON Schema
NameRequiredDescriptionDefault
modified_pathYesAbsolute path to the modified .docx file.
original_pathYesAbsolute path to the original .docx file.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this as read-only/idempotent/non-destructive, so the bar is lower; the description adds meaningful behavior: position-based matching, no reordering detection, ignoring tracked changes, and the output style. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Although longer than typical descriptions, the structure is organized into purpose, usage, limitations, output format, and sibling comparison, with examples. Each section adds non-redundant operational detail, so it earns its length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity and the presence of an output schema, the description is sufficient: it covers core behavior, matching strategy, important exclusions, and interaction with tracked changes. No critical operational gaps remain.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema has full 100% coverage with clear descriptions of the two absolute paths, so the baseline is 3. The description reinforces which file is original vs modified in the usage bullets but does not add parameter-specific semantics beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb ('Compare'), names the resource (two .docx files), and states the output granularity (paragraph/table-level text differences). It clearly distinguishes itself from sibling extract_fragments by framing this as a comparison tool rather than extraction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'Use this tool' bullet list explicitly enumerates three concrete use cases, and the 'Important Limitations' section states when NOT to use it (different structures, reordering). It also contrasts with extract_fragments, providing an alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

extract_fragmentsA
Read-onlyIdempotent

Extract text from a .docx file as tagged fragments.

Call this first to get fragment IDs, then use those IDs in ``apply_changes``.

Output format::

    <f=1>**Title**</f=1>
    <f=2>Body paragraph.</f=2>
    <table=3 rows=2 cols=3>
    <cell=3.1.1>Header</cell=3.1.1>
    <cell=3.1.2 span="2">Merged cell</cell=3.1.2>
    </table=3>

Fragment IDs:
  - Body: ``"1"``, ``"2"``, ...
  - Headers: ``"header_1.1"``, ``"header_1.2"``, ...
  - Footers: ``"footer_1.1"``, ``"footer_2.1"``, ...
  - Table cells: ``"table_id.row.col"`` (e.g., ``"3.1.2"``)

Formatting: ``**bold**``, ``_italic_``, ``__underline__``. ``

`` for paragraph breaks.

Limitations:
  - Images, nested tables, VML text boxes are skipped.
  - Pre-existing tracked changes are hard-rejected.

Args:
    document_path: Absolute path to the .docx file.

Returns:
    Tagged text string with fragment and table markup.
ParametersJSON Schema
NameRequiredDescriptionDefault
document_pathYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the annotations by detailing the exact output format, fragment ID conventions, markup syntax, and limitations (skipped elements, hard rejection of tracked changes). This provides substantial behavioral context that the annotations (readOnlyHint, idempotentHint) do not cover.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections (output format, fragment IDs, formatting, limitations, args, returns). It is appropriately sized given the tool's complexity, and every sentence contributes useful information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is thorough: it explains the output schema, fragment ID patterns, formatting, limitations, parameters, and return value. It also places the tool in its workflow context relative to apply_changes, making it fully self-contained for the agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With a single parameter (document_path) and 0% schema description coverage, the description compensates by explaining 'Absolute path to the .docx file,' which adds the required meaning. While not exhaustive, it fully clarifies the only parameter's purpose and type.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb+resource: 'Extract text from a .docx file as tagged fragments.' It further distinguishes the tool by explaining its role as the first step for obtaining fragment IDs to be used in apply_changes, setting it apart from sibling tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly instructs 'Call this first to get fragment IDs, then use those IDs in apply_changes,' which tells the agent exactly when to use this tool. It also mentions limitations (skips images, nested tables, etc.) that imply cases where the tool is not suitable, though it does not name alternative tools for those situations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

validate_document_toolA
Read-onlyIdempotent

Check a .docx file for structural issues.

Runs validation checks on the document's OOXML structure to ensure it will open correctly in Microsoft Word and that all tracked changes and comments are properly formed.

Use this tool:

  • After calling apply_changes to verify the redlined document is valid (automatically enabled by default via validate=True parameter)

  • When debugging a document that won't open correctly in Word

  • When verifying that an existing redlined document has proper structure

Validation Checks

  • Annotation ID isolation: Tracked-change and comment IDs must not collide across groups. Each <w:ins>, <w:del>, and <w:comment> needs a globally unique ID within the document.

  • Comment integrity: Every <w:comment> in comments.xml must have matching <w:commentRangeStart> / <w:commentRangeEnd> markers in the document body, and vice versa.

  • Tracked-change attributes: Every <w:ins> and <w:del> must have required attributes: w:id (unique ID), w:author (author name), and w:date (timestamp).

  • Package consistency: Content-type and relationship entries must be present in the .docx ZIP structure when comments.xml exists.

Example Output

Success case::

"Validation: passed (0 errors, 0 warnings)."

Failure case::

"Validation: FAILED (2 error(s), 1 warning(s)).
  Error 1: Annotation ID collision: ID 5 used by both tracked change and comment
  Error 2: Orphaned comment range: commentRangeStart with id=3 has no matching end
  Warning 1: Comment with id=7 is not referenced by any comment range"
ParametersJSON Schema
NameRequiredDescriptionDefault
document_pathYesAbsolute path to the .docx file to validate.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations (readOnlyHint: true, idempotentHint: true) are complemented by detailed behavioral descriptions: it lists the four specific validation checks (annotation ID isolation, comment integrity, tracked-change attributes, package consistency) and provides example success/failure output. This goes far beyond annotation hints and gives a clear picture of what the tool does, with no contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear headers, bullet points for validation checks, and code blocks for example output. Although somewhat long, every section adds value and the main purpose is front-loaded in the first sentence. No redundant or filler content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (one parameter, full schema coverage, no nested objects) and the presence of an output schema, the description is more than complete. It covers purpose, usage scenarios, validation checks, and example output, leaving no significant gaps for an agent to misuse the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already provides 100% coverage of the single parameter document_path, including a description ('Absolute path to the .docx file to validate'). The tool description adds no additional semantics about this parameter, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Check a .docx file for structural issues' and elaborates on validating OOXML structure for Word compatibility, tracked changes, and comments. This is a specific verb+resource statement that thoroughly distinguishes its scope from sibling tools, especially audit_document_tool, by listing the exact validation checks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description includes an explicit 'Use this tool:' section listing three concrete scenarios (after apply_changes, debugging open failures, verifying existing redlined documents). It also notes that validation is automatically enabled via validate=True in apply_changes, effectively communicating when the tool may not need to be called separately.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 6 tool updatesv0.2.0
    • First observedapply_changes
    • First observedapply_changes_from_file
    • First observedaudit_document_tool
    • First observeddiff_fragments
    • First observedextract_fragments
    • First observedvalidate_document_tool

TDQS

A4.4/5.0
Disambiguation4/5

Most tools have clear, distinct purposes: extract, apply changes, validate, audit, and diff. However, validate_document_tool and audit_document_tool both inspect document structure and could be confused, and apply_changes_from_file is a redundant variant of apply_changes. Overall, the descriptions help clarify boundaries.

Naming Consistency4/5

Tool names follow a consistent verb_noun pattern with lowercase underscores (extract_fragments, apply_changes, diff_fragments). The '_tool' suffix on validate_document_tool and audit_document_tool is a minor inconsistency, and apply_changes_from_file is long but clear. The naming is generally predictable.

Tool Count5/5

With 6 tools, the server is well-scoped for the domain of .docx extraction, tracked changes, validation, and comparison. Each tool contributes to a focused workflow, and the count is within the ideal 3-15 range.

Completeness4/5

The tool surface covers the core lifecycle: extraction, applying changes, validation, auditing, and diffing. Minor gaps exist, such as no direct tool for creating documents or accepting/rejecting changes, and the extraction tool skips some elements. However, the primary redlining workflow is well-supported.

Maintenance

ActivityInactive
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sontanon/docx-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server