word-mcp
Drives LibreOffice over UNO on Linux to open, measure, and fix .docx documents: reports page counts, locates strings by page, maps headings and sections with page ranges, extracts page text, formats paragraphs (keep-with-next, widow control), refreshes fields and tables of contents, and exports to PDF using LibreOffice's own pagination engine.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@word-mcp open report.docx and show me the outline with page numbers"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
word-mcp
An MCP server that measures and fixes the page layout of .docx documents using a real word
processor rather than a converter. Converters paginate differently from Word, and over a few
hundred pages the drift adds up, so the numbers here come from the application itself.
Platform | Driven through | Whose pagination |
macOS | Microsoft Word over Apple Events | Word |
Windows | Microsoft Word over COM | Word |
Linux | LibreOffice over UNO | LibreOffice |
The engine follows the platform; WORD_MCP_BACKEND=mac|win|uno overrides it. Every answer
carries a fidelity field saying whose numbers these are.
Example
Asking a document where its parts begin and how long they are:
>>> word_status()
{'engine': 'libreoffice', 'fidelity': 'libreoffice', 'available': True,
'version': '/usr/bin/soffice', 'document': None, 'detail': None}
>>> word_open('/tmp/report.docx')
'/tmp/report.docx'
>>> word_outline()
{
"total_pages": 13,
"fidelity": "libreoffice",
"sections": [
{ "name": "Introduction", "page": 1, "pages": 2 },
{ "name": "Background", "page": 3, "pages": 3 },
{ "name": "Method", "page": 6, "pages": 3 },
{ "name": "Results", "page": 9, "pages": 2 },
{ "name": "Conclusions", "page": 11, "pages": 2 },
{ "name": "Appendix A", "page": 13, "pages": 1 }
]
}
>>> word_find_page('Complexity')
{'text': 'Complexity', 'pages': [7, 7, 7, 7, 8, 8]}Keeping a caption attached to the figure above it, so a page break never separates them:
>>> word_format_paragraphs(contains='Figure 1.', keep_with_next=True, widow_control=True)
1
>>> word_save()
'saved'Sections can also be defined by text instead of by heading level, which is useful when a document has no outline levels set:
>>> word_outline(markers=['Introduction', 'Method', 'Conclusions'])The last occurrence of each marker is taken, so mentions inside a table of contents are skipped.
Related MCP server: docx-mcp
Layout
wordmcp/
├── models.py immutable result and parameter types
├── engine.py DocumentEngine: the contract an engine fulfils
├── engines/
│ ├── __init__.py engine selection; dependencies are passed in, not read from the module
│ ├── applescript.py Word on macOS
│ ├── com.py Word on Windows
│ └── uno.py LibreOffice
├── service.py document operations, expressed once
├── tools/
│ ├── session.py open, close, save, status
│ ├── measure.py page count, search, headings, outline, page text, self-test
│ ├── modify.py formatting, field updates, PDF export
│ └── escape.py engine-native code, registered only when allowed
├── server.py assembles a server from the tool groups
└── __main__.py composition root: pick an engine, serve over stdioEach tool module exposes register(mcp, service) and keeps nothing at module scope, so the
groups stay independent and no global server instance is needed. Tool bodies are one line:
they delegate to the service, which holds the logic and is what the tests exercise.
Dependencies are injected through constructors: an engine goes into DocumentService, the
service goes into create_server. There is no global state, so the logic runs against a stub:
server = create_server(DocumentService(StubEngine()), allow_raw=False)Tools
Tool | What it does |
| which engine is active, whether it answers, what is open |
| open, close, save |
| number of pages |
| pages on which a string occurs |
| headings with outline level and page |
| start page and length of every top-level part |
| text placed on a given page |
| refresh fields and tables of contents |
| keep with next, keep together, widow control, spacing |
| export to PDF with the application's own engine |
| run every operation and report what this machine supports |
| engine-native code; registered only when |
Installing
git clone https://github.com/<user>/word-mcp.git
cd word-mcp
uv syncmacOS. Needs Microsoft Word and automation permission: System Settings, Privacy and Security, Automation, the application running this server, Microsoft Word. The first call raises the system prompt.
Windows. Needs Microsoft Word: uv sync --extra windows, which adds pywin32.
Linux. Needs LibreOffice and the system Python-UNO package:
sudo apt install libreoffice python3-uno. The server starts soffice headless by itself;
WORD_MCP_UNO_PORT sets the socket. Run it with the interpreter that can see uno, which is
usually the system python3.
Connecting
{
"mcpServers": {
"word": {
"command": "uv",
"args": ["run", "--directory", "/path/to/word-mcp", "word-mcp"],
"env": { "WORD_MCP_ALLOW_RAW": "1" }
}
}
}On Linux the system interpreter is usually required:
{
"mcpServers": {
"word": {
"command": "python3",
"args": ["-m", "wordmcp"],
"env": { "PYTHONPATH": "/path/to/word-mcp" }
}
}
}WORD_MCP_ALLOW_RAW=1 registers word_run_raw, which runs code in the engine's own language:
AppleScript on macOS, a Python expression over the live application objects on Windows and
Linux. It exists so a failing call can be repaired without editing the server, but it is
arbitrary code execution; drop the variable once things settle.
Restart the client after changing its configuration.
Development
uv run pytest # service logic against a stub engine, no word processor needed
uv run ruff check .State of testing
The LibreOffice engine has been exercised on a real 161-page document: page count, text search, heading map, section lengths, page text, paragraph formatting, field updates and the escape hatch.
The Word engines for macOS and Windows follow documented interfaces but have not been run on a
live machine. Start with word_selftest. The likely places to adjust on macOS are
compute statistics and get information ... information type page number; the corresponding
COM calls on Windows are more stable.
Licence
MIT
Available Tools
13 toolsword_closeWord CloseA
Close the current document, saving it or discarding changes.
Inputs: save. Returns: result
word_export_pdfWord Export PdfC
Export the document to PDF with the word processor's own engine.
Inputs: path, pdf_path. Returns: Where the exported PDF landed.
word_find_pageWord Find PageC
List the pages on which a piece of text occurs, in document order.
Inputs: text (required), path, limit. Returns: Pages on which a search string occurs, in document order.
word_format_paragraphsWord Format ParagraphsA
Set layout properties on every paragraph containing a string.
keep_with_next ties a heading or a caption to what follows, keep_together forbids splitting a paragraph across pages, widow_control switches widow and orphan control on. Spacing is in points. Returns how many paragraphs changed.
Inputs: contains (required), path, space_after, space_before, +3 more. Returns: result
word_headingsWord HeadingsC
List every heading with its outline level and the page it starts on.
Inputs: path, max_level. Returns: result
word_openWord OpenC
Open a document and make it the current one.
Inputs: path (required). Returns: result
word_outlineWord OutlineB
Give the start page and length of each top-level part of the document.
Pass markers to define the parts by text instead of by heading level.
Inputs: path, markers. Returns: Section map of a document.
word_page_countWord Page CountC
Count the pages of a document as the word processor lays it out.
Inputs: path. Returns: result
word_page_textWord Page TextC
Read the text that the word processor placed on a given page.
Inputs: page (required), path. Returns: Text the engine placed on one page.
word_saveWord SaveB
Save the current document in place.
Inputs: no named parameters. Returns: result
word_selftestWord SelftestC
Try every operation on a document and report which ones this machine supports.
Inputs: path (required). Returns: result
word_statusWord StatusB
Report which word processor drives documents here and whether it answers.
Inputs: no named parameters. Returns: What is driving documents on this machine and whether it answers.
word_update_fieldsWord Update FieldsC
Refresh fields and tables of contents so their page numbers become current.
Inputs: toc, path. Returns: Outcome of refreshing fields and tables of contents.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 13 tools
Most tools target clearly distinct operations: lifecycle (open/close/save), page inspection, text search, outline extraction, formatting, field refresh, and PDF export. The main possible overlap is between word_headings and word_outline, but their descriptions distinguish all headings from customizable top-level parts.
All tools use a consistent word_ prefix and snake_case naming, making the family easy to recognize. The only minor deviation is that some names are noun-like (word_page_count, word_headings) while others are verb-like (word_open, word_find_page).
With 13 tools, the server sits comfortably in the well-scoped range. Each tool appears to cover a specific document operation or inspection task without excessive fragmentation.
The surface covers opening, saving, closing, layout inspection, page text reading, paragraph formatting, field updates, and PDF export. However, it lacks document creation and direct content editing operations such as inserting or replacing text, which are notable gaps for a Word automation server.
Related MCP Connectors
Create Word .docx files from sections or markdown, fill templates, and read text from a .docx.
Automate enterprise-grade documents from templates, merge and 100+ conversions: PDF, Office, HTML.
Convert, create and edit Word, PowerPoint, Excel and PDF documents from any AI agent.
Convert DOCX documents to and from PDF, TXT, HTML, ODT, JPG and RTF.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables Word document generation from templates using Jinja2 syntax and parsing of DOCX, PDF, and Excel files to extract structured content, metadata, and text.17 npm1MIT
- AlicenseBqualityDmaintenanceEnables comprehensive management of Microsoft Word documents with 30+ tools for reading, writing, formatting, template merging, image extraction, equation extraction, and style application.241MIT
- FlicenseBqualityDmaintenanceMCP server for automated visual-layout QA of DOCX documents, enabling rendering, measurement, rule checking, patching, and diffing in a closed loop.7-
- AlicenseNot gradedqualityCmaintenanceEnables creating, editing, reading, and converting Word, Excel, PowerPoint, PDF, and plain-text documents, including live editing of open Office documents, template-based document generation, and high-fidelity PDF/PNG rendering.3MIT