MCP Server¶
This guide explains how to run ExStruct as an MCP (Model Context Protocol) server so AI agents can call it safely as a tool.
What it provides¶
- Convert Excel into structured JSON (file output)
- Export worksheet images as PNG (COM-only, optional sheet/range target)
- Create a new workbook and apply initial ops in one call
- Edit Excel by applying patch operations (cell/sheet updates)
- Read large JSON outputs in chunks
- Read A1 ranges / specific cells / formulas directly from extracted JSON
- Pre-validate input files
Installation¶
Option 1: Using uvx (recommended)¶
No installation required! Run directly with uvx:
uvx --from 'exstruct[mcp]' exstruct-mcp --root C:\data
Benefits:
- No pip install needed
- Automatic dependency management
- Environment isolation
- Easy version pinning: uvx --from 'exstruct[mcp]==0.4.4' exstruct-mcp
Option 2: Traditional pip install¶
pip install exstruct[mcp]
Option 3: Development version from Git¶
uvx --from 'exstruct[mcp] @ git+https://github.com/harumiWeb/exstruct.git@main' exstruct-mcp --root .
Note: When using Git URLs, the [mcp] extra must be explicitly included in the dependency specification.
Start (stdio)¶
exstruct-mcp --root C:\\data --log-file C:\\logs\\exstruct-mcp.log --on-conflict rename
Key options¶
--root: Allowed root directory (required)--deny-glob: Deny glob patterns (repeatable)--log-level:DEBUG/INFO/WARNING/ERROR--log-file: Log file path (stderr is still used by default)--on-conflict: Output conflict policy (overwrite/skip/rename)--artifact-bridge-dir: Directory used bymirror_artifact=trueto copy output files--warmup: Preload heavy imports to reduce first-call latency
Tools¶
exstruct_extractexstruct_capture_sheet_imagesexstruct_makeexstruct_patchexstruct_list_opsexstruct_describe_opexstruct_read_json_chunkexstruct_read_rangeexstruct_read_cellsexstruct_read_formulasexstruct_validate_inputexstruct_get_runtime_info
exstruct_capture_sheet_images (COM only, Experimental)¶
- Purpose: export worksheet images as PNG through the existing PDF -> PNG pipeline.
- Input:
xlsx_path(required)out_dir(optional)dpi(default144, must be>= 1)sheet(optional; required whenrangeis provided)range(optional;A1:B2,Sheet1!A1:B2,'Sheet 1'!A1:B2)- Output:
out_dir(always returned, resolved path)image_pathswarnings- Notes:
- If
out_diris omitted, a unique<workbook_stem>_imagesdirectory is created under MCP--root. - COM/Excel desktop is required.
- This tool is currently shipped as
experimentalin MCP deployments. - MCP server runtime defaults
EXSTRUCT_RENDER_SUBPROCESS=1viasetdefault(subprocess PDF->PNG). If you prefer in-process rendering, setEXSTRUCT_RENDER_SUBPROCESS=0explicitly before starting the server. - Timeout tuning:
EXSTRUCT_MCP_CAPTURE_SHEET_IMAGES_TIMEOUT_SEC(default120)EXSTRUCT_RENDER_SUBPROCESS_STARTUP_TIMEOUT_SEC(default5)EXSTRUCT_RENDER_SUBPROCESS_JOIN_TIMEOUT_SEC(default120)EXSTRUCT_RENDER_SUBPROCESS_RESULT_TIMEOUT_SEC(default5)
- Stage-aware errors are returned from render subprocess mode:
stage=startup: worker bootstrap/import/startup failed.stage=join: timed out while worker remained alive.stage=result: worker exited but result payload was missing/invalid.stage=worker: worker returned an explicit rendering failure.
- Trade-offs:
EXSTRUCT_RENDER_SUBPROCESS=0: lower crash isolation and potentially higher long-running process memory pressure.EXSTRUCT_RENDER_SUBPROCESS=1: requiressys.executable+exstructmodule resolution in the worker process.
Example:
{
"tool": "exstruct_capture_sheet_images",
"xlsx_path": "C:\\data\\book.xlsx",
"sheet": "Sheet 1",
"range": "'Sheet 1'!A1:F20",
"dpi": 144
}
exstruct_extract defaults and mode guide¶
options.alpha_coldefaults totruein MCP (column keys becomeA,B, ...).- Set
options.alpha_col=falseif you need legacy 0-based numeric string keys. options.include_backend_metadatadefaults tofalseto keep shape/chart output compact.- Set
options.include_backend_metadata=truewhen you needprovenance,approximation_level, andconfidence. modeis an extraction detail level (not sheet scope):
| Mode | When to use | Main output characteristics |
|---|---|---|
light |
Fast, structure-first extraction | cells + table candidates + print areas |
libreoffice |
Best-effort rich extraction without Excel COM | light + merged cells + shapes + connectors + charts |
standard |
Default for Windows + Excel agent flows | balanced COM-backed detail and size |
verbose |
Need the richest COM metadata | adds links/maps and richer metadata |
Notes:
libreofficeis available for.xlsx/.xlsmonly.libreofficeis best-effort and not a strict subset of COM output.libreofficedoes not render PDFs/PNGs and does not compute auto page-break areas in v1.
Quick start for agents (recommended)¶
- Validate file readability with
exstruct_validate_input - Run
exstruct_extractwithmode="standard" - Read the result with
exstruct_read_json_chunkusingsheetandmax_bytes
Example sequence:
{ "tool": "exstruct_validate_input", "xlsx_path": "C:\\data\\book.xlsx" }
{ "tool": "exstruct_extract", "xlsx_path": "C:\\data\\book.xlsx", "mode": "standard", "format": "json" }
{ "tool": "exstruct_read_json_chunk", "out_path": "C:\\data\\book.json", "sheet": "Sheet1", "max_bytes": 50000 }
If path behavior is unclear, inspect runtime info first:
{ "tool": "exstruct_get_runtime_info" }
When a path is outside --root, the error message also recommends
exstruct_get_runtime_info with a relative path example.
Basic flow¶
- Call
exstruct_extractto generate the output JSON file - Use
exstruct_read_json_chunkto read only the parts you need
Direct read tools (A1-oriented)¶
Use these tools when you already know the target addresses and want faster, less verbose reads than chunk traversal.
exstruct_read_range- Read a rectangular A1 range (example:
A1:G10) - Optional:
include_formulas,include_empty,max_cells exstruct_read_cells- Read specific cells in one call (example:
["J98", "J124"]) - Optional:
include_formulas exstruct_read_formulas- Read formulas only (optionally restricted by A1 range)
- Optional:
include_values
Examples:
{
"tool": "exstruct_read_range",
"out_path": "C:\\data\\book.json",
"sheet": "Data",
"range": "A1:G10"
}
{
"tool": "exstruct_read_cells",
"out_path": "C:\\data\\book.json",
"sheet": "Data",
"addresses": ["J98", "J124"]
}
{
"tool": "exstruct_read_formulas",
"out_path": "C:\\data\\book.json",
"sheet": "Data",
"range": "J2:J201",
"include_values": true
}
Chunking guide¶
Key parameters¶
sheet: target sheet name. Strongly recommended when workbook has multiple sheets.max_bytes: chunk size budget in bytes. Start at50_000; increase (for example120_000) if chunks are too small.filter.rows:[start, end](1-based, inclusive).filter.cols:[start, end](1-based, inclusive). Works for both numeric keys ("0","1") and alpha keys ("A","B").cursor: pagination cursor (next_cursorfrom the previous response).
Retry guide by error/warning¶
| Message | Meaning | Next action |
|---|---|---|
Output is too large... |
Whole JSON cannot fit in one response | Retry with sheet, or narrow with filter.rows/filter.cols |
Sheet is required when multiple sheets exist... |
Workbook has multiple sheets and target is ambiguous | Pick one value from workbook_meta.sheet_names and set sheet |
Base payload exceeds max_bytes... |
Even metadata-only payload is larger than max_bytes |
Increase max_bytes |
max_bytes too small... |
Row payload is too large for the current size | Increase max_bytes, or narrow row/col filters |
Cursor example¶
- Call without
cursor - If response has
next_cursor, call again with that cursor - Repeat until
next_cursorisnull
Edit flow (make/patch)¶
Choose make vs patch¶
| Tool | Use when | Required path input |
|---|---|---|
exstruct_make |
Create a brand-new workbook and apply initial ops in one call | out_path |
exstruct_patch |
Edit an existing workbook (in-place style via out_name + on_conflict=overwrite is possible) |
xlsx_path |
New workbook flow (exstruct_make)¶
- Build patch operations (
ops) for initial sheets/cells - Call
exstruct_makewithout_path - Re-run
exstruct_extractto verify results if needed
exstruct_make highlights¶
- Creates a new workbook and applies
opsin one call out_pathis requiredopsis optional (empty list is allowed)- Supported output extensions:
.xlsx,.xlsm,.xls - Initial sheet behavior:
- default is
Sheet1 - when
sheetis specified and the same name is not created byadd_sheet, the initial sheet is created with thatsheetname - when
add_sheetcreates the same name, initial sheet remainsSheet1 - Reuses patch pipeline, so
patch_diff/errorshape is compatible withexstruct_patch - Supports the same extended flags as
exstruct_patch: dry_runreturn_inverse_opspreflight_formula_checkauto_formulabackendsheet(top-level default sheet for non-add_sheetops).xlsconstraints:- requires Windows Excel COM
- rejects
backend="openpyxl" - rejects
dry_run/return_inverse_ops/preflight_formula_check
Example:
{
"tool": "exstruct_make",
"out_path": "C:\\data\\new_book.xlsx",
"ops": [
{ "op": "add_sheet", "sheet": "Data" },
{ "op": "set_value", "sheet": "Data", "cell": "A1", "value": "hello" }
]
}
Internal implementation note¶
The patch implementation is layered to keep compatibility while enabling refactoring:
exstruct.mcp.patch_runner: compatibility facade (existing import path)exstruct.mcp.patch.service: patch/make orchestrationexstruct.mcp.patch.engine.*: backend execution boundaries (openpyxl/com)exstruct.mcp.patch.runtime: runtime utilities (path/backend selection)exstruct.mcp.patch.ops.*: backend-specific op application entrypoints
This keeps MCP tool I/O stable while allowing internal module separation.
Edit flow (patch)¶
- Inspect workbook structure with
exstruct_extract(andexstruct_read_json_chunkif needed) - Build patch operations (
ops) for target cells/sheets - Call
exstruct_patchto apply edits - Re-run
exstruct_extractto verify results if needed
exstruct_patch highlights¶
- Atomic apply: all operations succeed, or no changes are saved
opsaccepts an object list as the canonical form. For compatibility, JSON object strings inopsare also accepted and normalized.- Supports:
set_valueset_formulaadd_sheetset_range_valuesfill_formulaset_value_ifset_formula_ifdraw_grid_borderset_boldset_font_sizeset_font_colorset_fill_colorset_dimensionsauto_fit_columnsmerge_cellsunmerge_cellsset_alignmentset_styleapply_table_stylecreate_chart(COM only)restore_design_snapshot(internal inverse op)- Useful flags:
dry_run: compute diff only (no file write)return_inverse_ops: return undo operationspreflight_formula_check: detect formula issues before saveauto_formula: treat=...inset_valueas formulasheet: top-level default sheet used whenop.sheetis omitted (non-add_sheetonly)- default
out_name:{stem}_patched{ext}. If input stem already ends with_patched, ExStruct reuses the same name to avoid_patched_patchedchaining. mirror_artifact: copy output workbook to--artifact-bridge-diron success- Large ops guidance:
opsover200still runs, but returns a warning that recommends splitting into batches.- Backend selection:
backend="auto"(default): prefers COM when available; otherwise openpyxl. Also uses openpyxl whendry_run/return_inverse_ops/preflight_formula_checkis enabled.backend="com": forces COM. Requires Excel COM and rejectsdry_run/return_inverse_ops/preflight_formula_check.backend="openpyxl": forces openpyxl (.xlsis not supported).create_chartconstraints:- Supported only with COM backend.
chart_typesupports:line,column,bar,area,pie,doughnut,scatter,radar.- Alias input is accepted:
column_clustered,bar_clustered,xy_scatter,donut.
- Alias input is accepted:
data_rangeaccepts either one A1 range string or an array of ranges (multi-series).data_range/category_rangesupport sheet-qualified form (Sheet2!A1:B10,'Sales Data'!A1:B10).- Optional explicit labels:
chart_title,x_axis_title,y_axis_title. - Rejects
dry_run/return_inverse_ops/preflight_formula_check. - Can be combined with
apply_table_stylein one request when backend resolves to COM. - If COM is unavailable, mixed
create_chart+apply_table_stylerequests return a COM-required error. - Output includes
engine("com"or"openpyxl") to show which backend was actually used. - Output includes
mirrored_out_pathwhen mirroring is requested and succeeds. - Conflict handling follows server
--on-conflictunless overridden per tool call restore_design_snapshotremains openpyxl-only.- Sheet resolution order:
op.sheetis used when present- otherwise top-level
sheetis used for non-add_sheetops add_sheetstill requires explicitop.sheet(or aliasname)
set_style quick guide¶
- Purpose: apply multiple style fields in one op.
- Target: exactly one of
cellorrange. - Need at least one style field:
bold,font_size,color,fill_color,horizontal_align,vertical_align,wrap_text.
Example:
{
"tool": "exstruct_patch",
"xlsx_path": "C:\\data\\book.xlsx",
"ops": [
{
"op": "set_style",
"sheet": "Sheet1",
"range": "A1:D1",
"bold": true,
"color": "#FFFFFF",
"fill_color": "#1F3864",
"horizontal_align": "center",
"vertical_align": "center",
"wrap_text": true
}
]
}
apply_table_style quick guide¶
- Purpose: create a table and apply an Excel table style in one op.
- Required:
sheet,range,style. - Optional:
table_name. - Fails when range intersects an existing table, or table name duplicates.
- COM execution checklist (recommended on Windows):
- Microsoft Excel desktop app is installed and launchable in the current user session.
- Use
backend="com"for deterministic behavior, orbackend="auto"with COM availability. rangeincludes the header row and points to one contiguous A1 range.- Avoid protected sheets/workbooks and existing tables intersecting the target range.
- Common error codes:
table_style_invalid:styleis not a valid Excel table style name.list_object_add_failed: Excel COMListObjects.Add(...)failed for all compatible signatures.com_api_missing: required COM members such asListObjects.Addare unavailable.
Example:
{
"tool": "exstruct_patch",
"xlsx_path": "C:\\data\\book.xlsx",
"ops": [
{
"op": "apply_table_style",
"sheet": "Sheet1",
"range": "A1:D11",
"style": "TableStyleMedium9",
"table_name": "SalesTable"
}
]
}
apply_table_style minimal MCP sample (exstruct_make)¶
Use this for Windows + Excel COM smoke checks when you need a reproducible minimal request.
{
"tool": "exstruct_make",
"out_path": "C:\\data\\table_style_smoke.xlsx",
"backend": "com",
"ops": [
{
"op": "set_range_values",
"sheet": "Sheet1",
"range": "A1:C4",
"values": [
["Month", "Revenue", "Cost"],
["Jan", 120, 80],
["Feb", 150, 90],
["Mar", 140, 88]
]
},
{
"op": "apply_table_style",
"sheet": "Sheet1",
"range": "A1:C4",
"style": "TableStyleMedium2",
"table_name": "SalesTable"
}
]
}
auto_fit_columns quick guide¶
- Purpose: auto-fit column widths and optionally clamp with min/max bounds.
- Required:
sheet. - Optional:
columns,min_width,max_width. columnssupports Excel letters and numeric indexes (for example["A", 2]).- If
columnsis omitted, used columns are targeted.
Example:
{
"tool": "exstruct_patch",
"xlsx_path": "C:\\data\\book.xlsx",
"ops": [
{
"op": "auto_fit_columns",
"sheet": "Sheet1",
"columns": ["A", 2],
"min_width": 8,
"max_width": 40
}
]
}
Color fields (color / fill_color)¶
set_font_colorusescolor(font color only)set_fill_colorusesfill_color(background fill only)- Accepted formats for both fields:
RRGGBBAARRGGBB#RRGGBB#AARRGGBB- Values are normalized internally to uppercase with leading
#.
Examples:
{
"tool": "exstruct_patch",
"xlsx_path": "C:\\data\\book.xlsx",
"ops": [
{ "op": "set_font_color", "sheet": "Sheet1", "cell": "A1", "color": "1f4e79" },
{ "op": "set_fill_color", "sheet": "Sheet1", "range": "A1:C1", "fill_color": "CC336699" }
]
}
Alias and shorthand inputs¶
add_sheet:nameis accepted as an alias ofsheetset_dimensions:row->rowscol->columnsheight->row_heightwidth->column_widthcolumnsaccepts both letters ("A","AA") and positive indexes (1,2, ...)draw_grid_border:rangeshorthand is accepted and normalized tobase_cell+row_count+col_countset_alignment:horizontal->horizontal_alignvertical->vertical_alignset_fill_color:color->fill_color- Relative
out_pathforexstruct_makeis resolved from MCP--root.
Mirror artifact handoff¶
exstruct_patch/exstruct_makeinput:mirror_artifact(default:false)- Output:
mirrored_out_path(nullwhen not mirrored)- Behavior:
- Mirroring runs only on success.
- If
--artifact-bridge-diris not set, process still succeeds and warning is returned. - If copy fails, process still succeeds and warning is returned.
Claude Desktop artifact handoff recipe¶
- Start MCP server with
--artifact-bridge-dir. - Call
exstruct_patchorexstruct_makewithmirror_artifact=true. - Read
mirrored_out_pathfrom tool output and pass that path to Claude for follow-up tasks.
Example Claude Desktop MCP args:
{
"command": "uvx",
"args": [
"--from",
"exstruct[mcp]",
"exstruct-mcp",
"--root",
"C:\\data",
"--artifact-bridge-dir",
"C:\\data\\artifacts",
"--on-conflict",
"overwrite"
]
}
Example tool call:
{
"tool": "exstruct_patch",
"xlsx_path": "C:\\data\\book.xlsx",
"mirror_artifact": true,
"ops": [
{ "op": "set_value", "sheet": "Sheet1", "cell": "A1", "value": "updated" }
]
}
Op schema discovery tools¶
exstruct_list_ops- Returns available op names and short descriptions.
exstruct_describe_op- Input:
op - Output:
required,optional,constraints,example,aliases
Examples:
{ "tool": "exstruct_list_ops" }
{ "tool": "exstruct_describe_op", "op": "set_fill_color" }
Mistake catalog (error -> fix)¶
- Wrong (conflicting alias and canonical field):
{"op":"set_fill_color","sheet":"Sheet1","cell":"A1","color":"#D9E1F2","fill_color":"#FFFFFF"}- Correct:
-
{"op":"set_fill_color","sheet":"Sheet1","cell":"A1","fill_color":"#D9E1F2"} -
Wrong (conflicting alias and canonical field):
{"op":"set_alignment","sheet":"Sheet1","cell":"A1","horizontal":"center","horizontal_align":"left"}- Correct:
-
{"op":"set_alignment","sheet":"Sheet1","cell":"A1","horizontal_align":"center","vertical_align":"center"} -
Note:
color(set_fill_color) andhorizontal/vertical(set_alignment) are accepted aliases.- Canonical fields (
fill_color,horizontal_align,vertical_align) are recommended.
In-place overwrite recipe¶
To overwrite the original workbook path explicitly:
- set
out_nameto the same filename as the input workbook - set
on_conflicttooverwrite - keep
out_dirempty (or set it to the same directory)
Example:
{
"tool": "exstruct_patch",
"xlsx_path": "C:\\data\\book.xlsx",
"out_name": "book.xlsx",
"on_conflict": "overwrite",
"ops": [
{ "op": "set_value", "sheet": "Sheet1", "cell": "A1", "value": "updated" }
]
}
Runtime info tool¶
exstruct_get_runtime_inforeturns:rootcwdplatformpath_examples(relativeandabsolute)
Example response (shape):
{
"root": "C:\\data",
"cwd": "C:\\Users\\agent\\workspace",
"platform": "win32",
"path_examples": {
"relative": "outputs/book.xlsx",
"absolute": "C:\\data\\outputs\\book.xlsx"
}
}
AI agent configuration examples¶
Using uvx (recommended)¶
Claude Desktop / GitHub Copilot¶
{
"mcpServers": {
"exstruct": {
"command": "uvx",
"args": [
"--from",
"exstruct[mcp]",
"exstruct-mcp",
"--root",
"C:\\data",
"--log-file",
"C:\\logs\\exstruct-mcp.log",
"--on-conflict",
"rename"
]
}
}
}
Codex¶
[mcp_servers.exstruct]
command = "uvx"
args = [
"--from",
"exstruct[mcp]",
"exstruct-mcp",
"--root",
"C:\\data",
"--log-file",
"C:\\logs\\exstruct-mcp.log",
"--on-conflict",
"rename"
]
Using pip install¶
Codex¶
~/.codex/config.toml
[mcp_servers.exstruct]
command = "exstruct-mcp"
args = ["--root", "C:\\data", "--log-file", "C:\\logs\\exstruct-mcp.log", "--on-conflict", "rename"]
GitHub Copilot / Claude Desktop / Gemini CLI¶
Register an MCP server with a command + args in your MCP settings:
{
"mcpServers": {
"exstruct": {
"command": "exstruct-mcp",
"args": ["--root", "C:\\data"]
}
}
}
Operational notes¶
- Logs go to stderr (and optionally
--log-file) to avoid contaminating stdio responses. - On Windows with Excel, standard/verbose can use COM for richer extraction. On non-Windows, COM is unavailable and openpyxl-based fallbacks are used.
- For large outputs, use
read_json_chunkto avoid hitting client limits.