doc-control
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| DOC_CONTROL_AUTHOR | No | The author name recorded for every tracked change made by the tool (default `Claude`). | Claude |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {} |
| resources | {} |
| extensions | {
"io.modelcontextprotocol/ui": {
"mimeTypes": [
"text/html;profile=mcp-app"
]
}
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| anchor_createA | Make an anchor for a passage so it can be found again after edits shift or change addresses: the quoted text, |
| anchor_resolveA | Find an anchor's passage in the document as it is now: its current range, a 0-1 score and the match kind (exact, normalized or fuzzy). Pass the |
| caption_addA | Add a numbered caption next to a body paragraph (a table, figure or equation), as tracked insertions: label, a SEQ field with the number, and |
| comment_addA | Add one comment on a range: |
| comment_listA | List the comments in thread order (each root comment, then its replies) with id, author, date, text (clipped at 1,000 characters), quote (the text the comment covers, clipped at 200), resolved state and the address where each starts, including comments in notes and headers. Filter with |
| doc_batchA | 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. |
| doc_compareA | Write a redline: a new .docx at |
| doc_diffA | Align the paragraphs of two versions ( |
| doc_infoA | Cheap first look at a file: size, sha256 (pass it as expect.sha256 to a later write so it is refused if the file changed meanwhile), core properties (title, author, dates), whether Track Changes is on, whether Word holds it open (a ~$ lock file) and which parts exist (comments, notes, headers). The envelope's |
| doc_openA | Start a session on a document: back it up into its store (.doc-control// next to it; the newest 20 backups or 30 days are kept) and note it in the undo log if it changed since the last logged write. Call it once before editing; the document itself is not changed. If the document has no history yet, |
| doc_outlineA | List the headings (levels 1-9, by style or outline level) in document order, each with its address, level, style and text: the table-of-contents view. max_level 2 keeps levels 1-2; stories ["body", "notes"] adds headings in notes. Use doc.segment for chapters that are not styled as headings, para.list for every paragraph, para.get to read one heading in full. Read-only; paged: about 8,000 bytes per reply (limit up to 1,000), continue with |
| doc_segmentA | Split a manuscript into units with stable ids: unit chapters (default), parts or scenes (detected from headings, numerals, centring, scene markers; signals say which), or sentences or dialogue lines within |
| doc_statsA | Count what the body holds: paragraphs (and empty ones), words, characters, headings, tables, comments, footnotes, tracked changes by type, styles in use and the 20 most used fonts. stories ["notes", "headers"] adds separate counts for notes and for headers/footers (the body counts stay the body's). Use it to size a document or check for leftover revisions; doc.info gives file facts and the hash, revision.list the changes themselves. Read-only; one reply, not paged. |
| field_listA | List every field (PAGE, TOC, REF, SEQ, XE, citations such as ADDIN ZOTERO_ITEM...) with its address, story, code, type, shown result and whether it is stale (needs updating). stories defaults to all: body, notes, headers and comments; |
| field_updateA | Recompute the body's TOC, PAGE, NUMPAGES, SEQ and REF/PAGEREF results with headless LibreOffice and write only those result runs, as tracked changes (old result struck, new inserted). Needs LibreOffice (soffice): without it, ENGINE_UNAVAILABLE names the stale fields; set_update_on_open instead sets w:updateFields so Word updates them on opening. Citations are never changed; INDEX, SECTIONPAGES, SECTION, NOTEREF and unresolvable REFs are left and listed under |
| history_adoptA | Re-attach a moved or renamed document to its old undo history, so history.undo and history.restore work again. It finds the orphaned store whose last recorded state is this file's sha256 (doc.open lists them as |
| history_listA | List the document's undo log, newest first: each write's op_id, kind, time, author, the operations it ran, whether it was undone, and the deleted paragraphs history.restore can bring back (change numbers). Filter with |
| history_orphansA | List undo stores whose document is gone (moved, renamed or deleted): the app-data stores, plus |
| history_purgeA | Delete undo history for privacy: the whole log ( |
| history_restoreA | Bring back paragraphs a logged write deleted or changed, as a tracked insertion (tracked: false: plainly, for a change the writer approved). Give the |
| history_searchA | Search the undo log for a quote: in each logged request and in the text of every paragraph before and after each write, newest first. Use it to find when a passage was changed or deleted, and the op_id for history.undo or history.restore; text.find searches the current document instead. Exact by default (ignore_case, ignore_accents loosen it); match_level default or loose folds case, accents and punctuation and returns each hit's offsets and level. Works on an orphaned |
| history_undoA | Take back one logged write (doc.batch, text.replace and the other direct writes, comment and style writes, styleset.install, term.rename, field and note inserts, layout.apply, history.restore), returning its paragraphs and parts to their state before it: by default the latest one still in effect, or the |
| index_insertA | Insert an index (an INDEX field) after a body paragraph |
| index_markA | Mark an index entry: insert an XE field, as a tracked insertion, right after a range (p8#a1b2c3d4:10-15) so that word or phrase is indexed on its page. |
| layout_applyA | Bring the document to a page plan, the shape layout.get returns: per section its start ( |
| layout_getA | Read the page plan: per section where it starts ( |
| live_closeA | Close the document in its Word or LibreOffice window (attached with live.open). With unsaved changes it is refused (UNSAVED_CHANGES) unless |
| live_get_selectionA | Read what the user has selected in Word or LibreOffice right now, and the paragraph the selection starts in with its address (p12#a1b2c3d4), to edit with doc.batch or text.replace. Use it when the user points at text ("this paragraph", "here"); live.select moves the selection instead. The document must be attached with live.open (ENGINE_UNAVAILABLE otherwise). Read-only. |
| live_openA | Attach to Word or LibreOffice for live editing: find the window already holding the document, or open it in |
| live_placesA | Show the user a list of places as clickable buttons: in a client that renders MCP Apps, a click moves Word's or LibreOffice's cursor there (mode cursor) or selects the paragraph (mode select) by calling live.select, with no assistant turn. Each place has a |
| live_saveA | Save the document open in Word or LibreOffice (attached with live.open) to its file, from inside the app. Call it after live edits (doc.batch with engine live) to keep them; live.close with save: true saves and closes in one call. Overwrites the file on disk with the app's version; no backup is taken. |
| live_selectA | Show the user a place in Word or LibreOffice: select a paragraph, or with mode cursor only put the cursor at its start, by address ( |
| live_statusA | Check the live apps: which of Word and LibreOffice are installed and reachable, and which documents they have open; with |
| note_addA | Add a footnote or endnote: the reference mark goes at a body point (p3#a1b2c3d4:10-10, after offset 10), after a range, or at the end of a paragraph (p3#a1b2c3d4); |
| page_estimateA | Estimate the page each paragraph starts on (and ends on when it spans pages): from Word's rendered page marks and explicit breaks where present, else a words-per-page model; always flagged |
| para_deleteA | Delete a paragraph (p3#a1b2c3d4) or a run of paragraphs (p3#a1b2c3d4..p5#e5f6a7b8), as a tracked deletion the writer can reject. File engine: backed up first, logged for history.undo, dry_run previews, expect.sha256 refuses a file changed since; tracked: false deletes plainly (a change the writer approved). STALE_ADDRESS if the paragraph changed since it was read. Use text.replace to delete part of a paragraph, doc.batch for several edits all or nothing. Returns the address_map of shifted paragraphs. |
| para_getA | Read one paragraph in full by address (p142#a7b2a7b2, or fn3/p1#… in a note): text, style, direct paragraph formatting, character-formatted spans (bold, italic, font...) and layout facts (heading_level is null for a body paragraph, 1-9 for a heading). Use it before editing a paragraph or to check its formatting; para.list reads many paragraphs, style.get a style. Read-only; a very long text is paged (limit characters, |
| para_insertA | Insert one new paragraph with |
| para_listA | List every paragraph in document order with its address, text, style, heading level and layout facts (centred, page break before, blank paragraphs before, empty, table cell); heading_level is null for a body paragraph. normalized adds normalised text, pages the estimated page, stories notes or headers. Use it to index or scan a whole document; para.get reads one paragraph with formatting, doc.outline only headings, text.find searches. Read-only; paged: about 8,000 bytes per reply (limit up to 1,000), continue with |
| para_locateA | Say where paragraphs are, in terms a person can follow: for one paragraph, a range (p40#a1b2c3d4:0..p45#e5f6a7b8:0, offsets ignored) or the whole document, each one's chapter, scene, estimated page, shortest unique first … last words phrase, and a phrase Word's Find meets exactly once (for Ctrl+F or live.select). A phrase can be null with a |
| recipe_listA | List the cleanup recipes recipe.run can apply: the bundled ones and the user's own, each with name, version, description and source, plus any recipe files that failed validation and why. Call it to pick a recipe before recipe.run. Read-only; needs no document. |
| recipe_runA | Run a cleanup recipe (a name from recipe.list, or an inline |
| review_listA | Read a reviewed document in one go: the body's comments and tracked insertions and deletions grouped by paragraph, in document order. Each paragraph gives its address, its text as it reads now, its comment threads (id, author, date, text, quote: the text the comment covers, resolved, replies) and its changes: a deletion and an insertion by one author right next to each other are one |
| revision_acceptA | Accept tracked changes, making them plain text: by |
| revision_listA | List the tracked changes (insertions, deletions, moves, formatting, table rows and cells) in document order, each with id, type, author, date, paragraph address and text (clipped at 200 characters). A deletion and an insertion by one author right next to each other are one replacement: the insertion names the deletion in |
| revision_rejectA | Reject tracked changes, undoing them in the text (insertions removed, deletions restored): by |
| section_listA | List each section's page setup: break type, title page, even/odd headers, page-number start and format, and which header and footer story (hdr1.default, ftr2.first...) it uses per kind; null means inherited. Use the story keys to read header text with para.list (stories headers) or para.get; layout.get gives the same setup with the header and footer text, in the form layout.apply takes. Read-only. |
| server_capabilitiesA | Describe this doc-control server: API and package version, engines (file, live), which live apps are reachable, feature support per engine, every operation with its kind and summary, every error code, and whether it is a frozen build. Call it once at the start of a session; server.help gives one operation's full request and result schemas. Read-only; needs no document. |
| server_helpA | Get the JSON Schemas of one operation ( |
| style_createA | Add a new paragraph, character, table or numbering style with its parent (based_on), next and linked styles and run and paragraph formatting (e.g. run {"bold": true, "size_pt": 14}; paragraph in twips). |
| style_getA | Read one style by id or name ("Heading1" or "heading 1"): its type, parent chain, next and linked styles, how often it is used, heading level, the formatting it sets itself and its effective formatting after inheritance. Use it before style.update, or to see why text looks as it does; style.list lists all styles, para.get a paragraph's direct formatting. Read-only; STYLE_NOT_FOUND for an unknown style. |
| style_listA | List the styles defined in the document with id, name, type, parent and how many times each is used in the body. |
| style_mergeA | Merge styles: re-point every use of the |
| style_renameA | Rename a style's display |
| style_updateA | Change an existing style: its parent (based_on), next or linked style, quick-gallery flag, or run and paragraph formatting (e.g. run {"italic": true, "font": "Garamond"}; null removes a key; other keys stay). Every paragraph using the style changes with it; to format one paragraph use format.apply in doc.batch. Not a tracked change, but history.undo takes it back: the file is backed up first ( |
| styleset_exportA | Export the document's style definitions (all, the |
| styleset_export_dotxA | Write the document's style definitions (all, the |
| styleset_import_dotxA | Install the styles of a .dotx Word template ( |
| styleset_installA | Install a JSON style set (inline |
| table_getA | Read one table's grid: rows of cells, each with its first grid column, span, vertical merge (null, restart, continue) and the addresses of its paragraphs (read their text with para.get or para.list). Name it by |
| table_row_deleteA | Delete one row of a body table ( |
| table_row_insertA | Insert a row into a body table as a tracked change: after row |
| term_renameA | Rename a term or a character's name everywhere (Lucía to Elena) as one tracked batch: whole words by default, case-insensitive with case preserved (LUCÍA becomes ELENA), with optional inflections (["s"] also renames Lucías) and ignore_accents. match_level default/loose folds case, accents and punctuation. Matches inside fields or links are left and counted. Run dry_run first to check counts and the preview, then the same request without it. Use it instead of many text.replace edits. Backed up, undoable; tracked: false writes plainly. |
| text_findA | Find text or a Python regex ( |
| text_normalizeA | Normalise text (NFC, soft hyphens and zero-width characters removed, whitespace collapsed) and return a two-way offset map to the original code points, for the whole document, one paragraph or range ( |
| text_replaceA | Replace one range with new text, as a tracked change: part of a paragraph (p3#a1b2c3d4:10-15, code-point offsets), a whole paragraph (p3#a1b2c3d4) or a span across paragraphs (p3#a1b2c3d4:10..p5#e5f6a7b8:2); empty |
| toc_insertA | Insert a table of contents (a TOC field) after a body paragraph |
| xref_addA | Insert a cross-reference field at an insertion point ( |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| places |
TDQS
Scored across 68 tools
The 68-tool surface contains several clusters whose boundaries blur in practice: layout.get vs section.list, review.list vs comment.list/revision.list, doc.info vs doc.stats vs para.list/doc.outline, and history.list vs history.search. Descriptions do distinguish them, but an agent must read carefully to pick correctly, and multiple read tools target overlapping views of the same document.
Most tools follow a predictable resource_verb pattern (para_get, style_update, history_undo, text_replace, table_row_insert), and names are consistently snake_case. Minor deviations like doc_batch (itself referred to as doc.batch), live_get_selection vs live_select, and styleset_export_dotx keep it from perfect consistency.
68 tools is far too many for a single document-control server, even one covering editing, styles, revisions, fields, layout, live editing, and history. The surface could be consolidated substantially without losing capability.
Coverage is unusually thorough: paragraphs, tables, styles, comments, tracked revisions, fields, TOC/index entries, notes, layout, live app control, undo/restore history, recipes, and cross-references. No obvious lifecycle gap for a Word-document control server.