xlsx-for-aiBLOCK
MCP server + CLI giving AI agents 50 spreadsheet tools for .xlsx — live-recalc formulas (~390 Excel functions), repair broken references & external links, read/write, diff, and audit. Works in Claude Code, Cursor, Codex, and any MCP client.
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[](https://glama.ai/mcp/servers/senoff/xlsx-for-ai)
Short name: xfa — a real CLI command (`xfa `, `xfa samples`, `xfa --version`) and the prompt shorthand (e.g. "use xfa to read this file"). Same entrypoint as `xlsx-for-ai`; matches the internal `xfa_ / XFA_` brand surface.
Verified values, preserved structure, up to 100MB
The missing reliability layer for spreadsheet work in LLM agents. Read, write, diff, validate, and analyze .xlsx files end-to-end — with merged cells, formulas, named ranges, conditional formatting, pivots, and charts preserved.
xlsx-for-ai makes Claude reliable on real-world Excel files. Forty-plus tools cover the structural surface that pandas-style sandboxes drop on the floor: merged cells, named ranges, formulas with results, conditional formatting, pivots, slicers, charts, comments, data validations, hyperlinks, cross-sheet topology, external links, form controls, VBA macros, document properties, and protection settings. A soundness check (xlsx_validate) flags corruption other readers silently mask. A hosted recalc engine computes served values in-house — no third-party formula engine in the serve path.
npm install -g xlsx-for-ai
The global install puts the xlsx-for-ai-mcp binary on your PATH — that's what the canonical configs below point at. A pinned global install launches fast (it still needs an internet connection, because the files are read by the hosted service); upgrade with npm install -g xlsx-for-ai@latest when a new version ships.
Upgrading from 1.5.x? This is a re-architecture, not a feature bump: the heavy local engine is gone from the npm package. All rendering happens server-side. The cursor-reads-xlsx alias still works. See Migration below.MCP configuration
Add the server to your agent runtime under the name `xfa` (so "use xfa to rea
fc3294919ea1OBSERVED · 2026-10-10Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add xlsx-for-ai -- npx -y [email protected]
Exposed tools (55)
50 read · 4 write · 1 destructive. Blast radius: 1 tool can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
server_only_ping | read | No file. |
xlsx_aggregate | read | pandas-style df.groupby([cols]).agg({col: func}) on a LOCAL .xlsx file. funcs: sum / mean / min / max / count / count_distinct.\n |
xlsx_brand_new | read | a new server-side tool |
xlsx_cached_only | read | only in cache |
xlsx_charts | read | List every chart in a LOCAL .xlsx file with type (bar / line / pie / scatter / area / doughnut / radar / stock / surface / bubble), title, axis titles, and per-series formula refs (the cell ranges the chart pulls from). Sheet attribution via the OOXML drawing rel chain.\n\n |
xlsx_comments | read | list every cell comment in a workbook — both legacy notes (yellow stickies, cell.note) AND modern threaded comments (multi-author conversations stored separately in the OOXML zip). Per entry: kind, sheet, cell, author, text, plus any reply thread.\n |
xlsx_conditional_formats | read | list every conditional formatting rule in a workbook — color scales, data bars, icon sets, formula-based highlights, top-N, duplicate / unique values, contains-text, time-period, above-average. Per rule: range, type, operator, formulae, priority, stopIfTrue.\n |
xlsx_convert | read | universal spreadsheet format converter. Reads ANY of 25+ input formats (xlsx, xlsb, xlsm, xls, ods, fods, numbers, csv, tsv, dbf, lotus 1-2-3, quattro pro, sylk, dif, html, rtf, etc.) and emits ANY supported output format (xlsx, csv, json, md, html, etc.).\n |
xlsx_data_validations | read | list every cell-level data validation rule (dropdowns, numeric/date bounds, text-length caps, custom formulas) defined in a workbook — the constraints that Excel enforces when a human types into the cell.\n |
xlsx_describe | read | pandas-style df.describe() per column — count, nulls, unique, min/max/mean/std for numerics, dtype with purity score.\n |
xlsx_diff | read | compute a semantic diff between two LOCAL .xlsx files — cell-level deltas, formula changes, added/removed rows.\n |
xlsx_dup | read | first wins |
xlsx_dynamic_only | read | lives only on the server |
xlsx_eval | read | evaluate Excel formulas against a LOCAL .xlsx file with our own recalc engine. xlwings-style.\n |
xlsx_external_links | read | list every external workbook reference this file depends on — |
xlsx_filter | read | pandas-style row filter on a LOCAL .xlsx file with predicates AND-combined: eq/ne/gt/gte/lt/lte/contains/in/is_null/not_null.\n |
xlsx_form_controls | destructive | list every form control (Check Box, Button, Drop-down, List Box, Option Button, Scroll Bar, Spinner, Label, Group Box) in a workbook with the linked cell, current value, dropdown source range, and min/max/step bounds where applicable.\n |
xlsx_formulas | read | extract every formula in a LOCAL .xlsx workbook — cell coord (A1), formula text, cached result. openpyxl-style read-only metadata.\n |
xlsx_full | read | Real desc |
xlsx_future_cached | read | tampered |
xlsx_healer_diagnose | read | produce a structured diagnostic report of external references that are broken or at risk in a workbook. Returns five classes of finding: (1) external-workbook references that can\ |
xlsx_healer_intent | read | Goal-driven healing. Caller declares an INTENT ( |
xlsx_healer_simulate | read | simulate recipient-side accessibility of a workbook\ |
xlsx_hyperlinks | read | list every hyperlink in a workbook with its anchor cell, target URL/anchor, display text, tooltip, and a kind classifier (external / internal / mailto / unknown).\n |
xlsx_images | read | List every embedded image in a LOCAL .xlsx file with format (png / jpg / gif / svg / bmp / tiff / emf / wmf), size in bytes, sheet attribution, and anchor cell range (the cells the image floats over). Reads xl/media/* + xl/drawings/* directly.\n\n |
xlsx_keep | read | keep |
xlsx_list_sheets | read | list sheet names, dimensions, and visibility for a LOCAL .xlsx file.\n |
xlsx_macros | read | Inspect xlsm / xlsb workbooks for VBA macro presence, vbaProject.bin size, and likely module names (ThisWorkbook / Sheet<N> / Module<N> / Class<N> / UserForm<N> via heuristic UTF-16LE scan). Returns short safety advice the LLM should relay to the user.\n\n |
xlsx_merged_cells | read | list every merged-cell region with master-cell value, range, span dimensions, and kind heuristic ( |
xlsx_named_ranges | read | list all defined names (named ranges) in a LOCAL .xlsx workbook — name, scope (workbook or sheet), kind (cell / range / formula), reference.\n |
xlsx_only | read | kept |
xlsx_only_in_stale_cache | read | old but real |
xlsx_pivot | read | pandas-style pivot_table() on a LOCAL .xlsx file — reshape a flat table into a 2D matrix where rows are unique values of |
xlsx_post_slack | write | upload a local .xlsx file to a Slack channel as a file attachment, with an optional accompanying message.\n |
xlsx_post_teams | write | Upload a local .xlsx file to a Microsoft Teams channel as a file attachment, with an optional accompanying message.\n\n |
xlsx_print_settings | read | surface |
xlsx_properties | read | Surface the workbook\ |
xlsx_read | read | xfa — read an .xlsx file by path and return a rendered markdown/JSON/SQL representation.\n\n |
xlsx_read_handle | read | read a workbook that has already been uploaded to the server via the chunked upload flow, by its server-side cache handle, WITHOUT re-transferring the bytes. Returns the same shape as xlsx_read (text / json / markdown) but skips the file_b64 round-trip.\n\n |
xlsx_receipt | read | Attach an AI-generation receipt to a LOCAL .xlsx file — a cryptographic attestation embedded in docProps/custom.xml that says |
xlsx_redact | read | redact PII and sensitive values from a LOCAL .xlsx file before sharing or archiving.\n |
xlsx_schema | read | infer column schema of a LOCAL .xlsx file — types, nullable flags, header row, sample values.\n |
xlsx_session_set_validations | write | configure per-session data-validation rules the server will apply to subsequent calls in the same session (e.g., reject rows missing required columns, enforce enum values on a category column, range-bound numeric inputs). Stateful — affects this session only.\n\n |
xlsx_slicers_timelines | read | List every slicer (interactive filter button) and timeline (date-range filter visual) in a LOCAL .xlsx file with their captions, source bindings (table column or pivot table), and timeline granularity (years / quarters / months / days) plus the currently-selected date range.\n\n |
xlsx_sort | read | pandas-style df.sort_values() on a LOCAL .xlsx file with multi-column sort and per-column direction (asc/desc, default asc).\n |
xlsx_stamp | read | Sign a LOCAL .xlsx file with a |
xlsx_stub | read | has desc but no schema |
xlsx_tables | read | list every Excel ListObject ( |
xlsx_topology | read | one-call workbook orientation. Returns sheets × dimensions × formulas × named ranges × tables × validations × hyperlinks × merges in one shot, plus feature flags (macros / external refs / pivots / LAMBDA / dynamic arrays).\n |
xlsx_unknown_future_tool | read | d |
xlsx_validate | read | soundness check on a LOCAL .xlsx file — parses the workbook with the server\ |
xlsx_value_counts | read | pandas-style Series.value_counts() on one column of a LOCAL .xlsx file — count each unique value, sorted by frequency desc, with percentage.\n |
xlsx_verify_receipt | read | verify a workbook\ |
xlsx_verify_stamp | read | verify a workbook\ |
xlsx_write | write | create or update a LOCAL .xlsx file from a structured spec.\n\n |
Trust audit
BLOCKgrade D · trust 61/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | WARN |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (2 observation(s))
- Network
- declared (7 observation(s))
- Shell
- declared (1 observation(s))
- Dependencies
- not all pinned
- Secrets in source
- found
Findings (25)
cmd.append("--insecure-ignore-tlog") # degraded --no-tlog-upload path (sysarch-approved)api_key: 'xfa_ci_skip_registration',
const secret = 'xfa_live_abcdefghijklmnop1234567890';
payload: { error: { message: 'invalid token xoxb-1234567890-abcdefghij' } },assert.ok(!out.includes('xoxb-1234567890'),['t xoxb-1234567890-abcdef x', 'xoxb-1234567890', '<slack-token>'],
7. **Hidden trailing columns** (#1953). Fixture: hide cols X:Z when last data is column J. Assert: `<col hidden="1" min="24" max="26"/>` survives.
xlsx_form_controls
reporting-pack-v1.xlsx
reporting-pack-v2.xlsx
.grace-refutes.yml
const { SERVER_KEY, TOOL_PREFIX, OUTPUT } = require('../../scripts/plugin/generate-session-start.js');const { generate, allTools, MANIFEST, OUTPUT } = require('../../scripts/plugin/generate-session-start.js');const { firstSentence, validateList } = require('../../scripts/plugin/refresh-tool-manifest.js');const { TOOLS } = require('../../mcp.js');const { TOOL_ANNOTATIONS, applyAnnotations } = require('../../lib/annotations');- Spawn with `OTEL_SERVICE_NAME=<agent-name>` exported so traces land in Phoenix (http://127.0.0.1:6006) tagged by agent.
- `OTEL_SERVICE_NAME=cleaner` — traces land in Phoenix at http://127.0.0.1:6006 tagged `cleaner`.
- **OTEL traces tagged `cleaner`.** Spawn cleaner; complete a diagnose + execute against `na-variants-mixed`. Query Phoenix at http://127.0.0.1:6006 for traces tagged `service.name=cleaner` in the las
- Phoenix observability: `http://127.0.0.1:6006` (Phase 1 harness)
process.env.XLSX_FOR_AI_API = `http://127.0.0.1:${serverPort}`;blob = base64.b64decode(m["blob_b64"])
bundle = base64.b64decode(m["bundle_b64"])
base64.b64decode(bundle_b64, validate=True) # bundle must be real base64 (not consumed here)
blob = base64.b64decode(blob_b64, validate=True)
Gates applied: no_behavioural_pass.
fc3294919ea1full audit observations/trust-audit/mcp-server/senoff__xlsx-for-ai.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-10 | fc3294919ea1 | BLOCK | D | 61 | first audit |
Questions
What is the xlsx-for-ai MCP server?
MCP server + CLI giving AI agents 50 spreadsheet tools for .xlsx — live-recalc formulas (~390 Excel functions), repair broken references & external links, read/write, diff, and audit. Works in Claude Code, Cursor, Codex, and any MCP client.
What tools does xlsx-for-ai expose?
55 in total: 50 read-only, 4 that write, and 1 that can delete or overwrite (xlsx_form_controls). Every one is listed on this page with its risk.
Is xlsx-for-ai safe to connect to an agent?
No — not without reading the findings first. The audit graded it D (61/100) and found 1 critical or high issue in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 1 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does xlsx-for-ai need?
It reads SLACK_BOT_TOKEN, TEAMS_GRAPH_TOKEN and XLSX_FOR_AI_KEY from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does xlsx-for-ai run?
It speaks stdio, so it runs as a local process your client starts. It is published on npm as xlsx-for-ai at 4.2.4.
How current is this page?
The grade is for one exact copy of the source (fc3294919ea1), read on 2026-10-10. The repository is watched and re-audited when it changes.