Skip to main content
Glama

edit_document

Edit a Microsoft Word (.docx) document: apply a LIST of edits in ONE call. The client controls whether edits appear as tracked changes or directly in place. The author comes from developer-controlled _meta, not a tool argument; you cannot choose or change it.

'edits' is an array of { old, new }. For each edit:

  • 'old': an HTML snippet copied VERBATIM from the document's current HTML (as returned by read_document) that matches EXACTLY ONE spot (prefer a whole block: /// heading). Copy the inner markup as-is -- keep any , , nested -- and only shorten class attributes (see LAZY CLASSES).

  • 'new': the full replacement HTML for that block -- its FINAL text, with NO / of your own; the tool handles the configured review representation. Use "" to delete it.

DELETE OR REJECT AN ENTIRE TABLE ROW: use the complete ... as 'old' and "" as 'new'. Never empty the individual cells while preserving the ; that leaves a blank row in the document instead of removing the row.

THE DOCUMENT BODY AND EXPOSED HEADERS / FOOTERS ARE EDITABLE. A referenced running header/footer is emitted once as /; edit its blocks normally. Shared parts are not duplicated, so one edit updates every section/type listed in data-docx-refs.

COMMENTS ARE EDITABLE LIKE CONTENT. To comment, wrap the text in a bare and add a bare

Do NOT anchor on the following non-editable content:

  • FOOTNOTES / ENDNOTES: these auxiliary parts are read-only.

  • GLOBAL STYLES: the header at the TOP of the HTML, and adding or renaming a named style. To restyle, reuse an existing style class or apply a local Tailwind class on the block; editing the block is rejected.

MAKE EVERY 'old' UNIQUE. Each edit's 'old' must independently match exactly one location. NEVER reuse an ambiguous 'old' for different targets or rely on edit order to choose among repeated matches. To target duplicated blocks, expand EACH 'old' to a unique neighborhood by including an adjacent heading or block -- a CONSECUTIVE span copied verbatim. Preserve unchanged context in 'new'. A consecutive span can also replace adjacent blocks; NON-adjacent blocks require separate edits.

INSERTION ANCHORS ARE ALSO OOXML EXAMPLES. edit_document localizes only old to x_old; the reconciler sees that OOXML with old and new, not the rest of the document. Choose the smallest consecutive old containing the insertion boundary and a structure the new content should resemble: a same-role list item, a same-shape row, or one complete prior repeated block. Preserve the example unchanged in new. Do not substitute an unrelated heading, blank paragraph, or merged row merely because it is unique, including on retries. Context is evidence, not permission to edit beyond the user's requested scope.

RETRY SAFETY: a failed edit does not make a weaker anchor valid. Keep the same document part, same-role examples, insertion boundary, and unchanged anchor text. Reduce only the new content when splitting a failed insertion. Do not switch to an unrelated header/footer, blank/title block, or tag-only fragment, and never alter preserved text merely to satisfy a validator. If the structurally correct anchor still fails, stop instead of broadening the edit.

LAZY CLASSES (default): write class="..." (literally three dots) for EVERY class attribute in BOTH 'old' and 'new' -- it means "keep this class". Don't paste the real class lists. Spell a class out only when changing the class IS the edit (e.g. bold), to break a "multiple matches" tie, or on a brand-new INSERTED block (one with no counterpart in 'old') -- it has no existing element to inherit from, so it must SPELL OUT its class, never "...".

class="..." is ALL-OR-NOTHING -- it stands for the ENTIRE class value, so it must be the whole attribute, written EXACTLY as class="..." with nothing else inside or after the quotes. NEVER keep a fragment of the real class beside it: class="..." bg-[#F6F4EF]" is INVALID (the whole class, bg-[#F6F4EF] included, lives INSIDE one class attribute, so this fails to locate). To keep a distinguishing class (e.g. a background), spell the WHOLE class out for that element instead of lazying it.

STYLE-ONLY CHANGES: when changing only a block's named document style, preserve its tag and every unrelated class. Do NOT change the HTML tag merely because the target style commonly renders with another tag, or replace a full class list with only the new style token -- the other classes carry direct spacing, alignment, font, and layout that the request did not ask you to remove. In 'old', use class="..." normally. In 'new', copy that block's COMPLETE class value from read_document, remove only its previous named style token if it has one, add the requested named style token, and leave every Tailwind utility unchanged. Keep unrelated descendants lazy. Example, to change BodyText to IntenseQuote on <p class="BodyText text-center mb-[6pt]">Summary</p>: old: Summary new: Summary

LISTS: list content is marker-free semantic HTML. Never type bullets, numbers, or letters into paragraph text. Every item is <li><p>…</p></li>; nest a child <ol>/<ul> inside its parent <li>. Ordered lists use type="1|a|A|i|I" and start="…" when a restart matters.

When search_document returns one <li>, it is sufficient for changing or deleting only that item's content. Before an insertion, reorder, nesting/unnesting, restart, split, merge, or ordered/bullet conversion, call read_document for that page and inspect the parent <ol>/<ul>, its type/start, and the affected siblings before building the structural edit.

Choose the edit shape by intent:

  • A direct <p> or one <li> is only for changing or deleting that one item's content while keeping its list position, level, marker type, and numbering.

  • An insertion, reorder, nesting/unnesting, restart, split, merge, or ordered/bullet conversion is structural. Put the smallest complete affected <ol>/<ul> subtree in BOTH old and new; do not send loose sibling <li> elements for a new structural edit.

  • A newly inserted block cannot inherit class="...". Copy the complete formatting of the appropriate neighbouring item, spelling its classes out.

INSERTING INTO A CONTINUING NUMBERED LIST: separate <ol> wrappers do not automatically continue merely because their classes and types match. If old includes both the preceding N-1 item and following N item from one sequence, preserve the following start="N" so that context proves natural continuation. If only the separately wrapped following start="N" item is included, set it to start="N+1" in new. Keep its content and formatting unchanged, and do not seek out or renumber unrelated later fragments.

Examples (classes omitted only to keep these examples short): Insert between items: old: AlphaGamma new: AlphaBetaGamma Delete one item without changing the list structure: old: Obsolete new: "" Nest an item: old: ParentChild new: ParentChild Restart at five: old: First new: First

PREFER BATCHING: send all of a request's edits in one call when it makes sense -- they reconcile IN PARALLEL, so a 10-edit call takes about as long as one edit while 10 separate calls are ~10x slower (max 20 edits per call -- if a task needs more, send several batches of <=20). NO OVERLAPS: every edit must target a DIFFERENT block; two edits that touch the SAME block (or the same consecutive span) overlap and BOTH are dropped -- combine those changes into a SINGLE old/new pair.

KEEP EACH EDIT SMALL. Each edit is applied by a model with a bounded output, so ONE edit carrying a huge 'new' (say beyond ~10,000 characters -- several pages of new text) risks truncation or a timeout and fails the whole edit. When writing a LOT of new content, break it into MULTIPLE edits of a few blocks each: give each chunk its own { old, new } anchored on a DIFFERENT neighboring block (e.g. chunk 1 anchors on the block above and appends the first blocks; chunk 2 anchors on chunk 1's LAST block and appends the next ones -- but note within one batch edits must not overlap, so either anchor each chunk on a distinct existing block, or send the chunks as consecutive calls). Prefer many small edits over one giant edit; batching keeps them fast.

EDITS SUCCEED OR FAIL INDIVIDUALLY. A batch can apply in part: the result's 'count' is how many landed and 'failed_edits' lists the rest as { index, reason } ('index' is 1-based over the 'edits' you sent). The applied ones are ALREADY saved in the document, so NEVER resend the whole batch after a partial result -- that re-applies them and duplicates the text. Resend ONLY the listed index(es), fixed, or tell the user what couldn't be changed. When NOTHING applies you get an error instead and the document is untouched; then fix the listed edits and resend the whole batch.

Some successful edits need no new document mutation because the requested result is already represented by an existing tracked change. Those return count: 0 plus a notices entry. Do not retry an edit named by a notice.

SUCCESSFUL EDITS ARE COMPLETE: applied edits are already present in the returned document. Depending on client configuration, they appear as tracked changes or directly in place. If tracked changes are visible, deleted text can remain struck through until accepted; do not repeat a successful edit.

RESOLVE OR MODIFY AN EXISTING TRACKED CHANGE. read_document renders changes already in the doc as (insertions) and (deletions), each with a data-author. To act on one, copy its whole block verbatim into 'old' (keep the / and their data-author). Then write 'new' as that block's final state, under two rules:

  1. RESOLVE ONLY THE CHANGE YOU WERE ASKED ABOUT. A block often carries several pending changes. Every one you were not asked about must appear in 'new' exactly as it stands in 'old' -- wrapper, data-author and text untouched. Pending is the default state: clearing a change nobody mentioned is a WRONG edit even when the resulting words look right. "Mentioned" is semantic, not author-only: a revision is in scope when the request identifies its author, its text, its role in a combined change, or explicitly includes it in the requested final value. Apply the requested action to every such revision, even when several authors' wrappers contribute pieces of one accepted or rejected result.

  2. The only / allowed in 'new' are those ALREADY in 'old'; keep their data-author untouched. Never create one -- the tool handles any new revision markup itself. FINAL ACCEPTED TEXT: read remaining text and omit text. Text requested to "read exactly" must match exactly, including punctuation and spacing, and omit proposal labels or brackets absent from the supplied phrase.

  • ACCEPT an insertion -> keep its text, drop the wrapper. ACCEPT a deletion -> drop the and its text.

  • REJECT an insertion -> drop the and its text. REJECT a deletion -> keep its text, drop the wrapper.

  • MODIFY a change -- anyone's, your own included -> keep its / wrapper AND its data-author exactly as they are, and edit only the TEXT inside. Never unwrap it, re-author it, or hand-write a nested / in it. Examples (author configured as "Dana"): Reject Jane's insertion: old: The quick brown fox new: The fox Accept Jane's insertion; Sam's was not mentioned, so it stays exactly as it was: old: A big red fast car new: A big red fast car Accept a combined version update whose requested final value explicitly includes both pieces: old: Version 2.1 new: Version 2.1 Modify Jane's insertion, dropping "brown " -- edit her text in place; Dana's deletion is recorded inside Jane's insertion automatically: old: The quick brown fox new: The quick fox

BEST PRACTICES:

  • MATCH THE NEIGHBOURS. Editing or adding a table cell, a list item or a heading? Look at its siblings first -- the other cells in that column, the other bullets in that list, the other headings at that level -- and give yours the SAME formatting, spelled out. Content that is right but plain where its column is bold counts as wrong.

  • FORM ROLE PRECEDENCE. Infer labels and entry cells from repeated row structure before considering style names or cell widths. A class such as Answers does not make non-empty text a placeholder, and a narrow blank cell can still be its entry cell. When a non-empty cell is paired with an adjacent blank cell, preserve the non-empty cell and fill the blank unless explicitly told otherwise. An &nbsp;-only cell is blank; label padding is not an entry slot.

  • PRESERVE BLANK WORD FIELDS. "Click or tap here to enter text" marks an empty content control. Copy its complete placeholder element, including class and text, only when cloning a same-role peer in the same repeated form structure whose HTML visibly contains that placeholder. When filling an existing field, replace it with the value. Never infer a content control merely from "field" or "line", add one to an ordinary blank cell, or substitute filler.

  • HIGHLIGHTING COMES FROM WORD'S FIXED PALETTE, not from arbitrary colours: black, blue, cyan, darkBlue, darkCyan, darkGray, darkGreen, darkMagenta, darkRed, darkYellow, green, lightGray, magenta, red, white, yellow. Some are named differently in Word's own menu -- PINK is magenta (#FF00FF), turquoise is cyan (#00FFFF), violet is darkMagenta (#800080), bright green is green (#00FF00), gray 25%/50% are lightGray/darkGray. Write the palette colour's hex (e.g. bg-[#FF00FF] for pink); a colour off the palette gets snapped to the nearest one it can paint, which for a pastel is usually a grey.

Input Schema

NameRequiredDescriptionDefault
editsYes

Output Schema

NameRequiredDescriptionDefault

No arguments

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observed

TDQS

A4.8/5.0
Behavior5/5

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

With no annotations, the description carries the full behavioral load and does so: tracked-changes vs in-place is client-controlled, author comes from _meta and is unchangeable, edits succeed/fail individually with count/failed_edits/notices, applied edits are already saved, and there are documented limits (max 20 edits, ~10k-char 'new', parallel reconciliation). Mutating semantics and partial-failure behavior are fully disclosed.

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

Conciseness3/5

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

It is front-loaded with the core purpose and organized under clear headers, but it is enormous (well over a thousand words) with repeated restatements of retry safety and anchor uniqueness. Most sentences earn their place, yet the volume and redundancy go past what a tool description should carry.

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?

An output schema exists, so return values needn't be explained, yet the description still clarifies result semantics (count, failed_edits with 1-based index, count 0 + notices) that the schema alone would not make obvious. For a tool of this complexity, nothing an agent needs to call it correctly is missing.

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 coverage is reported at 0%, so the description must compensate, and it does far beyond the schema's one-line field notes: uniqueness of 'old', verbatim copying, the class="..." lazy convention, empty-string deletion, whole-<tr> row deletion, and per-edit overlap rejection. This is semantics the schema cannot express.

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?

Opens with a specific verb+resource+scope: apply a LIST of edits in ONE call to a Word .docx. It explicitly frames itself against the siblings by tying 'old' to HTML previously returned by read_document, so an agent can tell edit_document apart from read_document/search_document without further inspection.

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?

Gives explicit routing rules: call read_document before structural list edits, search_document's single <li> suffices for content-only changes, batch edits in one call (<=20), never resend a partially-applied batch, and don't retry edits named in notices. It also states when NOT to broaden an anchor on retry. When/when-not/alternatives are all present.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources