Skip to content

Agent Tools

Every agent, the in-process native agent, Zed’s default agent, and any external ACP agent (Claude Code, Codex, Gemini-CLI), reaches the workbook through one tool surface: the in-process expanse-workbook MCP server. These are its tools. Mutating tools gate through the standard allow/reject permission prompt before they run.

Read-only, never mutates the workbook.

Read the contents of a cell region. Address it with region (stable anchors, from a prior read) or displayRegion (0-based row/col coordinates), reads never mint, so an unseen rectangle is fine. Default mode summary returns a 5-row sample plus per-column stats (~10× smaller than full). Set includeContext: true for user-mention reads to include headers, border padding, and upstream / downstream dependencies. Set format: xml for a compact, token-cheap XML rendering instead of the default structured JSON.

ParameterTypeRequiredDescription
displayRegionDisplayRegionno0-based display-coordinate target rectangle. The A1-native fallback for callers that don’t hold anchors yet, e.g. a code-mode script reading by "A1:C3". Reads never mint, so an empty rectangle simply comes back as empty cells.
formatReadFormatnoEncoding of the response body. json (default) returns the structured [RegionReadResponse]; xml returns the compact, LLM-friendly XML rendering produced by [RegionReadResponse::to_xml], fewer tokens and easier for a model to skim than nested JSON arrays. The anchor AST is dropped in xml mode (it’s tooling metadata, not something a model reads), so tools that rewrite references should stay on json.
includeContextbooleannoWhen true the response carries a [RegionContext] envelope, sheet name, header row, border padding, upstream deps, downstream dependents. Useful for user-initiated mentions where the user’s implicit context (the column labels above their selection, the formulas that feed it) matters more than the literal rectangle. Defaults to false for autonomous agent reads.
modeReadModenoResponse detail. Summary returns per-column stats + the first SUMMARY_SAMPLE_ROWS rows; Full returns every cell. Summary is ~10–100× smaller, the agent should default here unless it genuinely needs every cell. Default = Summary.
regionRegionnoAnchor-based target rectangle, stable identity across structural edits. When omitted, falls back to displayRegion. Exactly one of region / displayRegion must be set.

Writes to the workbook, gated behind a permission prompt.

Set a single cell’s value (number, string, or boolean). For formulas use region_write_formula instead.

ParameterTypeRequiredDescription
anchorAnchorPairnoAnchor pair identifying the target cell. Stable across structural ops, unlike A1 which shifts. When omitted, the handler falls back to displayPos and mints a fresh anchor, covers the “agent writes to an empty sheet” case where no anchor has been minted yet (UI parity with SetCelldb.cell_addr).
displayPosDisplayPosno0-based display fallback for first-write, used when anchor is absent or doesn’t resolve (e.g. empty-sheet bootstrap). Mints a new anchor; subsequent reads return the freshly-minted anchor so the agent can address the same cell stably afterwards.
sheetIdintegeryes
valueobjectyesPlain value, number, bool, or string. Numbers are sent as JSON numbers (lossless via f64); bools as JSON bools; strings as strings. Use write_formula for formulas.

Writes to the workbook, gated behind a permission prompt.

Set a cell’s formula. Excel-style with leading = (e.g. =SUM(A1:A5)) or a Python expression without =. Reference existing cells (e.g. =B1*1.1) rather than hard-coding a number that already lives in the sheet, the reference stays correct when that input changes; a copied literal silently goes stale. Optionally include ast, an anchor-based formula tree whose refs stay stable through structural edits.

ParameterTypeRequiredDescription
anchorAnchorPairnoAnchor pair identifying the host cell. See [WriteCellParams::anchor] for the mint-on-fallback contract.
astAnchorNodenoReferences stay stable through the agent loop even if rows are inserted/deleted between read_region and write_formula. Takes precedence over formula when present; ignored for Python / SQL.
displayPosDisplayPosno0-based display fallback for first-write. See WriteCellParams.displayPos.
formulastringyesFormula source, Excel-style with leading = ("=SUM(A1:A5)") or Python expression without = ("A1 + math.sqrt(A2)"). The dispatcher uses the prefix to route to IronCalc vs Monty. When ast is also provided the AST is authoritative.
sheetIdintegeryes

Writes to the workbook, gated behind a permission prompt.

Apply formatting (bold / italic / underline / color / fill / align) to every cell in a region. Hex colors without leading # (e.g. ff0000), or null to clear. Align is left / center / right.

ParameterTypeRequiredDescription
displayRegionDisplayRegionno0-based display fallback for first-write. Mints anchors for every covered cell, matching the UI’s SetCell-on-blank-cell behaviour.
regionRegionnoAnchor-based target rectangle. When omitted, falls back to displayRegion and mints corner anchors on demand, covers the empty-sheet bootstrap case (no anchors exist yet).
styleCellStyleyes

Read-only, never mutates the workbook.

Re-evaluate formulas. Pass a sheetId to scope to one sheet, or omit to evaluate the whole workbook. Returns the count of cells re-evaluated.

ParameterTypeRequiredDescription
sheetIdinteger | nullnoNone evaluates the whole workbook. Some(id) scopes to a sheet.

Read-only, never mutates the workbook.

List sheets in the active workbook with cell counts. Call first when you don’t have a sheet reference yet.

No parameters.

Read-only, never mutates the workbook.

Speculatively evaluate an Excel formula at anchor without writing a cell. The response carries the resolved value (or an Excel error like #REF!); the formula itself never touches storage.

ParameterTypeRequiredDescription
anchorAnchorPairyesHost cell context, relative refs in the formula resolve as if it were stored at this position. =A1 means different things from B5 vs C7. Anchor-based so the position survives structural edits between the agent picking it and the eval running.
astAnchorNodenoOptional anchor-based AST. Takes precedence over formula when present, mirroring [WriteFormulaParams::ast].
formulastringyesFormula source. Same shape as [WriteFormulaParams::formula], Excel-style with leading = ("=SUM(A1:A5)").
sheetIdintegeryes

Writes to the workbook, gated behind a permission prompt.

Drag-fill the formula or value pattern from a source area into a target rectangle. Target must abut source on exactly one axis. Returns the count of cells written.

ParameterTypeRequiredDescription
displaySourceDisplayRegionnoDisplay-coord fallback for source, mints corner anchors on demand. See SetStyleParams.displayRegion.
displayTargetDisplayRegionnoDisplay-coord fallback for target, mints corner anchors on demand.
sourceRegionnoThe source area whose pattern is being replicated. Typically one row or one column the agent (or a human) authored as a template. Optional so the agent can pass display coordinates when anchors haven’t been minted yet (see displaySource).
targetRegionnoThe target rectangle to fill. Must be on the same sheet as source and adjacent (extending downward, upward, rightward, or leftward, direction is inferred from the geometry). The source area itself is left untouched.

Writes to the workbook, gated behind a permission prompt.

Rename a cell anchor across every formula that references it. Anchor-AST tree-walk over the workbook’s support graph: O(deg) cell visits.

ParameterTypeRequiredDescription
newAnchorPairyesThe anchor to point at instead. Need not exist on the axis yet, formulas referencing an unresolvable anchor will surface as #REF! at eval time, matching Excel’s broken-ref semantics.
oldAnchorPairyesThe anchor to rename. Every Ref and Range corner pointing at this anchor in any formula on this sheet (or any cross-sheet formula referencing it) is rewritten to new.
sheetIdintegeryes

Writes to the workbook, gated behind a permission prompt.

Run a Python script that orchestrates multiple ops sequentially against a scratch workbook. Use for multi-cell transactional edits or row loops. Helpers: list_sheets(); read_region(sheet, range), compact XML, for looking; read_values(sheet, range), a typed value grid, for computing on; sheet_xml(sheet), the whole sheet as one XML blob; write_cell(sheet, cell, value); write_formula(sheet, cell, formula); set_style(sheet, ref, style); auto_fill(sheet, source, target); rewrite_ref(sheet, old, new). Every cell / range argument is an A1 string, “B7” or “A1:C3”. commit: false (default) drops the pending log after running; commit: true replays atomically on success. The Python namespace is a persistent scratchpad, variables and function defs from one call stay in scope for the next, so you need not re-declare your working data each turn. Pass reset: true to wipe that namespace for a clean start.

ParameterTypeRequiredDescription
commitbooleannofalse (preview): the pending log is dropped after the script runs; the live workbook is untouched. The agent reads the returned log + value and re-issues with commit: true if it likes the outcome. true: on Done with every op succeeding, replay the pending writes through the live workbook atomically. On any per-op failure, pending is dropped and nothing is committed.
pythonstringyesPython source. Imports are denied; the script calls injected helpers, list_sheets(), read_region(...), read_values(...), sheet_xml(...), write_cell(...), write_formula(...), set_style(...), auto_fill(...), rewrite_ref(...). Every helper addresses cells / ranges by A1 string ("B7", "A1:C3"). read_region / sheet_xml return compact XML for the model to read; read_values returns a typed value grid for the script to compute on. Reads consult the live workbook; writes append to a pending log that’s replayed against the live DB on commit (or dropped on rollback). Read-after-write inside one script doesn’t see pending writes in v1, that’s tracked separately along with in-script dry_run / eval_sheet, both of which need an IronCalc-Model-as-scratch layer to stay coherent with pending state and so error out for now.
resetbooleannoWhen true, the persistent code-mode scratchpad is wiped before this script runs, variables and function definitions left by earlier code_mode_run calls are dropped, giving a clean namespace. The scratchpad otherwise carries over automatically between calls (so the agent need not re-declare its working data), so set this only when a fresh start is wanted. Only the Python namespace persists between calls, never the pending-write log, whose scope is unchanged by commit.