doc-control
PYPI · DOC-CONTROL
Edit Word documents by address: tracked changes, comments, anchors, with backups and undo.
Available components
Last scanned (7 hours ago)
Scores higher than 73% of PyPI servers
Category Documents and Files
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security100
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- Runs hatchling.build at install time, a recognised build step with no custom scripting around it. View diagnostics → Pass
- No production dependencies, so there is no dependency health to assess. View diagnostics → Pass
Provenance & Transparency97
- Source repository is publicly reachable at the declared URL. View diagnostics → Pass
- Cryptographically verified build provenance (signed, bound to nuncaeslupus/doc-control). View diagnostics → Pass
- Clear OSI-approved license (Apache-2.0).Pass
- Actively maintained (last published 0 days ago).Pass
- Disclosure check failed: no security disclosure policy was found in the source repository. See how to fix → Fail
Schema Quality & AI Usability38
- 0% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Fail
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 18106 tokens (~266/item across 68 items; 67 tools + 1 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management7
- Stability observed for 2 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage100
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 100% of tool parameters carry a description.Pass
- Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- All 4 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
- An AI judge read all 68 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
- Supports UI / widget rendering.Pass
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 16 Oct 26 +16
- Tool safety: pass → unverified ▼ security
- Malware scan: unverified → pass ▲ security
- Stability: Stability not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet. security
- Capabilities: pass → unverified ▼ functional
- Schema quality: 0 → unverified ▼ functional
- Tool coverage: 100 → unverified ▼ functional
- Stability: unverified → 0.03 ▲ functional
- Package version: 0.8.1 → 0.8.3 functional
- 15 Oct 26 59
First indexed and scored.
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 17 Oct 2026 · Analysed pypi/doc-control@0.8.3
Provenance Verified
A signed build attestation was found and verified, binding this exact artifact to the source repository it claims to come from.
| Result | Verified |
|---|---|
| Ecosystem | pypi |
| Reason | Verified |
| Discovered via | Registry attestation endpoint |
| Source repo | nuncaeslupus/doc-control |
| Certificate issuer | https://token.actions.githubusercontent.com |
| Certificate SAN | https://github.com/nuncaeslupus/doc-control/.github/workflows/release.yml@refs/heads/main |
| Rekor log index | 3281733764 |
| Predicate type | PyPI publish attestation https://docs.pypi.org/attestations/publish/v1 |
| Subject digest | sha256:478ab88818062751080dfdf2bb11e13f09948dc7d8c9a87e93d80ee0d595fc48 |
Background: How many MCP packages publish verified provenance →
Install scripts 1 script
| Hook | Tier | Command |
|---|---|---|
| build_backend | allowlisted | hatchling.build |
Background: Why install scripts are a supply-chain risk →
Dependencies 0 packages
| Packages resolved | 0 |
|---|---|
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
para_get ~208
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, `cursor` from the reply's `next`). STALE_ADDRESS if it changed since read.
| Name | Type | Req | Description |
|---|---|---|---|
| at | string | yes | Paragraph address from a read result, e.g. p142#a7b2a7b2. |
| cursor | string | – | The `next` value of the previous response, to continue the list. |
| doc | string | yes | Path to the .docx. |
| limit | integer | – | Most characters of text to return. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
para_insert ~495
Insert one new paragraph with `text` after or before an existing one (give `after` or `before`, e.g. p3#a1b2c3d4), as a tracked insertion (style it with style.apply in doc.batch). File engine: backed up first, logged for history.undo, dry_run previews, expect.sha256 refuses a changed file. tracked: false inserts plainly, on either engine. engine live inserts in the open Word/LibreOffice window (after live.open). Use doc.batch for several edits all or nothing. Returns the address_map of shifted paragraphs.
| Name | Type | Req | Description |
|---|---|---|---|
| after | string | – | Insert after this paragraph (or before). |
| author | string | – | Revision author. |
| before | string | – | Insert before this paragraph (or after). |
| doc | string | yes | Path to the .docx (live: or the file name of one open in a live app). |
| dry_run | boolean | – | Preview only; write nothing. |
| engine | – | – | `live` edits the document open in Word or LibreOffice (see live.open). |
| expect | object | – | 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. |
| tag | string | – | Appended to the author. |
| text | string | yes | Text of the new paragraph. |
| tracked | boolean | – | 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… |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
para_list ~318
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 `cursor` set to the reply's `next`.
| Name | Type | Req | Description |
|---|---|---|---|
| cursor | string | – | The `next` value of the previous response, to continue the list. |
| doc | string | yes | Path to the .docx. |
| limit | integer | – | Most items to return; a response is also capped at about 8,000 bytes. |
| normalized | boolean | – | Add `normalized`, the text as `text.normalize` gives it. |
| pages | boolean | – | Add the estimated `page` and `page_label` per paragraph, and `page_basis`, `rendered_marks` and `page_count` (see page.estimate). |
| stories | array | – | Stories to read (default ["body"]): "notes" adds footnotes and endnotes, each after the paragraph holding its mark; "headers" adds headers and footers, after the body. Their addresses carry a prefix… |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
para_locate ~321
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 `reason` (empty, duplicate). structure: false skips chapter detection for speed. Use it to tell a writer where a passage is; page.estimate gives only pages. Read-only; paged at about 8,000 bytes with `cursor`.
| Name | Type | Req | Description |
|---|---|---|---|
| at | string | – | Paragraph address or range (offsets ignored), e.g. p142#a7b2a7b2; default the whole document (empty paragraphs left out). |
| cursor | string | – | The `next` value of the previous response, to continue the list. |
| doc | string | yes | Path to the .docx. |
| limit | integer | – | Most items to return; a response is also capped at about 8,000 bytes. |
| overrides | array | – | Force or deny a chapter or scene at paragraphs by fingerprint. |
| profile | object | – | Detection settings for this document. |
| structure | boolean | – | false: skip chapter, part and scene detection (they come back null), for callers that keep their own structure; faster on a single paragraph. Default true. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
recipe_list ~62
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.
Input schema present but exposes no named parameters.
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
recipe_run ~175
Run a cleanup recipe (a name from recipe.list, or an inline `definition`) over the document and return the edits it proposes as a ready doc.batch request (`batch`, guarded by expect.sha256), repeating until the text is stable. Writes nothing itself: review the proposal, then apply it with doc.batch (dry_run there to preview). RECIPE_INVALID for an unknown or invalid recipe; edits that would touch unsupported content are listed under skipped. Refused for .txt/.md/.odt sources, which cannot be written.
| Name | Type | Req | Description |
|---|---|---|---|
| definition | object | – | An inline declarative recipe (same schema as a stored one). |
| doc | string | yes | Path to the .docx file. |
| dry_run | boolean | – | Accepted for symmetry; recipe.run never writes. |
| recipe | string | – | Name from recipe.list. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
revision_accept ~286
Accept tracked changes, making them plain text: by `ids` (from revision.list), by revision `author`, in a paragraph or run (`at`, p3#a1b2c3d4..p9#e5f6a7b8), or `all`. Not itself a tracked change: on the file engine the file is backed up first and the write is logged for history.undo; dry_run previews counts; expect.sha256 refuses a changed file. Use revision.reject to drop changes instead, doc.batch to accept and reject in one write. Returns counts and the revisions resolved.
| Name | Type | Req | Description |
|---|---|---|---|
| all | boolean | – | true: every revision in the document. |
| at | string | – | Paragraph p3#fp or run p3#fp..p9#fp. |
| author | string | – | Exact revision author. |
| doc | string | yes | Path to the .docx (live: or the file name of one open in a live app). |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| ids | array | – | Accept the revisions with these ids (from revision.list). |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
revision_list ~271
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). Filter by `author` or `type`; stories notes or headers adds their changes. Use the ids with revision.accept or revision.reject; doc.stats counts changes by type. Read-only; paged: about 8,000 bytes per reply (limit up to 1,000), continue with `cursor` set to the reply's `next`.
| Name | Type | Req | Description |
|---|---|---|---|
| author | string | – | Only this author. |
| cursor | string | – | The `next` value of the previous response, to continue the list. |
| doc | string | yes | Path to the .docx. |
| limit | integer | – | Most items to return; a response is also capped at about 8,000 bytes. |
| stories | array | – | Stories to list (default ["body"]): "notes" adds footnotes and endnotes, "headers" headers and footers, after the body's revisions; their addresses carry a prefix (fn3/p1#…, hdr1.default/p1#…). Row a… |
| type | string | – | Only this type. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
revision_reject ~297
Reject tracked changes, undoing them in the text (insertions removed, deletions restored): by `ids` (from revision.list), by revision `author`, in a paragraph or run (`at`, p3#a1b2c3d4..p9#e5f6a7b8), or `all`. Not itself a tracked change: on the file engine the file is backed up first and the write is logged for history.undo; dry_run previews counts; expect.sha256 refuses a changed file. Use revision.accept to keep changes instead, doc.batch to accept and reject in one write. Returns counts and the revisions resolved.
| Name | Type | Req | Description |
|---|---|---|---|
| all | boolean | – | true: every revision in the document. |
| at | string | – | Paragraph p3#fp or run p3#fp..p9#fp. |
| author | string | – | Exact revision author. |
| doc | string | yes | Path to the .docx (live: or the file name of one open in a live app). |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| ids | array | – | Reject the revisions with these ids (from revision.list). |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
section_list ~112
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.
| Name | Type | Req | Description |
|---|---|---|---|
| doc | string | yes | Path to the .docx. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
server_capabilities ~86
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.
Input schema present but exposes no named parameters.
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
server_help ~133
Get the JSON Schemas of one operation (`op`, e.g. "para.get": its request schema and its result's output_schema), or of every operation when `op` is left out. A doc.batch kind ("comment.reply", "para.move"...) gives the fields it takes inside `ops`, under batch_operations; a name that is both gets both. Old names (before 0.7.0) give the renamed operation. Call it before using an operation whose fields you are unsure of; server.capabilities lists the operations. Read-only.
| Name | Type | Req | Description |
|---|---|---|---|
| op | string | – | Operation or batch operation kind. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
style_create ~419
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). `id` defaults from `name`. Refused (STYLE_CONFLICT) when the id or name exists: use style.update to change a style, style.rename to rename one, styleset.install to add many. Not a tracked change, but history.undo takes it back: the file is backed up first (`backup`); dry_run previews.
| Name | Type | Req | Description |
|---|---|---|---|
| based_on | string | – | Parent style id or name; '' for none. |
| custom | boolean | – | A user-defined (not built-in) style. |
| default | boolean | – | The default style of its type. |
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| id | string | – | Style id (default: from the name). |
| link | string | – | Linked paragraph/character style; '' for none. |
| name | string | yes | Display name. |
| next | string | – | Style of the next paragraph; '' for none. |
| paragraph | object | – | Paragraph formatting (twips): alignment, indent{left,right,first_line,hanging}, spacing{before,after,line,line_rule}, keep_next, keep_lines, page_break_before, outline_level; null removes a key. |
| quick | boolean | – | Show in the quick-style gallery. |
| run | object | – | Character formatting: bold, italic, small_caps, strike, underline, font, size_pt, color, highlight, vertical_align; null removes a key. |
| type | – | – | Kind of style (default paragraph). |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
style_get ~122
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.
| Name | Type | Req | Description |
|---|---|---|---|
| doc | string | yes | Path to the .docx. |
| style | string | yes | Style id or name. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
style_list ~197
List the styles defined in the document with id, name, type, parent and how many times each is used in the body. `type` keeps one kind (paragraph, character, table, numbering); used_only drops unused ones. Use it to find styles to clean up or reuse; style.get gives one style's full and inherited formatting. Read-only; paged: about 8,000 bytes per reply (limit up to 1,000), continue with `cursor` set to the reply's `next`.
| Name | Type | Req | Description |
|---|---|---|---|
| cursor | string | – | The `next` value of the previous response, to continue the list. |
| doc | string | yes | Path to the .docx. |
| limit | integer | – | Most items to return; a response is also capped at about 8,000 bytes. |
| type | string | – | Only this kind of style. |
| used_only | boolean | – | Only styles used at least once. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
style_merge ~221
Merge styles: re-point every use of the `from` style or styles (ids or names) to `into` in the body, notes, headers and other styles, then delete the `from` styles. Use it to clean up duplicate styles; style.rename only renames, style.update changes formatting. Not a tracked change, but history.undo takes it back; it removes style definitions, so the file is backed up first (`backup`); check with dry_run first. STYLE_NOT_FOUND for an unknown style.
| Name | Type | Req | Description |
|---|---|---|---|
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| from | – | yes | Style id or name, or a list of them (they are removed). |
| into | string | yes | Style id or name. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
style_rename ~217
Rename a style's display `name` and/or `id` (id defaults from the name); every reference follows: paragraphs, runs, headers, notes, numbering, and based_on, next and link in other styles. STYLE_CONFLICT if the new name or id is taken. Use style.merge to fold one style into another instead. Not a tracked change, but history.undo takes it back: the file is backed up first (`backup`); dry_run previews.
| Name | Type | Req | Description |
|---|---|---|---|
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| id | string | – | Style id (default: from the name). |
| name | string | – | Display name. |
| style | string | yes | Style id or name. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
style_update ~355
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 (`backup`); dry_run previews. STYLE_NOT_FOUND for an unknown style.
| Name | Type | Req | Description |
|---|---|---|---|
| based_on | string | – | Parent style id or name; '' for none. |
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| link | string | – | Linked paragraph/character style; '' for none. |
| next | string | – | Style of the next paragraph; '' for none. |
| paragraph | object | – | Paragraph formatting (twips): alignment, indent{left,right,first_line,hanging}, spacing{before,after,line,line_rule}, keep_next, keep_lines, page_break_before, outline_level; null removes a key. |
| quick | boolean | – | Show in the quick-style gallery. |
| run | object | – | Character formatting: bold, italic, small_caps, strike, underline, font, size_pt, color, highlight, vertical_align; null removes a key. |
| style | string | yes | Style id or name. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
styleset_export ~143
Export the document's style definitions (all, the `styles` named, or custom_only) as a JSON style set, returned and also written to `out` when given (never overwrites an existing file). Feed it to styleset.install on another document to copy the look; styleset.export_dotx writes a Word template instead. The document is not changed.
| Name | Type | Req | Description |
|---|---|---|---|
| custom_only | boolean | – | Only user-defined styles. |
| doc | string | yes | Path to the .docx. |
| name | string | – | Set name. |
| out | string | – | Also write the JSON here. |
| styles | array | – | Only these styles (ids or names). |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
styleset_export_dotx ~158
Write the document's style definitions (all, the `styles` named, or custom_only) to a new .dotx Word template at `out` (must not exist), for Word users to attach or base documents on. The document itself is never changed. styleset.import_dotx brings a template's styles into a document; styleset.export gives a JSON style set instead. Returns the path, style count and size.
| Name | Type | Req | Description |
|---|---|---|---|
| custom_only | boolean | – | Only user-defined styles. |
| doc | string | yes | Path to the .docx. |
| name | string | – | Set name. |
| out | string | yes | New .dotx to create. |
| styles | array | – | Only these styles (ids or names). |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
styleset_import_dotx ~215
Install the styles of a .dotx Word template (`path`) into the document: new styles are added, existing ids replaced (on_conflict replace, default), kept (skip) or refused (error: STYLE_CONFLICT). Use it to apply a house template; styleset.install takes a JSON style set, style.create adds one style. Not a tracked change, but history.undo takes it back: the file is backed up first (`backup`); dry_run previews.
| Name | Type | Req | Description |
|---|---|---|---|
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| on_conflict | – | – | A style id already in the document (default replace). |
| path | string | yes | The .dotx to read. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
styleset_install ~238
Install a JSON style set (inline `styleset`, or a file at `path`, as styleset.export writes it) into the document: new styles are added, existing ids replaced (on_conflict replace, default), kept (skip) or refused (error: STYLE_CONFLICT). Use it to copy styles between documents; styleset.import_dotx reads a Word template, style.create adds one style. Not a tracked change, but history.undo takes it back: the file is backed up first (`backup`); dry_run previews.
| Name | Type | Req | Description |
|---|---|---|---|
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| on_conflict | – | – | A style id already in the document (default replace). |
| path | string | – | Or a style set file. |
| styleset | object | – | The style set (inline). |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
table_get ~239
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` (1-based, body only, the `cell.table` para.list shows) or by `at`, any paragraph address in it, also in notes and headers. Use it before table.row.insert/delete or to edit cells with text.replace. Read-only; ANCHOR_NOT_FOUND for no such table.
| Name | Type | Req | Description |
|---|---|---|---|
| at | string | – | Instead of `table`: any paragraph address in the table, in any story (`fn3/p1#…`, `hdr1.default/p1#…`); the reply's `table` is then numbered within that story. |
| doc | string | yes | Path to the .docx. |
| table | integer | – | Table number in the main story, 1-based in document order (the `cell.table` of a paragraph row); text-box and DrawingML tables are not counted. Tables of notes, headers and footers are reached with `… |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
table_row_delete ~250
Delete one row of a body table (`table` as table.get numbers it, `row` 1-based) as a tracked change the writer can reject. Refused (UNSUPPORTED_CONTENT) for a row with a vertically merged cell. Backed up and logged for history.undo; dry_run previews; expect.sha256 refuses a changed file. Use doc.batch to change several rows at once, para.delete for paragraphs outside tables.
| Name | Type | Req | Description |
|---|---|---|---|
| author | string | – | Revision author. |
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| row | integer | yes | The row, 1-based. |
| table | integer | yes | Table number as `table.get` numbers it: 1-based, in document order, main story only (a table in a note, header or footer cannot be named here). |
| tag | string | – | Appended to the author. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
table_row_insert ~310
Insert a row into a body table as a tracked change: after row `after_row` (0: before the first), with one text per cell in `cells` (e.g. ["2024", "12.5"]), matching the row it follows (SCHEMA_INVALID otherwise). Refused (UNSUPPORTED_CONTENT) between two rows a vertical merge spans. Backed up and logged for history.undo; dry_run previews; expect.sha256 refuses a changed file. Use doc.batch for several rows at once.
| Name | Type | Req | Description |
|---|---|---|---|
| after_row | integer | yes | Insert after this row (1-based); 0 inserts before the first row. |
| author | string | – | Revision author. |
| cells | array | yes | One text per cell of the row it follows (the first row for after_row 0); a horizontally merged cell is one cell. |
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| table | integer | yes | Table number as `table.get` numbers it: 1-based, in document order, main story only (a table in a note, header or footer cannot be named here). |
| tag | string | – | Appended to the author. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
term_rename ~636
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.
| Name | Type | Req | Description |
|---|---|---|---|
| author | string | – | Revision author. |
| case_sensitive | boolean | – | Exact spelling only; `to` is used as written. |
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Plan and preview only; write nothing. |
| expect | object | – | 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. |
| from | string | yes | Term to rename. |
| ignore_accents | boolean | – | `Lucia` also matches `Lucía`. |
| inflections | array | – | Suffixes that follow the term: "s" renames Lucías to Elenas; {"from": "o", "to": "a"} renames Lucíao to Elenaa. |
| match_level | string | – | Fold the search as `text.find` does: `default` ignores case, accents and punctuation (symbols such as `$` still count), `loose` drops symbols too; `exact` is the rename as without it. When passed, Wo… |
| preserve_case | boolean | – | LUCÍA becomes ELENA, lucía becomes elena, Lucía becomes Elena. |
| preview_limit | integer | – | Most changes echoed back in `preview`. |
| tag | string | – | Appended to the author. |
| to | string | yes | New term. |
| tracked | boolean | – | false: a plain write for a change the writer already approved: the same edits, with this call's own revisions accepted in the same verified write (no revision marks; undo works). Refused (UNSUPPORTED… |
| whole_word | boolean | – | Whole words only. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
text_find ~599
Find text or a Python regex (`regex`) in the document; each match comes back as a range (p8#b72009e4:0-8) with context, ready for text.replace or anchor.create. ignore_case, ignore_accents (maria finds María), whole_word and match_level (default: also ignores punctuation) loosen it; stories adds notes or headers. The first page gives `total`, and query_word, the query as typed in Word's Find box. Use para.locate to describe where a paragraph is, history.search for removed text. Read-only; limit (default 20) per page, `cursor` continues; stops after 10 s with `more`.
| Name | Type | Req | Description |
|---|---|---|---|
| context | integer | – | Characters of surrounding text on each side of a match. |
| cursor | string | – | The `next` value of the previous page. |
| doc | string | yes | Path to the .docx file. |
| ignore_accents | boolean | – | Ignore accents: `maria` finds `María`. A regex must be written without accents then. |
| ignore_case | boolean | – | Ignore case. |
| limit | integer | – | Most matches to return; more are reached with `cursor`. |
| match_level | string | – | Fold a literal query: `default` ignores case, accents and punctuation (symbols such as `$` still count), `loose` drops symbols too; `exact` is the search as without it. When passed, Word's Find codes… |
| query | string | yes | Text to find (at most 1000 characters), or a Python regex if `regex`. |
| regex | boolean | – | Treat `query` as a regex. |
| stories | array | – | Stories to read (default ["body"]): "notes" adds footnotes and endnotes, each after the paragraph holding its mark; "headers" adds headers and footers, after the body. Their addresses carry a prefix… |
| whole_word | boolean | – | Match only whole words (no letter, digit or mark on either side). |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
text_normalize ~238
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 (`at`, p142#a7b2a7b2:10-15), or a `text` string (give `doc` or `text`). Use it to compare or search text robustly and map found offsets back to addresses for text.replace; para.list normalized adds just the text. Read-only; paged at about 8,000 bytes with `cursor`; a very long paragraph comes in parts.
| Name | Type | Req | Description |
|---|---|---|---|
| at | string | – | Paragraph address or range, e.g. p142#a7b2a7b2:10-15. |
| cursor | string | – | The `next` value of the previous response, to continue the list. |
| doc | string | – | Path to a .docx. |
| limit | integer | – | Most items to return; a response is also capped at about 8,000 bytes. |
| text | string | – | Text to normalise instead of `doc`. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
text_replace ~550
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 `text` deletes it. Get ranges from text.find or para.get. File engine: backed up first, logged for history.undo, dry_run previews, expect.sha256 refuses a changed file. tracked: false writes plainly, on either engine. engine live edits the open app. STALE_ADDRESS if the paragraph changed since read. Use term.rename for a name everywhere, doc.batch for several edits.
| Name | Type | Req | Description |
|---|---|---|---|
| at | string | yes | Range p3#fp:10-15, p3#fp or p3#fp:10..p5#fp:2. |
| author | string | – | Revision author. |
| doc | string | yes | Path to the .docx (live: or the file name of one open in a live app). |
| dry_run | boolean | – | Preview only; write nothing. |
| engine | – | – | `live` edits the document open in Word or LibreOffice (see live.open). |
| expect | object | – | 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. |
| tag | string | – | Appended to the author. |
| text | string | yes | New text; empty deletes the range. |
| tracked | boolean | – | 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… |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
toc_insert ~281
Insert a table of contents (a TOC field) after a body paragraph `after` (p1#a1b2c3d4), as tracked insertions: a title (default "Contents", "" for none), the field listing heading levels `levels` (default "1-3") with a placeholder result, and a closing paragraph. Run field.update next to fill in the entries and page numbers (until then field.list shows it stale). Backed up and undoable (history.undo); dry_run previews. Returns the field paragraph's address.
| Name | Type | Req | Description |
|---|---|---|---|
| after | string | yes | Address of the body paragraph it goes after. |
| author | string | – | Revision author. |
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| levels | string | – | Heading levels it lists, e.g. "1-3" (default) or "2". |
| tag | string | – | Appended to the author. |
| title | string | – | Title paragraph above it (default "Contents"); "" for none. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
xref_add ~308
Insert a cross-reference field at an insertion point (`at`: p14#a1b2c3d4:20-20, or a paragraph address for its end), pointing `to` a caption or another body paragraph. show number (default: "Table 3" for a caption), page (a PAGEREF) or text. The target gets a hidden bookmark when it has none; run field.update afterwards to fill in the shown value. A tracked insertion; backed up and undoable (history.undo); dry_run previews. Add captions with caption.add first.
| Name | Type | Req | Description |
|---|---|---|---|
| at | string | yes | Insertion point: p<n>#<fp>:<k>-<k>, or a paragraph address for its end. |
| author | string | – | Revision author. |
| doc | string | yes | Path to the .docx. |
| dry_run | boolean | – | Preview only; write nothing. |
| expect | object | – | 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. |
| show | – | – | number (default): a caption's label and number, or a paragraph's number; page: the page it is on; text: the caption or paragraph text. |
| tag | string | – | Appended to the author. |
| to | string | yes | Address of the caption or heading it points at. |
| Name | Type | Req | Description |
|---|---|---|---|
| api | string | yes | API version (1.0). |
| doc | object | – | The document read or written: path, sha256 and paragraph count. |
| next | string|null | yes | Cursor for the next page (pass as cursor), or null. |
| ok | boolean | yes | Always true on success. |
| op | string | yes | The operation that ran. |
| result | object | yes | What the operation returns. |
| warnings | array | yes | Things to know about the result. |
No examples provided.
How do I install the doc-control MCP server?
doc-control runs locally as a PyPI package, launched with uvx doc-control. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
pypi · doc-control
claude mcp add nuncaeslupus-doc-control -- uvx doc-control
What is the doc-control MCP server?
doc-control is an MCP server listed in the public MCP registry as io.github.nuncaeslupus/doc-control. Edit Word documents by address: tracked changes, comments, anchors, with backups and undo. This page covers its PyPI package (doc-control).
Is the doc-control MCP server safe to use?
doc-control scores 75 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 17 October 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the doc-control MCP server expose?
doc-control exposes 67 tools: anchor_create, anchor_resolve, caption_add, comment_add, comment_list, and 62 more. Their descriptions and schemas cost roughly 18,102 tokens of context every time the server is loaded.
Is the doc-control MCP server still maintained?
doc-control is still listed as active in the MCP registry. We last reached this channel on 17 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the doc-control MCP server under?
doc-control declares the Apache-2.0 licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.