by rcarmo
Provides read, edit, and generation capabilities for Word, Excel, and PowerPoint OOXML files via an MCP server, supporting local stdio as well as HTTP, SSE, and raw TCP transports.
A Python‑based MCP server that processes OOXML documents (DOCX, XLSX, XLSM, PPTX). It can read content, inspect structure, apply patches, manage comments, insert images, and generate new files from Markdown, all through a unified set of tools.
uv tool install "git+https://github.com/rcarmo/python-office-mcp-server.git"
# or with pip
python -m pip install "git+https://github.com/rcarmo/python-office-mcp-server.git"
office-mcp-server
Add --http --port <port> to expose an HTTP/SSE endpoint.office_read(file_path="report.docx", output_format="markdown")
office_patch(file_path="budget.xlsx", changes=[{"target": "A1", "value": "12345"}], mode="dry_run")
OFFICE_MCP_HTTP_TOKEN when using the HTTP transport.office_help, office_read, office_inspect, office_patch, office_comment, office_table, office_template, office_audit, office_image).best_effort, safe, strict, dry_run.| Scenario | How the Server Helps |
|---|---|
| Consulting firms need to fill SOW templates from structured data. | Use office_help to discover the optimal workflow, then office_patch or word_generate_sow to apply data and office_audit to verify placeholders. |
| Finance teams generate Excel budget sheets from Markdown tables. | excel_from_markdown creates a workbook; office_patch updates specific cells safely; office_audit checks for missing values. |
| Marketing creates PowerPoint decks from slide outlines in Markdown. | pptx_from_markdown builds the deck; pptx_add_slide, pptx_set_notes, and office_image refine it. |
| Legal teams need to review and comment on Word contracts. | office_comment manages threaded comments, resolves or reopens them, and word_enable_track_changes tracks revisions. |
| Automation pipelines require batch inspection of document structures. | office_inspect lists sheets, tables, slides, sections, and placeholders for downstream processing. |
Q: Which file formats are supported?
A: Unencrypted .docx, .xlsx, .xlsm, and .pptx. Legacy binary formats (.doc, .xls, .ppt) and encrypted packages are not supported.
Q: Is the server actively maintained? A: The code is considered stable; only patches or hot‑fixes are applied. No formal issue tracking or support is provided.
Q: Can I run the server on Windows without Python installed?
A: Yes. Build a single‑file executable with PyInstaller (build_windows_onefile.py) to obtain dist/office-mcp-server.exe.
Q: How do I avoid argument‑size limits for large Markdown inputs?
A: Use the *_markdown_file parameters to pass a path instead of in‑line text.
Q: What transport options are available?
A: By default the server communicates over stdio. Adding --http starts an HTTP/SSE endpoint; --port enables legacy SSE, and raw TCP can be used via the pinned transport dependency.
Q: How are changes verified before committing?
A: Use mode="dry_run" to validate on a private copy, or mode="strict" with an explicit output_path to require every target to succeed before the commit.
Q: Where are template caches stored?
A: In .office-metadata-cache/ by default, overridable with the OFFICE_MCP_METADATA_CACHE_DIR environment variable.
This Python MCP server reads, edits and generates Word, Excel and PowerPoint documents. It defaults to local stdio; its pinned transport dependency also supports persistent Streamable HTTP sessions and legacy HTTP/SSE or raw TCP.
This standalone version has its own build workflows and can be installed with uv. It works with unencrypted .docx, .xlsx, .xlsm and .pptx files. Legacy binary .doc/.xls/.ppt files, password-encrypted packages and Information Rights Management are unsupported.
The code is considered stable, so it will not be maintained other than patches/hotfixes and there is zero support or issue tracking.
The current main stages covered edits on a private copy, checks that the saved package reopens, then replaces the destination once. Tools exposing mode also offer preview and strict matching. Excel cell patches preserve style dependencies and invalidate stale formula caches; Word and PowerPoint literal replacements preserve formatting across adjacent text runs. See the documentation index for operating guidance, writer limits, test instructions and format notes.
For systems architecture and consulting workflows, treat the server as core-first:
office_helpoffice_readoffice_inspectoffice_patchoffice_tableoffice_templateoffice_auditword_insert_at_anchorThese tools select document handlers from the file extension or provide cross-format workflow guidance. office_set_comment_identity configures default comment attribution separately.
| Tool | Description |
|---|---|
office_help |
Structured workflow help and recommendations for consulting/architecture document workflows |
office_read |
Read content from Word/Excel/PowerPoint as JSON or Markdown |
office_inspect |
Get document structure (sheets, slides, sections, tables, comments) |
office_patch |
Edit cells, shapes, sections, or replace placeholders |
office_comment |
Add/get/reply/delete comments; Word also supports resolve/reopen, threaded get, and reply threading |
office_table |
Read tables, add/update rows, and create Word/PowerPoint tables |
office_template |
Copy templates or analyze template structure |
office_audit |
Audit for placeholders, completion, or tracking status |
office_image |
Insert images into Word, Excel, or PowerPoint documents |
These remain discoverable, but should usually be reached from office_help, diagnostics, or a clear recovery need rather than as the default starting point.
These were a proof-of-concept approach for managing and updating specific document templates. Tools marked sow are deprecated and retained for compatibility; prefer the unified editing tools for new workflows.
| Tool | Description |
|---|---|
word_generate_sow |
Fill SOW template with structured data |
word_cleanup_sow |
Remove template artifacts and guidance (tracked) |
word_get_section_guidance |
Extract template instructions from a section |
word_parse_sow_template |
Analyze SOW template structure |
word_create_sow_from_markdown |
Create SOW from Markdown content |
word_extract_sow_structure |
Extract structured data from existing SOW |
word_insert_at_anchor |
Insert paragraphs before/after an anchor paragraph or paragraph index |
word_list_anchors |
List headings and high-signal paragraphs that can be used as insertion anchors |
word_document_map |
Return a lightweight map of sections, tables, placeholders, anchors, and warnings |
word_enable_track_changes |
Enable Word's track changes mode |
word_patch_with_track_changes |
Replace text with revision marks |
word_accept_all_changes |
Accept insertion/deletion wrappers in the main document XML; see revision limits below |
| Tool | Description |
|---|---|
pptx_add_slide |
Add new slide with specified layout |
pptx_delete_slide |
Remove a slide |
pptx_duplicate_slide |
Copy a slide with independent chart and embedded-workbook parts |
pptx_reorder_slides |
Change slide order |
pptx_hide_slide |
Hide/unhide a slide |
pptx_set_notes |
Set speaker notes |
pptx_recommend_layout |
Get best layout for content type |
pptx_log_changes |
Add change log slide |
pptx_import_slide |
Copy a slide between presentations, with optional speaker notes |
| Tool | Description |
|---|---|
word_from_markdown |
Create Word document from Markdown (supports inline text or markdown_file path for large inputs) |
excel_from_markdown |
Create Excel workbook from Markdown tables (supports inline text or markdown_file for large inputs) |
pptx_from_markdown |
Create PowerPoint from Markdown slides (supports inline text or markdown_file for large inputs) |
| Tool | Description |
|---|---|
restart_server |
Hot-reload the server after code changes |
list_supported_formats |
Show available document formats |
Tool results keep their legacy text content and add structuredContent for mappings. Failed operations set MCP isError; partial success still needs per-target checks. Tool lists support pagination and explicit conservative annotations. The read-only office://guidance/workflows resource and review_document prompt offer workflow guidance without opening files; the prompt's document-type argument supports completion.
See the uMCP integration for opt-in progress, cooperative cancellation, HTTP authentication/session rules and the pinned dependency update procedure.
# Find the best workflow for filling a consulting SOW from markdown
office_help(
goal="fill_sow_from_markdown",
document_type="word",
constraints=["preserve_template_structure"],
format="summary"
)
# Map a common consulting request onto a deterministic workflow
office_help(
task="Patch an Excel estimate workbook safely and verify the result",
format="detailed"
)
# Discover the safest path for a stakeholder review deck
office_help(
goal="create_review_deck",
document_type="powerpoint",
format="summary"
)
Word template metadata is cached on disk as JSON to avoid re-scanning the same template on every analysis call.
.office-metadata-cache/OFFICE_MCP_METADATA_CACHE_DIRword_parse_sow_template and office_template(operation="analyze")# Read Excel as Markdown
office_read(file_path="data.xlsx", output_format="markdown")
# Read specific range
office_read(file_path="data.xlsx", scope="Sheet1!A1:D10")
# Read a single worksheet
office_read(file_path="data.xlsx", scope="Sheet1")
# Read Excel formulas instead of cached values (reading never recalculates)
office_read(file_path="model.xlsx", include_formulas=True)
# Read Word document
office_read(file_path="report.docx", output_format="markdown")
# List Excel sheets
office_inspect(file_path="data.xlsx", what="sheets")
# List Word tables
office_inspect(file_path="report.docx", what="tables")
# List PowerPoint slides
office_inspect(file_path="deck.pptx", what="slides")
# Analyze a Word template and reuse cached metadata on later runs
office_template(
source_path="templates/sow.docx",
destination_path="",
operation="analyze"
)
# Discover insertion anchors before adding narrative content
word_list_anchors(file_path="report.docx", query="delivery")
# Get a compact map of a Word document
word_document_map(file_path="report.docx")
# Patch Excel cell
office_patch(
file_path="data.xlsx",
changes=[{"target": "A1", "value": "New Value"}]
)
# Patch Word placeholder
office_patch(
file_path="report.docx",
changes=[{"target": "<Customer>", "value": "Contoso"}]
)
# Patch PowerPoint shape
office_patch(
file_path="deck.pptx",
changes=[{"target": "slide:1/Title 1", "value": "New Title"}]
)
# PowerPoint soft return in a single text box
office_patch(
file_path="deck.pptx",
changes=[{"target": "slide:1/Title 2", "value": "Contoso{br}Project"}]
)
Covered mutation tools return per-target diagnostics. office_patch, office_table and office_comment accept best_effort, safe, strict and dry_run; other tools accept a mode only if it appears in their schema. Fields depend on the tool and how early validation fails:
success
status (success, partial_success, failed, skipped)
warnings
matched_targets
unmatched_targets
skipped_targets
diagnostics
next_tools
best_effort: current compatibility-oriented behavior
safe: requires a distinct output path for covered mutation flows
strict: for office_patch, any missing or failed target prevents the entire batch commit
dry_run: for office_patch, validates changes on a private copy, discards it, and leaves source and destination unchanged
For office_patch, safe requires a distinct destination but may commit the accepted subset. Use strict with a new output_path when every target is required. Receipts distinguish changes_planned from committed changes_applied, include results[].applied, and record source_sha256.
Source/destination fingerprint changes prevent publication. Process-local writer locks cover staged patches and the enrolled existing-document writers in writer scope; arbitrary external editors are not locked. Hard-linked document paths refuse mutation. Tables and comments share staged publication, but their XLSX serialisation does not preserve every opaque part as office_patch does. Output-only generation paths retain separate contracts.
Excel cell patches preserve append-only style dependencies and invalidate formula caches on cell-level formula elements across worksheets. calculation_state="recalculation-required" means an external calculation engine must refresh results; no recalculation runs here. Unsupported style registry rewrites refuse before commit. Word read-back includes tracked insertions and excludes tracked deletions.
Start with office_help, then inspect, preview, patch to a new output, and reopen/audit the result. Excel value patches coerce numeric-looking strings, currencies and percentages; this API has no force-text option for numeric identifiers. See operating limits before processing untrusted or complex files.
Install the development dependencies before running bash tests/run_tests.sh, or select related test paths as arguments. Set PYTHON=/path/to/python to choose the environment. The testing guide covers setup, focused batches, Gherkin reports and the optional LibreOffice checks. Verification never auto-formats or fixes source.
Shared acceptance scenarios execute through pytest-bdd in tests/acceptance/. Each run replaces test-results/acceptance.json with a fresh inventory and per-step outcomes. Planned, undefined, ambiguous and unexecuted cases cannot count as acceptance passes. Fixtures and shared requirements come from the tagged references/fixtures-ooxml submodule. Python reads the shared Gherkin directly and uses tests/acceptance/shared-mapping.json for local implementation status; no duplicate executable feature copy is maintained. Schema-2 document inputs have stable content IDs and one physical payload under central fixtures/<format>/<scenario-group>/; tests obtain paths from the manifest. The separate native-test catalogue staging directory is incomplete reconciliation input, not additional executable coverage.
The testing guide separates historical runtime results, fixture-migration measurements and current release checks. The uMCP integration report records its original source pin, scope-separated test counts and official-SDK smoke result; it is not the current fixture-release report. LibreOffice checks were skipped locally because the executable was unavailable. Native Microsoft Office rendering and Windows executable behaviour have not been verified locally.
The test results distinguish committed tests from local-only tests. The implementation checklist records the completed merge into main; the XLSX adoption decision explains why the server retains upstream openpyxl.
# Add row to Word table
office_table(
file_path="report.docx",
operation="add_row",
table_id="staffing",
data={"Role": "PM", "Count": "1", "Notes": "Lead"}
)
# Create table in Word
office_table(
file_path="report.docx",
operation="create",
data={
"headers": ["Phase", "Owner", "Target Date"],
"rows": [{"Phase": "Discovery", "Owner": "PM", "Target Date": "2026-04-01"}],
"insert_after_section": "Delivery Plan"
}
)
# Add table to PowerPoint
office_table(
file_path="deck.pptx",
operation="create",
table_id="3",
data={
"headers": ["Phase", "Duration"],
"rows": [["Discovery", "2 weeks"]]
}
)
# Enable Track Changes in document settings
word_enable_track_changes(file_path="draft.docx", output_path="draft-tracked.docx")
# Apply a tracked replacement
word_patch_with_track_changes(
file_path="draft-tracked.docx",
replacements={"Old wording": "New wording"},
output_path="draft-review.docx"
)
# Accept main-document insertion/deletion wrappers
word_accept_all_changes(
file_path="draft-review.docx",
output_path="draft-final.docx"
)
word_accept_all_changes traverses the main document XML, including its tables. It does not resolve revisions in separate headers, footers, footnotes or other story parts, and it does not implement move/format revision resolution or reject-all. Despite its name, it is not a complete Word revision engine. The office_patch(track_changes=...) compatibility parameter currently does not control Word dispatch; use the documented tracked workflow and inspect its output.
office_image supports raster formats (PNG, JPG/JPEG, GIF) across Word, Excel, and PowerPoint.
SVG support is currently:
| Format | Word | Excel | PowerPoint |
|---|---|---|---|
| PNG | Yes | Yes | Yes |
| SVG | Yes | No | Yes |
Notes:
# Avoid MCP argument-size limits by passing a markdown_file path
word_from_markdown(
output_path="report.docx",
markdown_file="inputs/large-report.md"
)
excel_from_markdown(
output_path="budget.xlsx",
markdown_file="inputs/budget-tables.md"
)
pptx_from_markdown(
output_path="deck.pptx",
markdown_file="inputs/deck.md"
)
word_create_sow_from_markdown(
output_path="sow.docx",
template_path="templates/Agile.docx",
markdown_file="inputs/sow.md"
)
# Audit for placeholders
office_audit(file_path="report.docx", checks=["placeholders"])
# Audit for completion
office_audit(file_path="report.docx", checks=["completion"])
Word stores comment text in word/comments.xml and thread/resolution metadata in word/commentsExtended.xml.
word_get_commentsword_get_comments(
file_path="SoW.docx",
filter="all", # all | open | resolved | mine
author=None, # used with filter="mine"
format="flat" # flat | threaded
)
Each comment now includes:
idauthorinitialsdatetextdone (resolved state)is_replyparent_idpara_idWhen format="threaded", response includes:
threads: grouped { root, replies[] }flat: full backward-compatible flat listword_resolve_commentword_resolve_comment(
file_path="SoW.docx",
comment_id="121",
resolved=True, # True=resolve, False=reopen
output_path=None,
)
Notes:
commentsExtended.xml is missing, it is created and wired into the package.w14:paraId, a paraId is synthesized for stable mapping.word_reply_to_commentword_reply_to_comment(
file_path="SoW.docx",
comment_id="121",
text="Done — updated as requested.",
author="Rui Carmo",
auto_resolve=True,
)
auto_resolve=True performs reply + resolve in one call.
office_comment)office_comment supports Word thread workflows directly:
office_comment(file_path="SoW.docx", operation="get", format="threaded")
office_comment(file_path="SoW.docx", operation="get", filter="open")
office_comment(file_path="SoW.docx", operation="resolve", target="121")
office_comment(file_path="SoW.docx", operation="reopen", target="121")
Supported operations:
add, get, reply, resolve, reopen, deleteadd, get, delete (reply/resolve/reopen return clear unsupported errors)add, get, delete (reply/resolve/reopen return clear unsupported errors)Fixture-based tests cover:
commentsIds.xml fallbackcommentsExtended.xml creationPrimary test files:
tests/test_word_comment_resolution.pytests/test_word_comment_roundtrip_fixture.pytests/test_word_comment_replies.pyInspect the document before choosing targets. Use section: targets for section content and literal text for placeholders; office_patch has no operation argument.
office_inspect(file_path="draft.docx", what="sections")
word_list_anchors(file_path="draft.docx", query="Delivery")
changes = [
{"target": "<Customer>", "value": "Contoso"},
{"target": "section:Delivery", "value": "Delivery starts after approval."}
]
office_patch(file_path="draft.docx", changes=changes, mode="dry_run")
office_patch(
file_path="draft.docx", changes=changes,
mode="strict", output_path="review.docx"
)
office_read(file_path="review.docx")
office_audit(file_path="review.docx", checks=["placeholders", "completion"])
Preview reports planned changes; strict commit requires every requested target to apply. Word replacement tools use tracked revisions, and read-back includes insertions while excluding deletions. Inspect the saved document before accepting those revisions. Package checks cannot establish that a document's meaning or rendered layout is correct.
Using uv:
uv tool install "git+https://github.com/rcarmo/python-office-mcp-server.git"
Using pip:
python -m venv .venv
. .venv/bin/activate # Windows PowerShell: .venv\\Scripts\\Activate.ps1
python -m pip install "git+https://github.com/rcarmo/python-office-mcp-server.git"
This installs the office-mcp-server command and the exact Git-pinned transport dependency. Git must be available during installation. The public PyPI package named umcp is unrelated; use the repository's dependency declaration. Requires Python >=3.10; locally tested on 3.10, 3.12 and 3.13. If a GUI client cannot find the command, configure the absolute executable path; its environment may not inherit your shell's PATH.
git clone --recurse-submodules https://github.com/rcarmo/python-office-mcp-server.git
cd python-office-mcp-server
uv sync --frozen
uv run office-mcp-server
# For development and tests: uv sync --frozen --extra dev
# In an activated pip environment: python -m pip install -e '.[dev]'
git clone --recurse-submodules https://github.com/rcarmo/python-office-mcp-server.git
cd python-office-mcp-server
python -m venv .venv
. .venv/bin/activate # Windows PowerShell: .venv\\Scripts\\Activate.ps1
python -m pip install -r requirements.txt
python office_server.py
This starts the stdio server; it waits for MCP messages rather than opening a web page. Configure the client with the same virtual-environment interpreter and an absolute script path:
{
"command": "/absolute/path/to/python-office-mcp-server/.venv/bin/python",
"args": ["/absolute/path/to/python-office-mcp-server/office_server.py"]
}
On Windows, use .venv\\Scripts\\python.exe and escape backslashes in JSON. Relative document paths depend on the server process's working directory; absolute paths avoid ambiguity.
For network clients use explicit --http; plain --port retains legacy SSE. Configure OFFICE_MCP_HTTP_TOKEN through the server environment for bearer authentication, and keep a TLS proxy and OS/path boundary for remote access. See transports. The client examples below use stdio.
VS Code (.vscode/mcp.json):
{
"servers": {
"office": {
"command": "office-mcp-server"
}
}
}
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"office": {
"command": "office-mcp-server"
}
}
}
mcp-cli (mcp_servers.json):
{
"mcpServers": {
"office": {
"command": "office-mcp-server"
}
}
}
To use uvx instead of a pre-installed binary:
{
"command": "uvx",
"args": ["--from", "git+https://github.com/rcarmo/python-office-mcp-server.git", "office-mcp-server"]
}
Some MCP clients can start with subsets of tools disabled by policy/session settings. If a call returns a disabled-tool error, enable the corresponding MCP tools in the client first, then retry. This enablement behavior is controlled by the MCP client/host, not by this server.
Create .vscode/mcp.json using the VS Code example above; the repository does not ship that file. Open the Command Palette and run MCP: List Servers to confirm office is listed.
Add the server to your Copilot CLI configuration:
# Open config file
code ~/.config/github-copilot/config.json
# Add this to the mcpServers section:
{
"mcpServers": {
"officeServer": {
"command": "python",
"args": ["/path/to/python-office-mcp-server/office_server.py"]
}
}
}
cd python-office-mcp-server
pip install -r requirements.txt
python office_server.py
Build a standalone .exe using PyInstaller.
cd python-office-mcp-server
python -m pip install -r requirements.txt
python -m pip install -r requirements-build.txt
python build_windows_onefile.py --clean
Output artifact:
dist/office-mcp-server.exepython build_windows_onefile.py --name office-server-prod
dist\office-mcp-server.exe
Use the generated executable in MCP client configuration by pointing command to the .exe path.
The Windows workflow builds the executable and checks tool discovery. Mutation workflows have been exercised through Python and clean-wheel stdio, not the Windows executable.
python-docx — Word document handlingopenpyxl — Excel workbook handlingpython-pptx — PowerPoint presentation handlingreferences/fixtures-ooxml — Tagged shared fixtures, facts and behaviour contracts used by testspyinstaller — Build-time dependency for one-file Windows executableThe server dynamically loads tool modules from tools/:
office_unified_tools.py — Unified document operationsword_tools.py — Word conversion toolsword_advanced_tools.py — Revisions, anchors, tables and legacy SOW workflowsexcel_tools.py — Excel conversion toolsexcel_advanced_tools.py — Excel advanced operations (internal)pptx_tools.py — PowerPoint conversion toolspptx_advanced_tools.py — Slide management toolspptx_slide_transfer_tools.py — Relationship-aware slide importmcp_features.py — Office metadata, structured failures, guidance and HTTP/request policymutation.py — Staging, writer locks, fingerprints, cooperative cancellation and commit receiptspackage_guard.py / package_preservation.py — Bounded admission and package differencesxlsx_preservation.py — Cell-edit style and calculation dependenciesword_spans.py / pptx_text.py — Adjacent-run text replacementTools are discovered automatically by class name pattern (*Tools).
Please log in to share your review and rating for this MCP.
Explore related MCPs that share similar capabilities and solve comparable challenges
by headroomlabs-ai
Compress tool outputs, logs, files, RAG chunks, and conversation history before they reach the LLM, keeping answers identical while saving up to 95% of tokens for JSON payloads.
by modelcontextprotocol
A Model Context Protocol server for Git repository interaction and automation.
by zed-industries
A high‑performance, multiplayer code editor designed for speed and collaboration.
by modelcontextprotocol
Model Context Protocol Servers
by modelcontextprotocol
A Model Context Protocol server that provides time and timezone conversion capabilities.
by cline
An autonomous coding assistant that can create and edit files, execute terminal commands, and interact with a browser directly from your IDE, operating step‑by‑step with explicit user permission.
by upstash
Provides up-to-date, version‑specific library documentation and code examples directly inside LLM prompts, eliminating outdated information and hallucinated APIs.
by daytonaio
Provides a secure, elastic infrastructure that creates isolated sandboxes for running AI‑generated code with sub‑90 ms startup, unlimited persistence, and OCI/Docker compatibility.
by continuedev
Enables faster shipping of code by integrating continuous AI agents across IDEs, terminals, and CI pipelines, offering chat, edit, autocomplete, and customizable agent workflows.