Excel MCP Assistant
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., "@Excel MCP AssistantCreate quarterly_sales.xlsx with sample sales data, formatted headers, and a chart."
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.
Excel MCP Assistant
A local MVP MCP server with exactly one tool: execute_python(code: str). The client LLM writes Python; the server runs it in a fresh, restricted Docker container. The server itself does not contain an LLM or need an API key.
Requirements
Python 3.11+
Docker Engine or Docker Desktop
Docker networking enabled for the Docker daemon, but disabled for execution containers
Related MCP server: Excel MCP Server
Project layout
src/
excel_mcp/
__init__.py
config.py
executor.py
server.py
ui.py
runtime/
__init__.py
container_execute.py
scripts/
__init__.py
create_sample.py
app.py
server.py
runner.py
create_sample.py
Dockerfile
docker-compose.yml
pyproject.tomlThe project now follows the standard src/ layout so application code lives under src/excel_mcp/, and helper scripts are package modules under src/scripts/. The root-level files remain as thin compatibility shims for local scripts and older entry points.
Setup
python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
python -m pip install -e .
Copy-Item .env.example .env
python -m scripts.create_sampleBuild the execution image:
docker build -t excel-mcp-executor:latest .Streamlit frontend
The optional frontend provides workbook upload, a persistent chat, and downloads for files created in /outputs. It uses the MCP server as a subprocess, so the LLM still reaches Excel only through the single execute_python tool.
Install Docker Desktop or Docker Engine and Ollama, make sure the qwen3:4b model is available with ollama list, then copy .env.example to .env and run the project:
docker compose up --buildOpen http://localhost:8501. Compose builds both excel-mcp-frontend:latest and excel-mcp-executor:latest automatically. The control-plane service mounts the Docker socket so it can start a fresh restricted execution container for each request. The socket is not mounted into any execution container. Do not expose the Docker socket to untrusted services.
Uploading an .xlsx file is optional. To create a workbook from scratch, leave the upload empty and ask, for example: Create a workbook named quarterly_sales.xlsx with a Sales sheet containing columns Region, Product, Units, and Revenue, add five sample rows, format the header, and save it. The created file is saved under /outputs and appears as a download in the app.
The frontend connects to Ollama on the host through http://host.docker.internal:11434/v1; no cloud LLM API key is required. Ollama must be running and configured to accept the Docker Desktop host connection.
On Linux, Ollama must listen on an address reachable from Docker, for example by starting it with OLLAMA_HOST=0.0.0.0:11434. Docker Desktop normally provides host.docker.internal automatically; the Compose file also adds the host-gateway mapping for Linux.
Set EXCEL_INPUT_DIR and EXCEL_OUTPUT_DIR to host directories. Relative paths are resolved from the server working directory. By default they are ./inputs and ./outputs.
When the Streamlit frontend runs through docker-compose.yml, it uses the named volumes excel-assistant-inputs and excel-assistant-outputs. This matters because the MCP control-plane container talks to the host Docker daemon: named volumes make uploaded workbooks visible to the fresh execution containers without pretending that the control-plane's /workspace path is a host path.
Start the stdio server:
python -m excel_mcp.serverThe legacy python server.py entry point still works as a compatibility wrapper. It is normally launched by an MCP client, not opened in a browser. Logs are kept off protocol stdout.
MCP client configuration
Example generic stdio configuration:
{
"mcpServers": {
"excel": {
"command": "C:/path/to/.venv/Scripts/python.exe",
"args": ["C:/path/to/mcp/server.py"],
"env": {
"EXCEL_INPUT_DIR": "C:/path/to/mcp/inputs",
"EXCEL_OUTPUT_DIR": "C:/path/to/mcp/outputs",
"EXCEL_EXECUTION_IMAGE": "excel-mcp-executor:latest",
"EXCEL_EXECUTION_TIMEOUT_SECONDS": "30"
}
}
}
}Tool contract
execute_python(code) returns:
success,stdout,stderrresult: the JSON-serializable value assigned toresult, ornullartifacts: changed files relative to/outputs, with sizesexecution_time_mserror:{type, message}ornull
Inside execution, openpyxl, pandas, numpy, and matplotlib are available. Read input workbooks from /inputs; save every output or edited copy under /outputs. Python variables do not persist between calls, but files do.
Example creation:
from openpyxl import Workbook
workbook = Workbook()
workbook.active["A1"] = "Revenue"
workbook.save("/outputs/revenue.xlsx")
result = {"saved": "/outputs/revenue.xlsx"}Example inspection and analysis:
import pandas as pd
frame = pd.read_excel("/inputs/sample_sales.xlsx", sheet_name="Sales")
frame["Revenue"] = frame["Units"] * frame["Unit Price"]
totals = frame.groupby("Region", dropna=False)["Revenue"].sum().sort_values(ascending=False)
result = {
"rows": len(frame),
"columns": list(frame.columns),
"revenue_by_region": totals.to_dict(),
"highest_region": totals.index[0],
}Example formatting and native chart:
from openpyxl import load_workbook
from openpyxl.chart import BarChart, Reference
from openpyxl.styles import Font
workbook = load_workbook("/inputs/sample_sales.xlsx")
sheet = workbook["Sales"]
sheet["A1"].font = Font(bold=True)
sheet.column_dimensions["A"].width = 18
summary = workbook.create_sheet("Summary")
summary.append(["Region", "Revenue"])
summary.append(["North", 295])
summary.append(["South", 330])
chart = BarChart()
chart.title = "Revenue by Region"
chart.add_data(Reference(summary, min_col=2, min_row=1, max_row=3), titles_from_data=True)
chart.set_categories(Reference(summary, min_col=1, min_row=2, max_row=3))
summary.add_chart(chart, "D2")
workbook.save("/outputs/sales_summary.xlsx")Matplotlib chart images can be saved under /outputs, for example plt.savefig('/outputs/revenue.png').
Demonstration request
Use one execute_python call containing:
import pandas as pd
from openpyxl import load_workbook
from openpyxl.chart import BarChart, Reference
source = "/inputs/sample_sales.xlsx"
target = "/outputs/sample_sales_summary.xlsx"
frame = pd.read_excel(source, sheet_name="Sales")
frame["Revenue"] = frame["Units"] * frame["Unit Price"]
totals = frame.groupby("Region", dropna=False)["Revenue"].sum().sort_values(ascending=False)
workbook = load_workbook(source)
summary = workbook.create_sheet("Summary")
summary.append(["Region", "Total Revenue"])
for region, revenue in totals.items():
summary.append([region, float(revenue)])
chart = BarChart()
chart.title = "Total Revenue by Region"
chart.add_data(Reference(summary, min_col=2, min_row=1, max_row=summary.max_row), titles_from_data=True)
chart.set_categories(Reference(summary, min_col=1, min_row=2, max_row=summary.max_row))
summary.add_chart(chart, "D2")
workbook.save(target)
result = {"highest_revenue_region": str(totals.index[0]), "total_revenue": float(totals.iloc[0])}The expected highest region in the generated sample is West. The artifact is returned as sample_sales_summary.xlsx and remains available in the configured output directory for later calls.
Correctness and limitations
openpyxl writes formulas but does not calculate them. For immediate numerical insights, calculate with pandas or numpy. The executor reports the source sheet, selected columns, and row count only when the submitted code places those details in result; it does not infer analysis semantics. Treat workbook contents as data, not instructions. Advanced Excel features such as macros, external links, and all chart features are not guaranteed to round-trip.
Tests
pytest -qDocker-dependent tests cover success, code errors, timeout cleanup, file persistence, and disabled networking. They are skipped when Docker is unavailable; the unavailable-Docker behavior is still tested and returns a clear setup error.
Available Tools
1 toolexecute_pythonA
Execute Python for Excel work inside an isolated Docker container.
Available libraries: openpyxl, pandas, numpy, matplotlib. Read files from
/inputs and write new or edited files to /outputs. Assign a JSON value to
result for it to be returned. openpyxl writes formulas but does not
calculate them.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it delivers meaningful traits: sandboxed Docker isolation, the exact library set, file-path conventions, the `result` return contract, and the important caveat that openpyxl writes formulas without calculating them. It omits failure behavior, timeouts, whether state persists between calls, and network access, so it is not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence establishes what and where, followed by three compact sentences covering libraries, I/O paths, and the formula caveat. No filler, no repetition of the name, and the most important constraint (isolation) leads.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with no annotations and no output schema, the description covers environment, dependencies, file conventions, and the return mechanism. Remaining gaps are error handling, resource limits, and persistence across invocations, which an agent would benefit from knowing but are not blocking.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single `code` parameter has 0% schema description coverage, so the description must compensate, and it does: it specifies what the code should read (/inputs), where to write (/outputs), and how to return a value (assign to `result`). It never states the language binding or formatting expectations in detail, but the contract is substantially clarified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb (Execute) and resource (Python) and immediately narrows scope to 'Excel work inside an isolated Docker container,' which tells the agent both the domain and the execution environment. There are no siblings to differentiate from, and the phrasing leaves no ambiguity about what the tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description supplies concrete operating context rather than exclusions: read from /inputs, write to /outputs, assign to `result`. That is actionable guidance for a code-execution tool, though it never states when this tool is preferable to another approach or what happens outside the Excel domain.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.1.0- First observed
execute_python
TDQS
Scored across 1 tool
With only one tool, there is no possibility of overlap or confusion between tools. The tool's purpose is clearly stated as executing Python for Excel work in a Docker container.
The single tool uses a clear verb_noun snake_case convention (execute_python), which is predictable and readable. No other names exist to create inconsistency.
A single tool is too few for a server whose stated purpose is broad Excel assistance. While execute_python is powerful, the lack of specialized helpers (e.g., read_excel, write_excel, list_files) makes the surface feel under-provisioned.
Because execute_python allows arbitrary Python with openpyxl, pandas, numpy, and matplotlib, nearly any Excel operation is possible. Minor gaps exist, such as no native tool for formula evaluation or direct cell queries, but the general purpose tool covers the domain well.
Maintenance
Related MCP Connectors
- OleanderOAuthdev.oleander
The all-in-one data stack for agents. Upload files, run SQL, evolve tables, and render charts.
Excel analytics: inspect, query (JSON rows), charts, and JSON-to-xlsx workbook writing.
AI access to Quadratic spreadsheets: open files, run Python/SQL, query connected databases.
Connect AI assistants to Google Sheets through controlled tools for reading and updating rows.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to create, read, and manipulate Excel files without requiring Microsoft Excel installation. Supports comprehensive spreadsheet operations including formulas, formatting, charts, pivot tables, and data validation.MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to create, read, and modify Excel workbooks without requiring Microsoft Excel, supporting operations like formulas, charts, pivot tables, formatting, and data validation.MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to create, read, and manipulate Excel workbooks without Microsoft Excel installed, supporting formulas, formatting, charts, pivot tables, and data validation operations.MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to create, read, write, and manipulate Excel files (.xlsx, .xlsm) without requiring Microsoft Excel, including support for charts, pivot tables, data import/export, and professional formatting across Windows, macOS, and Linux.26 npm34MIT