xlsx-for-ai 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mcp.js +138 -1
- package/package.json +1 -1
package/mcp.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* xlsx-for-ai MCP stdio server (2.0)
|
|
6
6
|
*
|
|
7
|
-
* Registers
|
|
7
|
+
* Registers 18 tools and relays each tools/call to the hosted API.
|
|
8
8
|
* xlsx_read falls back to local engine if API is unreachable (5xx / timeout).
|
|
9
9
|
* All other tools fail with a clear "needs API connectivity" error.
|
|
10
10
|
*/
|
|
@@ -393,6 +393,65 @@ const TOOLS = [
|
|
|
393
393
|
},
|
|
394
394
|
},
|
|
395
395
|
|
|
396
|
+
{
|
|
397
|
+
name: 'xlsx_eval',
|
|
398
|
+
description:
|
|
399
|
+
'xlsx-for-ai — read, write, diff, redact, supervise .xlsx files locally.\n' +
|
|
400
|
+
'This tool: evaluate Excel formulas against a LOCAL .xlsx file via HyperFormula. xlwings-style.\n' +
|
|
401
|
+
'Two modes: pass `formulas` (array of "=SUM(A1:A10)" expressions to compute against the workbook) or `cells` (array of "Sheet1!A1" cell refs to fresh-evaluate). Replaces pandas\' "trust the cached value" behavior with a real eval — if the cache is stale or missing, this still produces the right answer.\n\n' +
|
|
402
|
+
'USE WHEN: the user wants the live computed value of a formula, not the cached one. Or when a workbook has formulas that depend on external data the cache might be stale on. ' +
|
|
403
|
+
'Engine omits INDIRECT/HYPERLINK/WEBSERVICE/RTD/DDE by design — no I/O risk.\n\n' +
|
|
404
|
+
'DO NOT USE WHEN: the workbook has no formulas (use xlsx_read). Or for upload/attached files.',
|
|
405
|
+
inputSchema: {
|
|
406
|
+
type: 'object',
|
|
407
|
+
properties: {
|
|
408
|
+
file_path: { type: 'string', description: 'Absolute path to the .xlsx file.' },
|
|
409
|
+
formulas: {
|
|
410
|
+
type: 'array',
|
|
411
|
+
items: { type: 'string' },
|
|
412
|
+
description: 'Freeform formula expressions to evaluate against the workbook. Each ~"=A1+B1" or "=SUM(Sheet1!A:A)".',
|
|
413
|
+
},
|
|
414
|
+
cells: {
|
|
415
|
+
type: 'array',
|
|
416
|
+
items: { type: 'string' },
|
|
417
|
+
description: 'Cell refs to fresh-evaluate, e.g. ["Sheet1!A1", "Calc!B5"].',
|
|
418
|
+
},
|
|
419
|
+
sheet: { type: 'string', description: 'Default sheet for unqualified cell refs.' },
|
|
420
|
+
},
|
|
421
|
+
required: ['file_path'],
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
|
|
425
|
+
{
|
|
426
|
+
name: 'xlsx_convert',
|
|
427
|
+
description:
|
|
428
|
+
'xlsx-for-ai — read, write, diff, redact, supervise .xlsx files locally.\n' +
|
|
429
|
+
'This tool: 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' +
|
|
430
|
+
'No other tool in the MCP space ingests legacy formats — pandas.read_excel only reads xlsx/xls; openpyxl is xlsx-only. xlsx_convert is the only "any-spreadsheet → LLM-readable" hosted endpoint.\n\n' +
|
|
431
|
+
'USE WHEN: the user has a .xls / .xlsb / .ods / Numbers / .csv / Lotus / Quattro / dBASE file they want to read or convert. ' +
|
|
432
|
+
'Output to text formats (csv/json/md/html) renders into the response body for the agent to read directly. Output to binary formats (xlsx/xlsb/etc.) returns bytes in `_meta.file_b64` for the npm client to save.\n\n' +
|
|
433
|
+
'DO NOT USE WHEN: the input is already xlsx and you want to read it (use xlsx_read). Or for upload/attached files.',
|
|
434
|
+
inputSchema: {
|
|
435
|
+
type: 'object',
|
|
436
|
+
properties: {
|
|
437
|
+
file_path: { type: 'string', description: 'Absolute path to the source spreadsheet file (any supported format).' },
|
|
438
|
+
to: {
|
|
439
|
+
type: 'string',
|
|
440
|
+
enum: [
|
|
441
|
+
'xlsx', 'xlsb', 'xlsm', 'xls', 'ods', 'fods', 'dbf',
|
|
442
|
+
'csv', 'tsv', 'txt', 'html', 'md', 'json',
|
|
443
|
+
'dif', 'sylk', 'eth', 'prn', 'rtf',
|
|
444
|
+
],
|
|
445
|
+
description: 'Target format. Binary formats land bytes in _meta.file_b64; text formats render in body.',
|
|
446
|
+
},
|
|
447
|
+
sheet: { type: 'string', description: 'Render only this sheet (text outputs).' },
|
|
448
|
+
sheets: { type: 'string', enum: ['all', 'first'], description: 'For text outputs: render every sheet (default) or only the first.' },
|
|
449
|
+
out_path: { type: 'string', description: 'Optional save path for binary outputs (xlsx/xlsb/etc.).' },
|
|
450
|
+
},
|
|
451
|
+
required: ['file_path', 'to'],
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
|
|
396
455
|
{
|
|
397
456
|
name: 'xlsx_validate',
|
|
398
457
|
description:
|
|
@@ -410,6 +469,62 @@ const TOOLS = [
|
|
|
410
469
|
required: ['file_path'],
|
|
411
470
|
},
|
|
412
471
|
},
|
|
472
|
+
|
|
473
|
+
{
|
|
474
|
+
name: 'xlsx_data_validations',
|
|
475
|
+
description:
|
|
476
|
+
'xlsx-for-ai — read, write, diff, redact, supervise .xlsx files locally.\n' +
|
|
477
|
+
'This tool: 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' +
|
|
478
|
+
'No other tool can do this: pandas drops validations entirely on read; openpyxl exposes them but only on a per-cell loop; this surfaces them in one shot with target cells, formulae, error messages, and prompt text.\n\n' +
|
|
479
|
+
'USE WHEN: auditing a form / data-entry workbook to know what inputs are legal. Or extracting a dropdown list for use elsewhere. Or generating fixtures that match the validation contract. ' +
|
|
480
|
+
'Free tier — counts against the 10k/mo cap.\n\n' +
|
|
481
|
+
'DO NOT USE WHEN: just trying to read values (use xlsx_read). Or trying to enforce validations on write (xlsx_write does not write validations).',
|
|
482
|
+
inputSchema: {
|
|
483
|
+
type: 'object',
|
|
484
|
+
properties: {
|
|
485
|
+
file_path: { type: 'string', description: 'Absolute path to the .xlsx file.' },
|
|
486
|
+
sheet: { type: 'string', description: 'Optional: restrict to a specific sheet.' },
|
|
487
|
+
},
|
|
488
|
+
required: ['file_path'],
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
|
|
492
|
+
{
|
|
493
|
+
name: 'xlsx_hyperlinks',
|
|
494
|
+
description:
|
|
495
|
+
'xlsx-for-ai — read, write, diff, redact, supervise .xlsx files locally.\n' +
|
|
496
|
+
'This tool: 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' +
|
|
497
|
+
'No other tool can do this: pandas drops hyperlinks on read entirely; openpyxl gives raw access but does not classify or aggregate; this surfaces all links plus a per-kind tally for instant audit.\n\n' +
|
|
498
|
+
'USE WHEN: security-auditing a workbook before opening it (what URLs does it point at?). Or extracting a reference list of URLs from a financial model / dashboard. Or finding mailto links for a contact-list workbook. ' +
|
|
499
|
+
'Free tier — counts against the 10k/mo cap.\n\n' +
|
|
500
|
+
'DO NOT USE WHEN: trying to follow / fetch the targets (this tool does not fetch — by design, for safety). Or just reading cell text (use xlsx_read).',
|
|
501
|
+
inputSchema: {
|
|
502
|
+
type: 'object',
|
|
503
|
+
properties: {
|
|
504
|
+
file_path: { type: 'string', description: 'Absolute path to the .xlsx file.' },
|
|
505
|
+
sheet: { type: 'string', description: 'Optional: restrict to a specific sheet.' },
|
|
506
|
+
},
|
|
507
|
+
required: ['file_path'],
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
|
|
511
|
+
{
|
|
512
|
+
name: 'xlsx_topology',
|
|
513
|
+
description:
|
|
514
|
+
'xlsx-for-ai — read, write, diff, redact, supervise .xlsx files locally.\n' +
|
|
515
|
+
'This tool: 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' +
|
|
516
|
+
'No other tool can do this: pandas gives you a frame per sheet but no structure; openpyxl makes you fan out across 6+ object trees to learn the same thing; this is the "what is in this workbook?" call you make first to decide which other tool to call next.\n\n' +
|
|
517
|
+
'USE WHEN: an agent has just been handed a workbook and needs to orient before drilling in. Or surveying many workbooks for triage / index. Or auditing whether a workbook is "interesting" (formulas? macros? external refs?). ' +
|
|
518
|
+
'Free tier — counts against the 10k/mo cap.\n\n' +
|
|
519
|
+
'DO NOT USE WHEN: you already know the sheet you want and just want its data (use xlsx_read or xlsx_describe).',
|
|
520
|
+
inputSchema: {
|
|
521
|
+
type: 'object',
|
|
522
|
+
properties: {
|
|
523
|
+
file_path: { type: 'string', description: 'Absolute path to the .xlsx file.' },
|
|
524
|
+
},
|
|
525
|
+
required: ['file_path'],
|
|
526
|
+
},
|
|
527
|
+
},
|
|
413
528
|
];
|
|
414
529
|
|
|
415
530
|
// ---------------------------------------------------------------------------
|
|
@@ -595,6 +710,28 @@ async function dispatchTool(name, args) {
|
|
|
595
710
|
return callTool('xlsx_pivot', body);
|
|
596
711
|
}
|
|
597
712
|
|
|
713
|
+
if (name === 'xlsx_eval') {
|
|
714
|
+
const body = {
|
|
715
|
+
file_b64: fileToB64(args.file_path),
|
|
716
|
+
options: { sheet: args.sheet },
|
|
717
|
+
};
|
|
718
|
+
if (args.formulas) body.formulas = args.formulas;
|
|
719
|
+
if (args.cells) body.cells = args.cells;
|
|
720
|
+
return callTool('xlsx_eval', body);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (name === 'xlsx_convert') {
|
|
724
|
+
const body = {
|
|
725
|
+
file_b64: fileToB64(args.file_path),
|
|
726
|
+
to: args.to,
|
|
727
|
+
options: { sheet: args.sheet, sheets: args.sheets },
|
|
728
|
+
};
|
|
729
|
+
const result = await callTool('xlsx_convert', body);
|
|
730
|
+
// Binary outputs land bytes in _meta.file_b64 — apply the save helper
|
|
731
|
+
// if the user passed out_path.
|
|
732
|
+
return applyFileB64(result, args.out_path);
|
|
733
|
+
}
|
|
734
|
+
|
|
598
735
|
if (name === 'xlsx_validate') {
|
|
599
736
|
return callTool('xlsx_validate', {
|
|
600
737
|
file_b64: fileToB64(args.file_path),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xlsx-for-ai",
|
|
3
3
|
"mcpName": "io.github.senoff/xlsx-for-ai",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.3.0",
|
|
5
5
|
"description": "The MCP server that makes LLMs reliable on real-world Excel spreadsheets. Thin npm client over a hosted API — read, write, diff, redact, and supervise .xlsx files from any MCP-aware agent.",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"bin": {
|