# GRID Agent Tools (npm · @grid-is/agent-tools)

Load, read, edit, and recalculate .xlsx workbooks headlessly — no Excel required.

- Trust score: 65/100 (medium)
- Change this week: +6
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-11-05

## Components

- npm · `@grid-is/agent-tools`: 65/100 (this document), [markdown](https://verifymcp.io/servers/is-grid-agent-tools/grid-is-agent-tools.md), [page](https://verifymcp.io/servers/is-grid-agent-tools/grid-is-agent-tools)

## Channel facts

- Registry: `npm`
- Package: `@grid-is/agent-tools`
- Version: `0.5.0`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-11-05.

- **Supply Chain Security**: 98/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - No install/post-install scripts declared.
  - 33 of 103 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 6/100
  - Repository check failed: no source repository is declared.
  - Provenance check failed: no build-provenance attestation is published.
  - Licence could not be checked: the licence is shipped as a file inside the package, not declared as a standard (SPDX) licence identifier, so we cannot tell whether it is OSI-approved.
  - Actively maintained (last published 12 days ago).
  - Security-disclosure policy not yet verified: we couldn't inspect the source repository.
- **Schema Quality & AI Usability**: 64/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 5838 tokens (~208/item across 28 items; 28 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 43/100
  - Stability observed for 13 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
- **Tool Safety**: 75/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 0 of 1 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "executeOfficeJs" implies "execute" and declares no destructiveHint at all, which the MCP spec reads as destructive by default.
  - An AI judge read all 28 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### How do I install the GRID Agent Tools MCP server?

GRID Agent Tools runs locally as an npm package, launched with npx -y @grid-is/agent-tools. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add is-grid-agent-tools -- npx -y @grid-is/agent-tools
```

### Cursor

```json
{
  "mcpServers": {
    "is-grid-agent-tools": {
      "command": "npx",
      "args": [
        "-y",
        "@grid-is/agent-tools"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "is-grid-agent-tools": {
      "command": "npx",
      "args": [
        "-y",
        "@grid-is/agent-tools"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add is-grid-agent-tools -- npx -y @grid-is/agent-tools
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "is-grid-agent-tools": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "@grid-is/agent-tools"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add is-grid-agent-tools --command npx --arg -y --arg @grid-is/agent-tools
```

### Hermes

```yaml
mcp_servers:
  is-grid-agent-tools:
    command: "npx"
    args: ["-y", "@grid-is/agent-tools"]
```

### Netclaw

```json
{
  "McpServers": {
    "is-grid-agent-tools": {
      "Transport": "stdio",
      "Command": "npx",
      "Arguments": [
        "-y",
        "@grid-is/agent-tools"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add is-grid-agent-tools -t stdio -c npx -a -y @grid-is/agent-tools
```

### Other

```json
{
  "mcpServers": {
    "is-grid-agent-tools": {
      "command": "npx",
      "args": [
        "-y",
        "@grid-is/agent-tools"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-11-05 (score 65, +1)

No change was recorded against any check on this day. Stability & Change Management went from 40 to 43. That category is still filling its 30-day observation window: 12 days of observed history at the previous scan, 13 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-11-03 (score 64, +1)

No change was recorded against any check on this day. Stability & Change Management went from 33 to 37. That category is still filling its 30-day observation window: 10 days of observed history at the previous scan, 11 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-11-02 (score 63, +4)

- [functional improvement] Stability: unverified → 0.33

### 2026-10-24 (score 59, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-10-23 (score 44)

First indexed and scored.

## MCP tools (28)

### `loadWorkbook` (~52 tokens)

Load an .xlsx file into memory and make it the active workbook. A session starts with this or createWorkbook. Returns the sheet names.

Input parameters:

- `path` (string, required): Absolute or relative path to the .xlsx file.

### `createWorkbook` (~54 tokens)

Create a blank single-sheet workbook in memory and make it the active workbook. Nothing is written to disk until saveWorkbook.

Input parameters:

- `path` (string, required): Path for the new .xlsx file. saveWorkbook writes it here by default.

### `saveWorkbook` (~69 tokens)

Save the active workbook to an .xlsx file. Provide a new path, or set overwrite: true to write over an existing file (including the source).

Input parameters:

- `overwrite` (boolean): Overwrite an existing file. Default false.
- `path` (string): Output path. Defaults to the source path.

### `listWorkbooks` (~19 tokens)

List all loaded workbooks and their sheet names.

### `selectWorkbook` (~75 tokens)

Make a previously loaded workbook the active one for all other spreadsheet tools. Switching keeps in-memory state, so unsaved edits survive. Use listWorkbooks to see what is loaded; use loadWorkbook to (re)load from disk.

Input parameters:

- `path` (string, required): Path of a previously loaded workbook, as shown by listWorkbooks.

### `describeStructure` (~174 tokens)

Analyzes the spreadsheet and returns a structured description of all data regions, headers, and labels.
This helps you understand:
\- Where data tables are located (islands/regions)
\- Which rows are headers vs data
\- Column and row labels for each data region
\- Sheet names and their contents
\- Whether iterative calculation is on (needed for intentional circular references)

Labels are limited to 50 per sheet. Use totalLabels to check if more exist, and labelOffset to paginate.

Use this information to write accurate formulas that reference the correct cells and ranges.

Input parameters:

- `labelOffset` (number): Optional: skip N labels before returning up to 50. Use for pagination when totalLabels > 50.
- `sheets` (array): Optional: limit analysis to specific sheet names. If omitted, all sheets are analyzed.

### `readCalculatedValues` (~366 tokens)

Read cell values, formula results, and lookups from spreadsheets, and optionally apply temporary values for what-if calculations.
The 'read' array accepts cell references, ranges, and formulas. Use formulas like XLOOKUP, QUERY, AVERAGE, etc. directly in 'read' to find and compute values in a single call.

Examples:
\- Read cells: { "read": ["A1", "B1:B10", "Sheet2!C5"] }
\- Lookup: { "read": ["=XLOOKUP(\"Revenue\", A1:A10, B1:B10)"] }
\- Filtered average: { "read": ["=QUERY(Sheet1!A1:D100, \"SELECT AVG(D) WHERE A = 'Category1'\")"] }
\- What-if: { "read": ["C8"], "apply": [{ "cell": "B1", "value": 100 }] }

Large ranges are automatically truncated. When a range entry is truncated the response includes `nextOffset` — call again with `cursors: { "<same expression>": <nextOffset> }` to read the next page.

Input parameters:

- `apply` (array): Temporary values to apply before reading (not persisted)
- `cursors` (object): Optional pagination cursors keyed by entries in `read`. Pass `nextOffset` from a previous truncated response to continue paging through that range. Formula entries (those starting with `=`) ignore cu…
- `read` (array, required): Cell references, ranges, or formulas to read. Examples: "A1", "B1:B10", "Sheet1!C5", "=XLOOKUP(\"Revenue\", A1:A10, B1:B10)", "=AVERAGE(C1:C10)"

### `editCells` (~413 tokens)

Permanently write values or formulas to cells. Merge or unmerge cells.

IMPORTANT: After editing, you MUST call readCalculatedValues to see the resulting changes.
The tool returns a delta showing changes, but you should verify formulas propagated correctly.

Writing text over a cell that held a number or date is reported in `warnings` (level "high" or "low"). A "high" warning usually means a real value was turned into a text string that only looks the same — write the value itself, not its displayed text.

Examples:
\- Set value: { "apply": [{ "target": "A1", "value": 100 }], "note": "Set initial value" }
\- Set formula: { "apply": [{ "target": "B1", "value": "=A1*2" }], "note": "Add formula" }
\- With style: { "apply": [{ "target": "A1", "value": 100, "styleIndex": 0 }], "styles": [{ "bold": true }], "note": "Bold value" }
\- Merge cells: { "apply": [], "merge": ["A1:B2"], "note": "Merge header" }
\- Unmerge: { "apply": [], "unmerge": ["A1:B2"], "note": "Unmerge cells" }

Formulas must start with "=". Values are auto-detected as number, boolean, or string.

Input parameters:

- `apply` (array, required): Array of cell edits to apply
- `merge` (array): Array of ranges to merge (e.g., ["A1:B2", "D4:E6"]). Each range must span at least 2 cells.
- `note` (string): Description of this edit for version history
- `styles` (array): Array of style objects referenced by styleIndex in apply items
- `unmerge` (array): Array of ranges to unmerge. Can specify exact merged range or any cell within a merge.

### `fillCells` (~265 tokens)

Extend a selection by filling cells with auto-detected patterns (numbers, dates, formulas).
Similar to Excel's fill handle - detects sequences and continues them.
Fill direction is inferred from selection and extend_to: the dimension that changes determines the fill axis.

IMPORTANT: After filling, you MUST call editCellStyles to apply formatting to the filled cells.

Examples:
\- Fill down: { "sheet": "Sheet1", "selection": "A1:A3", "extend_to": "A1:A10", "note": "Extend series" }
\- Fill right: { "sheet": "Sheet1", "selection": "A1:C1", "extend_to": "A1:F1", "note": "Extend headers" }
\- Fill up: { "sheet": "Sheet1", "selection": "A8:B10", "extend_to": "A1:B10", "note": "Extend upward" }

Input parameters:

- `extend_to` (string, required): Target range to fill to (e.g., "A1:A10")
- `note` (string): Description of this operation for version history
- `selection` (string, required): Source range containing the pattern (e.g., "A1:A3")
- `sheet` (string, required): Sheet name to operate on

### `editCellStyles` (~74 tokens)

Apply formatting styles to cells without changing values.

IMPORTANT: After using fillCells, you MUST call this to apply formatting to the filled range.

Input parameters:

- `apply` (array, required): Array of style applications
- `note` (string): Description of this operation for version history
- `sheet` (string, required): Sheet name to operate on

### `manageSheets` (~91 tokens)

Add, remove, rename, or change visibility of sheets.
Operations are executed in order: add → rename → setVisibility → remove.

Input parameters:

- `add` (object): Add a new sheet
- `note` (string): Description of this operation for version history
- `remove` (object): Remove a sheet
- `rename` (object): Rename a sheet
- `setVisibility` (object): Set sheet visibility

### `manageRowsAndColumns` (~91 tokens)

Insert, delete, or auto-size rows and columns.
Operations are executed in order: column insert → column delete → row insert → row delete → column autosize → row autosize.

Input parameters:

- `columns` (object): Column operations
- `note` (string): Description of this operation for version history
- `rows` (object): Row operations
- `sheet` (string, required): Sheet name to operate on

### `runFormula` (~450 tokens)

Run one or more formulas without writing to any cell. Returns the calculated results.
Useful for testing formulas or computing values without modifying the workbook.

Examples:
\- Single: { "formula": "=SUM(A1:A10)" }
\- Batch: { "formulas": ["=SUM(A1:A10)", "=AVERAGE(B1:B10)", "=COUNT(C1:C10)"] }
\- With temp values: { "formula": "=A1*B1", "apply": [{ "cell": "A1", "value": 5 }] }
\- Against a specific sheet: { "formula": "=SUM(A:A)", "sheet": "Sheet2" }

Use "formulas" array to test multiple formulas in one call (more efficient than multiple calls).

Bare cell references (e.g. A1, SUM(A:A)) resolve against the primary workbook's first sheet
by default. Use the "sheet" parameter when you need them to resolve against a different sheet.
The response includes a "_note" field identifying the sheet bare references resolved
against, so you can verify they resolved where you intended.

Sheets in external (linked) workbooks can be read with workbook-qualified references inside
the formula itself, e.g. ='[external.xlsx]Sheet1'!A1. If an external sheet shares its name
with a sheet in the primary workbook, the primary workbook's sheet always wins for plain
references — only the workbook-qualified form reaches the external one.

Input parameters:

- `apply` (array): Optional temporary values to apply before running formula(s)
- `formula` (string): Single formula to evaluate (must start with "=")
- `formulas` (array): Array of formulas to evaluate (more efficient for multiple formulas)
- `sheet` (string): Sheet name against which bare cell references (e.g. A1, SUM(A:A)) resolve. Defaults to the primary workbook's first sheet. Use this when you need formulas to evaluate in the context of a different sh…

### `goalSeek` (~105 tokens)

Find the input value needed to achieve a target result (like Excel's Goal Seek).
Iteratively adjusts the control cell until the target cell reaches the desired value.

Input parameters:

- `goalSeek` (object, required): Goal seek parameters
- `persist` (boolean): Whether to persist the solved control cell (and any pre-seek writes) to the workbook. Defaults to false: a pure calculation that reports the solution without changing the model.
- `write` (array, required): Values to write before goal seeking

### `whatIf` (~129 tokens)

Test hypothetical value changes and see which formula cells are affected.
Applies temporary changes, recalculates, shows before/after diff of affected formula cells,
then restores the original state. A string value starting with "=" is applied as a temporary
formula. Max 20 changes, max 100 affected cells reported.

Example: { "changes": { "A1": 50, "B1": "=A1*2" } }

Input parameters:

- `changes` (object, required): Map of cell references to hypothetical values (e.g. { 'A1': 50, 'B1': 100 })

### `getStyles` (~99 tokens)

Get the workbook's style definitions. Returns styles where each index corresponds to a style_index in cell data. Use this to understand what formatting (colors, fonts, borders, etc.) is applied to cells.

If no indices are provided, returns all styles as an array.
If indices are provided, returns only those styles as an object keyed by index.

Input parameters:

- `indices` (array): Optional array of style indices to fetch. If omitted, returns all styles.

### `getComment` (~124 tokens)

Read the full text of the comment or note on a specific cell, including all replies for threaded comments. Returns kind="none" if the cell has neither. Use after `getComments` to see the body of an entry whose preview was truncated, or when an agent message refers to a specific cell with a TODO/question on it.

Input parameters:

- `address` (string, required): Sheet-qualified cell reference, e.g. "'LBO Model'!E46" or "Sheet1!B2". For non-default sheets you must include the sheet name; otherwise the first sheet is assumed.

### `getComments` (~154 tokens)

List the cells in the workbook that have a comment or note attached, with author, kind (threaded comment vs. legacy note), reply count, and a short text preview. Comments are how a reviewer flags TODOs, justifies a number, or asks a question on a specific cell — read them when auditing, debugging, or completing a partly-built workbook. Returns up to 25 entries; pass `offset` to page. Use `getComment` to read the full text or thread for a specific cell.

Input parameters:

- `offset` (integer): Pagination offset; results are returned in pages of 25.
- `sheet` (string): Restrict to a single sheet by name. Omit to list across the whole workbook.

### `dependents` (~627 tokens)

Trace downstream dependents — the cells that read from a given cell, transitively.
Default mode 'grouped': cells sharing a formula pattern are collapsed into labeled chunks,
labeled from nearby headers. This provides a token-efficient structural view that shows how
values flow from parameters through intermediate calculations to outputs.

Switch to mode: "cells" to drill into individual cells: each node carries the formula, value,
and error of the dependent cell so you can see exactly how a value propagates through the sheet.
When a formula uses a range, Apiary resolves range containment internally; the dependent formula
appears as a direct child of the queried cell rather than via an intermediate range node.

"grouped" response shape — each node carries:
\- type: "output" (computed, no dependents), "inter" (computed, has dependents), "data" (value range), "param" (single value cell)
\- labels: human-readable names derived from nearby headers
\- formula: the formula pattern for this chunk (with relative references)
\- rootHeight: dependency distance from graph roots (parameters/data)
\- leafDepth: dependency distance from graph leaves (outputs)
\- dependents: dict of downstream chunk nodes keyed by their ref (omitted for terminal outputs)
\- alreadyVisited: true when this chunk was expanded elsewhere in the tree (diamond/cycle cut)
\- truncated: present when traversal stopped early; reason is "maxDepth" or "maxNodes"; totalChildren reports the real count when children were cut short

"cells" response shape — each node carries:
\- kind: "cell" or "name"
\- formula: the formula string, or null for value cells
\- value: the calculated value
\- errorValue: present only when the cell evaluates to a formula error
\- dependents: a dict of child nodes keyed by their own ref (omitted for leaves with no downstream consumers)
\- alreadyVisited: true when this node has been fully expanded elsewhere in the tree (diamond/cycle cut)
\- truncated: present when traversal stopped early; reason is…

Input parameters:

- `maxDepth` (integer): Maximum recursion depth through formula cells (default 10). Range expansion does not consume depth.
- `maxNodes` (integer): Total node budget for the returned tree (default 100). When the budget is exhausted, the node whose children were cut is marked truncated with totalChildren; re-query a specific cell to drill deeper.
- `mode` (string): Output mode: 'grouped' (default) shows chunks of cells sharing a formula pattern, labeled from nearby headers — token-efficient for structure. 'cells' drills into individual cells.
- `reference` (string, required): Cell reference to trace (e.g. 'C1', 'Sheet2!A1')

### `precedents` (~628 tokens)

Trace upstream dependencies — the cells a formula reads from, transitively.
Default mode 'grouped': cells sharing a formula pattern are collapsed into labeled chunks,
labeled from nearby headers. This provides a token-efficient structural view that surfaces
which parameters feed into which outputs.

Switch to mode: "cells" to drill into individual cells: each node carries the formula,
calculated value, and error (e.g. #DIV/0!) so you can follow error propagation to its source.
Ranges referenced by formulas appear as 'range' nodes. If every range member is a leaf value
cell, the range is collapsed into a single node with no further children.

"grouped" response shape — each node carries:
\- type: "output" (computed, no dependents), "inter" (computed, has dependents), "data" (value range), "param" (single value cell)
\- labels: human-readable names derived from nearby headers
\- formula: the formula pattern for this chunk (with relative references)
\- rootHeight: dependency distance from graph roots (parameters/data)
\- leafDepth: dependency distance from graph leaves (outputs)
\- precedents: dict of upstream chunk nodes keyed by their ref (omitted for leaves)
\- alreadyVisited: true when this chunk was expanded elsewhere in the tree (diamond/cycle cut)
\- truncated: present when traversal stopped early; reason is "maxDepth" or "maxNodes"; totalChildren reports the real count when children were cut short

"cells" response shape — each node carries:
\- kind: "cell", "range", or "name"
\- formula: the formula string, or null for value cells and range vertices
\- value: the calculated value (cell and name nodes)
\- errorValue: present only when the cell evaluates to a formula error
\- precedents: a dict of child nodes keyed by their own ref (omitted for leaves)
\- alreadyVisited: true when this node has been fully expanded elsewhere in the tree (diamond/cycle cut)
\- truncated: present when traversal stopped early; reason is "maxDepth" or "maxNodes"; totalChildren reports the real cou…

Input parameters:

- `maxDepth` (integer): Maximum recursion depth through formula cells (default 10). Range expansion does not consume depth.
- `maxNodes` (integer): Total node budget for the returned tree (default 100). When the budget is exhausted, the node whose children were cut is marked truncated with totalChildren; re-query a specific cell to drill deeper.
- `mode` (string): Output mode: 'grouped' (default) shows chunks of cells sharing a formula pattern, labeled from nearby headers — token-efficient for structure. 'cells' drills into individual cells.
- `reference` (string, required): Cell reference to trace (e.g. 'C1', 'Sheet2!A1')

### `inspect` (~206 tokens)

Inspect detailed per-cell information including value, formula, number format, style, and hyperlink.
Returns up to 20 cells per call. When the range is larger, the response is truncated and includes `nextOffset` — call again with the same `reference` and `offset: <nextOffset>` to continue.

Examples:
\- Single cell: { "reference": "A1" }
\- Range: { "reference": "B2:C5" }
\- Cross-sheet: { "reference": "Sheet2!A1" }
\- Next page: { "reference": "A1:K10", "offset": 20 }

Input parameters:

- `offset` (integer): Pagination offset into the range (0-based, row-major). When the previous response had `nextOffset`, pass that value here to read the next page.
- `reference` (string, required): Cell reference or range to inspect (e.g. 'A1', 'B2:C5', 'Sheet2!A1')

### `listErrors` (~156 tokens)

List all formula errors and model errors in a workbook, grouped by error, detail and origin (the cell where the error arose). Errors saved in the file are recalculated to find their origin and detail. Results are scoped to a sheet or range when provided, and truncated per group when the default cell limit is exceeded.

Input parameters:

- `max` (integer): Max cells listed per formula-error group (default 50).
- `range` (string): Restrict to a range, e.g. 'Sheet1!B2:D10' or 'B2:D10' (resolved against the default/first sheet). Takes precedence over 'sheet' if both are given.
- `sheet` (string): Restrict to a single sheet by name.

### `symbols` (~56 tokens)

Get workbook structural metadata: sheet dimensions, named ranges, tables, and dependency graph stats.
Complements describeStructure (which provides labels and data regions) with structural/entity information.

Use this to understand the workbook's overall shape before inspecting specific cells.

### `viewRange` (~505 tokens)

Render a worksheet rectangle as a compact text grid — by default the displayed (number-formatted) values, what a human sees in the cells — with column letters and row numbers.
Use this FIRST to scan or orient in an area (a financial statement, a block, a table): one call returns the whole rectangle instead of reading it cell-by-cell.
Pass `show` to audit other layers of the same grid: raw unformatted values, a style property ('-' marks unset cells), or the formula structure — formula cells get a legend key, identical fills share one key, so a miscolored cell, a wrong format, or a hardcoded override stands out against the value grid you just read.
For precedents/dependents or error provenance, use `inspect`.
Returns at most 500 cells; a larger rectangle marks the cut with *** TRUNCATED *** and ends with a note naming the rows or columns that remain — request those in a follow-up call.

Examples:
\- Range: { "reference": "B40:N80" }
\- Sheet-qualified: { "reference": "'LBO Model'!B40:N80" }
\- Single cell: { "reference": "C12" }
\- Font colors: { "reference": "B40:N80", "show": "fontColor" }
\- Formula structure: { "reference": "B40:N80", "show": "formula" }

Input parameters:

- `reference` (string, required): A1 range to view, sheet-qualified where needed (e.g. "'LBO Model'!B40:N80"). A single cell is allowed.
- `show` (string): What each cell renders. 'value' (default): formatted display values; a † marks a number whose format hides that it is numeric (a date, an accounting dash) — a legend below the grid explains it. 'rawV…

### `findCells` (~482 tokens)

Search for cells matching specified criteria within a sheet or range. Returns up to 200 matches. Use matchMode to control whether all criteria must match (AND, default) or any (OR). Range iteration is limited to 10,000 cells — use sheet scope for larger searches.

Input parameters:

- `fillColor` (string): Match cells whose fill color matches this search term. Accepts hex values ("FFFF00", "#FF0000"), partial hex ("FF"), color family words ("yellow", "blue", "gray") which match by hue, specific color n…
- `fontColor` (string): Match cells whose font color matches this search term. Accepts hex values ("0000FF", "#FF0000"), partial hex, color family words ("blue", "red", "gray") which match by hue, specific color names ("ste…
- `formulaContains` (string): Match cells whose formula text contains this substring (case-insensitive).
- `hasFormula` (boolean): Match cells that have (true) or don't have (false) a formula.
- `matchMode` (string): "AND" = all criteria must match (narrows results). "OR" = any criterion matches (broader sweep). Defaults to "AND".
- `range` (string): Restrict search to an A1-style range, e.g. 'Sheet1!B2:D10' or 'B2:D10'. An unqualified range resolves against 'sheet' if given, otherwise the first sheet. Defined names are not accepted. Ranges large…
- `sheet` (string): Restrict search to a single sheet by name.
- `valueContains` (string): Match cells whose value (converted to text) contains this substring (case-insensitive).
- `valueWithin` (array): Match cells whose numeric value falls within this inclusive range [min, max].

### `captureRange` (~245 tokens)

Render a range as a PNG image and return its raw bytes (Uint8Array).

Use this when the formatting itself is the information — fills, font colors, borders,
merged cells, number formats — that the text-grid tools (viewRange) can't convey, or when
the user asks to *see* part of the workbook. The bytes are ready to attach to a multimodal
message or write to a file; this tool does no LLM wiring itself.

Gridlines and row/column headers render as Excel shows them. Renders against the browser's
native canvas when available, and skia-canvas in Node.

Input parameters:

- `headers` (boolean): Draw row/column headers (A, B, C … / 1, 2, 3 …).
- `reference` (string, required): A1 range to capture, sheet-qualified where needed (e.g. "'LBO Model'!B40:N80"). A single cell is allowed.
- `scale` (number): Output pixel density for headless (Node/Worker) rendering — 2 = crisp/retina. Ignored on a browser main thread, where the display's devicePixelRatio governs.

### `generateWorkbookContext` (~37 tokens)

Generate a comprehensive natural-language description of the active workbook: sheet structures, data regions, labels, and relationships. More detailed than describeStructure.

### `executeOfficeJs` (~92 tokens)

Execute an Office.js code snippet directly against the active workbook. Returns any error plus the list of Office.js APIs the code used that are not yet implemented. Edits synced before a script error remain applied.

Input parameters:

- `code` (string, required): Office.js JavaScript to run against the active workbook. `context` (RequestContext) and `Excel` are in scope; call `await context.sync()` to flush writes.

## Diagnostics

Captured diagnostic sections: Provenance, Dependencies. The full working is on the page: https://verifymcp.io/servers/is-grid-agent-tools/grid-is-agent-tools#diagnostics

## Score history

- 2026-11-05: 65
- 2026-11-04: 64
- 2026-11-03: 64
- 2026-11-02: 63
- 2026-11-01: 59
- 2026-10-31: 59
- 2026-10-30: 59
- 2026-10-29: 59
- 2026-10-28: 59
- 2026-10-27: 59
- 2026-10-26: 59
- 2026-10-25: 59
- 2026-10-24: 59
- 2026-10-23: 44

## Common questions

### What is the GRID Agent Tools MCP server?

GRID Agent Tools is an MCP server listed in the public MCP registry as is.grid/agent-tools. Load, read, edit, and recalculate .xlsx workbooks headlessly, no Excel required. This page covers its npm package (@grid-is/agent-tools).

### Is the GRID Agent Tools MCP server safe to use?

GRID Agent Tools scores 65 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 5 November 2026. It declares no install or post-install scripts. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the GRID Agent Tools MCP server expose?

GRID Agent Tools exposes 28 tools: loadWorkbook, createWorkbook, saveWorkbook, listWorkbooks, selectWorkbook, and 23 more. Their descriptions and schemas cost roughly 5,838 tokens of context every time the server is loaded.

### Is the GRID Agent Tools MCP server still maintained?

GRID Agent Tools is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- npm package: https://www.npmjs.com/package/@grid-is/agent-tools
- Socket report: https://socket.dev/npm/package/@grid-is/agent-tools
- Website: https://grid.is/agent-tools
- Changelog RSS feed: https://verifymcp.io/servers/is-grid-agent-tools/grid-is-agent-tools.xml
- Changelog JSON feed: https://verifymcp.io/servers/is-grid-agent-tools/grid-is-agent-tools.json
- HTML version of this page: https://verifymcp.io/servers/is-grid-agent-tools/grid-is-agent-tools
