Excel MCP Server for manipulating Excel files
Project description
A Model Context Protocol (MCP) server that lets you manipulate Excel files without needing Microsoft Excel installed. Create, read, and modify Excel workbooks with your AI agent.
Features
- 📊 Excel Operations: Create, read, update workbooks and worksheets
- 📈 Data Manipulation: Formulas, formatting, charts, pivot tables, and Excel tables
- 🔍 Data Validation: Built-in validation for ranges, formulas, and data integrity
- 🎨 Formatting: Font styling, colors, borders, alignment, and conditional formatting
- 📋 Table Operations: Create and manage Excel tables with custom styling
- 📊 Chart Creation: Generate various chart types (line, bar, pie, scatter, etc.)
- 🔄 Pivot Tables: Create dynamic pivot tables for data analysis
- 🔧 Sheet Management: Copy, rename, delete worksheets with ease
- 🔌 Triple transport support: stdio, SSE (deprecated), and streamable HTTP
- 🌐 Remote & Local: Works both locally and as a remote service
Development and CI parity
Install dev extras so local runs match PR and release gates (docs/architecture/ci-cd-packaging-governance.md):
pip install -e ".[dev]"
python -m pytest
hatch build
python -m twine check dist/*
From the repository root with uv (uses uv.lock if present):
uv sync --extra dev
uv run python -m pytest
uv run hatch build
uv run python -m twine check dist/*
The PyPI distribution name is excel-com-mcp (same as [project].name in pyproject.toml). A legacy console entrypoint excel-mcp-server is also installed. Examples below use excel-com-mcp for uvx and MCP JSON so they stay aligned with manifest.json → server.mcp_config (command / args).
Usage
The server supports three transport methods:
1. Stdio Transport (for local use)
uvx excel-com-mcp stdio
{
"mcpServers": {
"excel": {
"command": "uvx",
"args": ["excel-com-mcp", "stdio"]
}
}
}
Local clone in Cursor (this repo): MCP often starts uv with no project working directory, so uv run --extra com … fails with *“--extra com has no effect when used outside of a project* and *program not found*. Pass the project explicitly with **--project** (absolute path to the folder that contains pyproject.toml`):
{
"mcpServers": {
"excel-mcp-local": {
"command": "uv",
"args": [
"run",
"--project",
"C:/Users/YOU/mcp/excel-mcp-server",
"--extra",
"com",
"excel-com-mcp",
"stdio"
]
}
}
}
On Windows you can use C:\\\\Users\\\\YOU\\\\... instead of forward slashes. Omit "com" on non-Windows installs. You can add "cwd" with the same path as a hint for other tools, but --project is what fixes uv run.
2. SSE Transport (Server-Sent Events - Deprecated)
uvx excel-com-mcp sse
SSE transport connection:
{
"mcpServers": {
"excel": {
"url": "http://localhost:8000/sse",
}
}
}
3. Streamable HTTP Transport (Recommended for remote connections)
uvx excel-com-mcp streamable-http
Streamable HTTP transport connection:
{
"mcpServers": {
"excel": {
"url": "http://localhost:8000/mcp",
}
}
}
Environment Variables & File Path Handling
SSE and Streamable HTTP Transports
When running the server with the SSE or Streamable HTTP protocols, you must set the EXCEL_FILES_PATH environment variable on the server side. This variable tells the server where to read and write Excel files.
- If not set, it defaults to
./excel_files. - With these transports, tool
filepathvalues must be relative to that directory (e.g.reports/q1.xlsx); absolute paths and directory traversal are rejected.
You can also set the FASTMCP_PORT environment variable to control the port the server listens on (default is 8017 if not set).
- Example (Windows PowerShell):
$env:EXCEL_FILES_PATH="E:\MyExcelFiles" $env:FASTMCP_PORT="8007" uvx excel-com-mcp streamable-http
- Example (Linux/macOS):
EXCEL_FILES_PATH=/path/to/excel_files FASTMCP_PORT=8007 uvx excel-com-mcp streamable-http
Stdio Transport
When using the stdio protocol, the file path is provided with each tool call, so you do not need to set EXCEL_FILES_PATH on the server. The server will use the path sent by the client for each operation.
Path normalization (resolve_target)
Internally, workbook targets are normalized with resolve_target in excel_mcp.path_resolution (single entry point for FR-1 / future COM path comparison). It uses os.path.realpath for stable absolute paths; relative resolution order (search_roots, then cwd) is documented in that module.
- stdio, allowlist off: tool paths must still be absolute; the server returns
os.path.normpathonly (legacy behavior for existing clients). - stdio, allowlist on and SSE / streamable HTTP: paths are finalized with
resolve_targetbefore jail and allowlist checks.
Integrators can reuse path_is_allowed / assert_path_allowed from excel_mcp.path_policy so file and future COM backends share the same policy.
Optional path allowlist (EXCEL_MCP_ALLOWED_PATHS)
For tighter control (aligned with FR-11), set EXCEL_MCP_ALLOWED_PATHS to one or more allowed directory roots, separated by os.pathsep (semicolon on Windows, colon on macOS/Linux—the same rule as the PATH environment variable). Whitespace around each entry is trimmed; ~ is expanded per entry.
When unset or blank, behavior matches the pre-fork defaults: stdio accepts any absolute path (subject to existing validation), and SSE/HTTP use only the EXCEL_FILES_PATH jail.
When set:
- stdio: each workbook path is resolved with
resolve_target, then must lie inside at least one listed root (directory containment, same idea as the remote jail). - SSE / streamable HTTP: the resolved path must be inside
EXCEL_FILES_PATHand inside at least one allowlist root (intersection).
If the variable is non-empty but no root path resolves (typos, missing drive letters, unreadable paths), the allowlist is treated as active with zero valid roots and paths are rejected until the environment is corrected (fail-closed).
Examples:
# Windows: two roots (note the semicolon)
$env:EXCEL_MCP_ALLOWED_PATHS = "E:\Workbooks;E:\SharedTemplates"
uvx excel-com-mcp stdio
# Linux / macOS: colon-separated
EXCEL_MCP_ALLOWED_PATHS=/var/excel-in:/var/excel-out uvx excel-com-mcp stdio
Workbook transport and COM policy (not MCP wire transport)
These environment variables control workbook routing (file-backed openpyxl path vs COM automation when wired in later stories). They do not select the MCP client↔server wire transport (stdio, SSE, or streamable HTTP); that is configured by how you launch the server (see above). See ADR 0001 for the vocabulary split.
| Variable | Meaning |
|---|---|
EXCEL_MCP_TRANSPORT |
Workbook mode: auto, file, or com (case-insensitive). Default auto when unset or empty. Invalid values raise at read time. Parsed by excel_mcp.routing.read_workbook_transport. |
EXCEL_MCP_COM_STRICT |
When 1 / true / yes (case-insensitive): strict COM policy. When 0 / false / no, or explicitly relaxed: non-strict. Unset or empty defaults to strict (True). Parsed by read_com_strict. |
EXCEL_MCP_COM_ALLOW_FILE_FALLBACK |
When 1 / true / yes: operators allow documented file fallback in scenarios where non-strict routing would apply (ADR 0005). Unset or empty: False. Parsed by read_com_allow_file_fallback. |
EXCEL_MCP_SAVE_AFTER_WRITE_DEFAULT |
Default for optional tool parameter save_after_write when omitted on mutating tools. 1 / true / yes → default true (extra save_workbook after file-backed writes). Unset or empty defaults to false (FR-8: no extra flush until requested). Parsed by read_save_after_write_default. |
Effective strictness for the router is effective_com_strict(): False if file fallback is allowed or EXCEL_MCP_COM_STRICT is explicitly falsy; otherwise True. Allowing file fallback forces non-strict effective behavior whenever that flag is on.
Optional MCP tool parameters (workbook routing)
Every workbook tool accepts optional workbook_transport (auto | file | com) and save_after_write (boolean). When omitted, transport defaults to EXCEL_MCP_TRANSPORT and the save flag defaults per EXCEL_MCP_SAVE_AFTER_WRITE_DEFAULT. Read-only tools ignore save_after_write (no extra save). These names refer to workbook execution routing (ADR 0001), not MCP wire transport.
Routing observability
Routed workbook operations (via execute_routed_workbook_operation in excel_mcp.routing.routed_dispatch) emit one JSON object per dispatch on logger excel-mcp.routing at INFO (no stdout). Fields follow ADR 0001 vocabulary:
- workbook_transport — requested mode:
auto,file, orcom. - workbook_backend — resolved backend after the selection matrix:
fileorcom. - routing_reason — stable reason string from
RoutingBackend(e.g.forced_file,read_class_file_backed,full_name_match). - duration_ms — wall time for resolve plus executed file I/O (when applicable).
- workbook_path — redacted path (basename only by default; set
EXCEL_MCP_LOG_FULL_PATHS=1for full path in break-glass scenarios). - operation_name — routed contract method name (e.g.
read_range_with_metadata). - mcp_tool_name — optional registered MCP tool name when supplied by the caller.
- v1_file_forced —
truewhen ADR 0004 forces the file backend for a tool (chart / pivot v1) regardless ofauto→COM for other writes.
ADR 0003 — file-backed reads vs Excel host state
Read-class tools (read_data_from_excel, get_workbook_metadata, validation reads, etc.) stay file-backed: they read the on-disk workbook through openpyxl, not live Excel grid memory. If you mutate via COM without saving on every write, disk can lag Excel. Agent pattern: call save_workbook before read_data_from_excel (or other reads) when you need file reads to reflect what Excel has in memory. See docs/architecture/adr/0003-read-path-com-parity.md.
FR-9 — Protected View, read-only, duplicate instances
COM operations return clear, fail-closed errors when Excel blocks writes (e.g. Protected View, read-only). If multiple open workbooks resolve to the same path across Excel instances, routing fails closed with an error asking the operator to close duplicates or use a single Excel instance.
NFR-2 — routing latency
p95 routing overhead is not continuously benchmarked in CI. See docs/performance/routing-nfr2-note.md for an honest scope note and an optional local micro-benchmark idea.
NFR-4 — elevation
The server does not request administrator elevation by default (COM automation targets the user’s normal Excel session; see also the blueprint §5 “do not start Excel as admin without explicit user opt-in”).
Planning / delivery status: workbook transport epics and stories are tracked in docs/plan/transport-routing/IMPLEMENTATION-ROADMAP.md. Phases 1–6 are done in epic/story frontmatter (including optional [com], ComThreadExecutor, and ComWorkbookService skeleton). Epic 7 is delivered in code: COM write-class parity per the inventory matrix, MCP save_workbook (ADR 0003), FR-9 actionable errors (Protected View, read-only, duplicates), and ADR 0004 v1 tool-forced file routing for create_chart / create_pivot_table (see logs: routing_reason v1_file_forced, field v1_file_forced: true when applicable).
Optional Windows COM ([com]): to install pywin32 for COM-backed workbook routing, use pip install excel-com-mcp[com] (or the equivalent for your installer). pywin32 is distributed under the PSF License Agreement (same terms as CPython).
COM execution threading (Windows)
COM apartment rules require Excel automation from a consistent thread. The server uses excel_mcp.com_executor.ComThreadExecutor: a single worker thread pulls jobs from a queue; submit(fn, *args, **kwargs) runs fn on that thread and blocks the caller until the result is ready (or an exception is propagated), so synchronous MCP tool handlers stay compatible without turning every tool async. On Windows, that worker thread calls pythoncom.CoInitialize() before processing jobs and CoUninitialize() on shutdown so COM APIs such as GetActiveObject("Excel.Application") behave like a normal main-thread script (without this, automation from a plain background thread often fails even when Excel is running). The executor does not start Excel by itself. For tests or clean process teardown, call shutdown(wait=True); abrupt exit may still cut off in-flight work—see the module docstring on com_executor for limitations (including no reentrant submit from inside a job on the worker).
Windows manual smoke (COM write path)
- Install the optional stack:
pip install "excel-com-mcp[com]"(or your package equivalent) sopywin32is available. - Start Microsoft Excel manually and open the target
.xlsxusing File → Open (a running instance with the workbook loaded is required; the server does not launch Excel). - Run the MCP server (e.g. stdio) on the same Windows machine with routing env vars as needed (defaults:
EXCEL_MCP_TRANSPORT=autowhen unset). - Call
write_data_to_excelwith an absolute path to that file,workbook_transport=comorauto, and a smalldatagrid; withauto, the workbook must be detected as open in Excel for COM to win on write tools. - Read-class tools (e.g.
read_data_from_excel,get_workbook_metadata) stay file-backed per ADR 0003 even whenworkbook_transport=com; after COM writes, callsave_workbook(or usesave_after_write=trueon mutating tools) before reads so on-disk content matches Excel. - Optional: set
save_after_write=trueon the write so the server persists via COMSavewhen the executed backend wascom, or via openpyxl when it wasfile. - Confirm routing in
excel-mcp.log: one JSON line per dispatch withworkbook_backendcomand a stablerouting_reason(e.g.full_name_match/forced_com) for writes routed to COM. - For release-style sign-off, follow
docs/plan/transport-routing/MANUAL-WINDOWS-RC-CHECKLIST.md(Protected View, read-only, duplicate instance, save-then-read, chart/pivotv1_file_forcedrows).
CI locally (contributors)
GitHub Actions runs the same gates as PR CI via .github/workflows/reusable-validate-and-test.yml: editable install with dev extras, pytest, hatch build, and twine check dist/*.
python -m pip install --upgrade pip
pip install -e ".[dev]"
pytest
hatch build
twine check dist/*
No Excel or Windows COM is required for this default path (Linux CI).
Available Tools
The server provides a comprehensive set of Excel manipulation tools. See TOOLS.md for complete documentation of all available tools.
Star History
License
MIT License - see LICENSE for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file excel_com_mcp-0.1.9.tar.gz.
File metadata
- Download URL: excel_com_mcp-0.1.9.tar.gz
- Upload date:
- Size: 52.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
52670a332877fc937d730db988f19c0b7410771a4769aa7c5278550c3fa51814
|
|
| MD5 |
95458e7bf1c079cdcf110d11cc20f58e
|
|
| BLAKE2b-256 |
9048cd988e6cfbf5c372fc4c7ebbb9fa6129ae1f6dfe73fa49c5483872ca9665
|
Provenance
The following attestation bundles were made for excel_com_mcp-0.1.9.tar.gz:
Publisher:
release-pypi-publish.yml on benvdbergh/excel-mcp-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
excel_com_mcp-0.1.9.tar.gz -
Subject digest:
52670a332877fc937d730db988f19c0b7410771a4769aa7c5278550c3fa51814 - Sigstore transparency entry: 1394032981
- Sigstore integration time:
-
Permalink:
benvdbergh/excel-mcp-server@84ec7d09fdfe2d6ec359b737f6af0919267e061e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/benvdbergh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi-publish.yml@84ec7d09fdfe2d6ec359b737f6af0919267e061e -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file excel_com_mcp-0.1.9-py3-none-any.whl.
File metadata
- Download URL: excel_com_mcp-0.1.9-py3-none-any.whl
- Upload date:
- Size: 67.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
83a6c3199f8a846381a659df503325449cddf02a2da1cbdc9db7f07de6c5d06d
|
|
| MD5 |
569a13022cdeecbb271e2e35cca9f06e
|
|
| BLAKE2b-256 |
2dea26c5684f3df3bee54f8b526aa1222dd6d337a4807e11963f36124fd18363
|
Provenance
The following attestation bundles were made for excel_com_mcp-0.1.9-py3-none-any.whl:
Publisher:
release-pypi-publish.yml on benvdbergh/excel-mcp-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
excel_com_mcp-0.1.9-py3-none-any.whl -
Subject digest:
83a6c3199f8a846381a659df503325449cddf02a2da1cbdc9db7f07de6c5d06d - Sigstore transparency entry: 1394032987
- Sigstore integration time:
-
Permalink:
benvdbergh/excel-mcp-server@84ec7d09fdfe2d6ec359b737f6af0919267e061e -
Branch / Tag:
refs/heads/main - Owner: https://github.com/benvdbergh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pypi-publish.yml@84ec7d09fdfe2d6ec359b737f6af0919267e061e -
Trigger Event:
workflow_dispatch
-
Statement type: