Skip to main content
Glama

doc_batch

Apply multiple Word .docx edits in one atomic batch as tracked changes or plain approved writes, with dry-run previews, conflict checks, and stale-file guards.

Instructions

The main editing tool: apply several edits in one verified write, as tracked changes, all or nothing. One family per batch: text.replace, para.insert, para.delete, para.move, style.apply, format.apply, comment.add/reply/resolve; or table.row.insert/delete; or style.create/update/rename/merge; or revision.accept/reject. Example ops: [{"op": "text.replace", "at": "p3#a1b2c3d4:10-15", "text": "new"}]. Every address is as read; overlapping edits are BATCH_CONFLICT, outdated ones STALE_ADDRESS. File engine: backed up first, dry_run previews, expect.sha256 refuses a changed file, history.undo takes the batch back. tracked: false writes approved text plainly, on either engine. engine live edits the open app (comment.add, text.replace, para.insert only; no dry_run or rollback). server.help gives each kind's fields.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
docYesPath to the .docx (live: or the file name of one open in a live app).
opsYesOperations, applied together. Every address refers to the document as read; an operation placed relative to a paragraph another operation deletes or moves is a BATCH_CONFLICT. Kinds: text.replace ['at', 'text']; para.insert ['after', 'before', 'text']; para.delete ['at']; para.move ['after', 'at', 'before']; style.apply ['at', 'style']; format.apply ['align', 'at', 'bold', 'font', 'indent_first_line_cm', 'indent_left_cm', 'indent_right_cm', 'italic', 'line_spacing', 'size_pt', 'small_caps', 'spacing_after_pt', 'spacing_before_pt', 'underline']; comment.add ['at', 'text']; comment.reply ['comment', 'text']; comment.resolve ['comment', 'resolved']; style.create ['based_on', 'custom', 'default', 'id', 'link', 'name', 'next', 'paragraph', 'quick', 'run', 'type']; style.update ['based_on', 'link', 'next', 'paragraph', 'quick', 'run', 'style']; style.rename ['id', 'name', 'style']; style.merge ['from', 'into']; revision.accept ['all', 'at', 'author', 'ids']; revision.reject ['all', 'at', 'author', 'ids']; table.row.insert ['after_row', 'cells', 'table']; table.row.delete ['row', 'table'].
tagNoAppended to the author.
authorNoRevision author.
engineNo`live` edits the document open in Word or LibreOffice (see live.open).
expectNoWrite guard: the sha256 read earlier (doc.info, or a reply's doc.sha256), e.g. {"sha256": "9f86d081…"}; a file changed since is DOC_CHANGED_ON_DISK.
dry_runNoPreview only; write nothing.
trackedNotrue (default): edits are tracked changes. false: a plain write, for a change the writer already approved: built as the tracked edit, then this call's own revisions are accepted in the same verified write (no revision marks; the log has it, and undo takes it back from the backup, only while the document is exactly as the write left it: no out-of-order undo). Refused (UNSUPPORTED_CONTENT) when a paragraph it rewrites holds another unresolved tracked change. Text, paragraph and style/format edits only (refused with revision, row and comment operations). engine live: the app's change tracking is off for the edit and put back after; text.replace and para.insert, refused (UNSUPPORTED_CONTENT) next to another unresolved tracked change; the app's undo takes it back. A plain edit inside a tracked-inserted table row is allowed: rejecting that row later removes the plain text too.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
okYesAlways true on success.
opYesThe operation that ran.
apiYesAPI version (1.0).
docNoThe document read or written: path, sha256 and paragraph count.
nextYesCursor for the next page (pass as cursor), or null.
resultYesWhat the operation returns.
warningsYesThings to know about the result.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changedv0.7.2
    • addedInput schema / properties / expect / description
      Added value: +"Write guard: the sha256 read earlier (doc.info, or a reply's doc.sha256), e.g. {\"sha256\": \"9f86d081…\"}; a file changed since is DOC_CHANGED_ON_DISK."
    • changedInput schema / properties / tracked / description
      Previous value: -"true (default): edits are tracked changes. false: a plain write, for a change the writer already approved: built as the tracked edit, then this call's own revisions are accepted in the same verified write (no revision marks; the log has it, and undo takes it back from the backup, only while the document is exactly as the write left it: no out-of-order undo). Refused (UNSUPPORTED_CONTENT) when a paragraph it rewrites holds another unresolved tracked change. Text, paragraph and style/format edits only (refused with revision, row and comment operations); file engine only for now. A plain edit inside a tracked-inserted table row is allowed: rejecting that row later removes the plain text too."New value: +"true (default): edits are tracked changes. false: a plain write, for a change the writer already approved: built as the tracked edit, then this call's own revisions are accepted in the same verified write (no revision marks; the log has it, and undo takes it back from the backup, only while the document is exactly as the write left it: no out-of-order undo). Refused (UNSUPPORTED_CONTENT) when a paragraph it rewrites holds another unresolved tracked change. Text, paragraph and style/format edits only (refused with revision, row and comment operations). engine live: the app's change tracking is off for the edit and put back after; text.replace and para.insert, refused (UNSUPPORTED_CONTENT) next to another unresolved tracked change; the app's undo takes it back. A plain edit inside a tracked-inserted table row is allowed: rejecting that row later removes the plain text too."
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "properties": {
      +    "api": {
      +      "description": "API version (1.0).",
      +      "type": "string"
      +    },
      +    "doc": {
      +      "description": "The document read or written: path, sha256 and paragraph count.",
      +      "properties": {
      +        "characters": {
      +          "description": "text.normalize of a text string: its length.",
      +          "type": "integer"
      +        },
      +        "paragraphs": {
      +          "description": "Body paragraphs.",
      +          "type": "integer"
      +        },
      +        "path": {
      +          "description": "Path of the document.",
      +          "type": "string"
      +        },
      +        "sha256": {
      +          "description": "sha256 of the file (pass as expect.sha256 to a write).",
      +          "type": "string"
      +        },
      +        "source": {
      +          "description": "A .txt/.md/.odt source's format, encoding and split mode; \"text\" for a text string (text.normalize).",
      +          "type": [
      +            "object",
      +            "string"
      +          ]
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "next": {
      +      "description": "Cursor for the next page (pass as cursor), or null.",
      +      "type": [
      +        "string",
      +        "null"
      +      ]
      +    },
      +    "ok": {
      +      "description": "Always true on success.",
      +      "type": "boolean"
      +    },
      +    "op": {
      +      "description": "The operation that ran.",
      +      "type": "string"
      +    },
      +    "result": {
      +      "description": "What the operation returns.",
      +      "properties": {
      +        "accepted": {
      +          "description": "Revisions accepted.",
      +          "type": "integer"
      +        },
      +        "address_map": {
      +          "description": "Old address -> new address of every paragraph whose address changed.",
      +          "type": "object"
      +        },
      +        "applied": {
      +          "description": "Edits applied (a count), or for style kinds one entry per style op.",
      +          "type": [
      +            "integer",
      +            "array"
      +          ]
      +        },
      +        "author": {
      +          "description": "Revision author stamped on the changes.",
      +          "type": "string"
      +        },
      +        "backup": {
      +          "description": "Path of the backup taken before the write.",
      +          "type": [
      +            "string",
      +            "null"
      +          ]
      +        },
      +        "changed_parts": {
      +          "description": "Package parts rewritten.",
      +          "items": {
      +            "type": "string"
      +          },
      +          "type": "array"
      +        },
      +        "comment_ids": {
      +          "description": "Ids of the comments added.",
      +          "items": {
      +            "type": "string"
      +          },
      +          "type": "array"
      +        },
      +        "date": {
      +          "description": "Revision date (UTC, ISO 8601).",
      +          "type": "string"
      +        },
      +        "dry_run": {
      +          "description": "True when nothing was written (a preview).",
      +          "type": "boolean"
      +        },
      +        "engine": {
      +          "description": "live: edited in the open app; nothing backed up or verified.",
      +          "type": "string"
      +        },
      +        "footprint": {
      +          "description": "Part name -> the paragraphs or items it touched in that part.",
      +          "type": "object"
      +        },
      +        "merged_paragraphs": {
      +          "description": "Paragraphs joined by resolving paragraph marks.",
      +          "type": "integer"
      +        },
      +        "op_id": {
      +          "description": "Undo-log id of this write (history.undo / history.restore).",
      +          "type": [
      +            "string",
      +            "null"
      +          ]
      +        },
      +        "op_ids": {
      +          "description": "Live: one log entry per edit, in request order.",
      +          "items": {
      +            "type": "string"
      +          },
      +          "type": "array"
      +        },
      +        "paragraphs_changed": {
      +          "description": "Paragraphs whose style reference was rewritten.",
      +          "type": "integer"
      +        },
      +        "preview": {
      +          "description": "One entry per edit: what changes where.",
      +          "items": {
      +            "description": "A previewed edit.",
      +            "properties": {
      +              "action": {
      +                "description": "accept or reject (revision kinds).",
      +                "type": "string"
      +              },
      +              "after": {
      +                "description": "Text after.",
      +                "type": "string"
      +              },
      +              "at": {
      +                "description": "Where it applies.",
      +                "type": "string"
      +              },
      +              "before": {
      +                "description": "Text before.",
      +                "type": "string"
      +              },
      +              "op": {
      +                "description": "Index of the edit in ops.",
      +                "type": "integer"
      +              },
      +              "revisions": {
      +                "description": "Revisions it resolves (revision kinds).",
      +                "type": "integer"
      +              }
      +            },
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "references_rewritten": {
      +          "description": "Style references rewritten (renames, merges).",
      +          "type": "integer"
      +        },
      +        "rejected": {
      +          "description": "Revisions rejected.",
      +          "type": "integer"
      +        },
      +        "revision_ids": {
      +          "description": "w:id of every revision this write created.",
      +          "items": {
      +            "type": [
      +              "integer",
      +              "string"
      +            ]
      +          },
      +          "type": "array"
      +        },
      +        "revisions": {
      +          "description": "The revisions resolved (capped; see revisions_omitted).",
      +          "items": {
      +            "description": "A resolved revision.",
      +            "properties": {
      +              "action": {
      +                "description": "accept or reject.",
      +                "type": "string"
      +              },
      +              "at": {
      +                "description": "Paragraph address.",
      +                "type": "string"
      +              },
      +              "author": {
      +                "description": "Its author.",
      +                "type": "string"
      +              },
      +              "id": {
      +                "description": "Revision id.",
      +                "type": "string"
      +              },
      +              "type": {
      +                "description": "Revision type (insert, delete, mark_insert, format...).",
      +                "type": "string"
      +              }
      +            },
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "revisions_omitted": {
      +          "description": "Resolved revisions left out of the list.",
      +          "type": "integer"
      +        },
      +        "sha256": {
      +          "description": "sha256 of the file after the write (pass as expect.sha256 next).",
      +          "type": [
      +            "string",
      +            "null"
      +          ]
      +        },
      +        "tracked": {
      +          "description": "False for a plain (untracked) write.",
      +          "type": "boolean"
      +        },
      +        "warnings": {
      +          "description": "Notes on what the write could not do as asked.",
      +          "items": {
      +            "type": "string"
      +          },
      +          "type": "array"
      +        }
      +      },
      +      "required": [
      +        "applied"
      +      ],
      +      "type": "object"
      +    },
      +    "warnings": {
      +      "description": "Things to know about the result.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "api",
      +    "ok",
      +    "op",
      +    "result",
      +    "warnings",
      +    "next"
      +  ],
      +  "type": "object"
      +}
  2. Addedv0.1.3

TDQS

A4.6/5.0
Behavior5/5

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

Annotations only declare the safe-mutation profile (readOnly=false, destructive=false), while the description carries all the real load: backup-then-write, dry_run preview, expect.sha256 refusal (DOC_CHANGED_ON_DISK), undo semantics, BATCH_CONFLICT/STALE_ADDRESS errors, and detailed tracked:false behavior including UNSUPPORTED_CONTENT refusals and out-of-order-undo limits. Exceptionally rich and non-contradictory.

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?

One dense paragraph that front-loads the core purpose, then families, then engine/tracked nuances. Every clause carries information (error codes, engine limits, undo rules), though the compression makes it heavy reading for a first-pass selection.

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?

For a complex 8-parameter, nested, multi-op write tool with an output schema already present, the description covers the engine choice, tracking semantics, write guard, backup/undo, and refusal modes. Nothing an agent needs to invoke it correctly is missing.

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?

Schema coverage is 100%, so parameters are already documented, but the description adds value beyond the schema: the concrete address form ('p3#a1b2c3d4:10-15'), the family-grouping rule, and the tracked:false consequences that the schema only names. It stops short of fully explaining every op's fields (deferring to server.help), so it sits above the 3 baseline but not maximal.

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?

States a specific verb and resource ('apply several edits in one verified write, as tracked changes, all or nothing') and enumerates the exact op families it covers. This lets an agent distinguish it from the many single-op siblings (text_replace, para_delete, style_update, revision_accept, comment_add) without opening any schema.

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?

Gives the key selection rule ('One family per batch') plus preview/guard behavior and the live-engine restriction to comment.add/text.replace/para.insert. It implies the batch-vs-single-op choice rather than stating it outright ('use this when you have multiple edits, otherwise the single-op tools'), so it falls just short of explicit when/when-not guidance.

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