xlvane 1.1.1 → 1.2.1

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/README.md CHANGED
@@ -58,7 +58,7 @@ xlvane help edit # usage and examples of one command
58
58
  - `--json` prints one JSON document per command with a documented schema ([docs/cli-json.md](https://github.com/DevXord/xlvane/blob/main/docs/cli-json.md)). Exit codes: 0 success, 1 a check found something (`diff`, `validate`), 2 usage error, 3 input or file error.
59
59
  - Colour (red errors, yellow warnings, green results, bold headings) is used only on a terminal and never carries information alone; `NO_COLOR` or `TERM=dumb` turn it off, `FORCE_COLOR=1` turns it on. Control characters from files, such as an escape character in a cell, are shown as `\x1b` and never reach the terminal.
60
60
  - Tables and summaries go to separate streams: `xlvane read report.xlsx > out.txt` writes only the table; the row count and warnings notes go to stderr.
61
- - `xlvane migrate` prepares a project for `@xlvane/compat`.
61
+ - `xlvane migrate` prepares a project for `@xlvane/compat`, and `xlvane mcp` starts the MCP server from `@xlvane/mcp` (a separate package; [its README](https://github.com/DevXord/xlvane/blob/main/packages/mcp/README.md)).
62
62
 
63
63
  ## Reading a workbook
64
64
 
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { On as XlvError, Vt as suggest, _ as isoDate, b as readWorkbook, dn as parseRange, g as inspect } from "./options-Ba6r4zP1.js";
3
- import { a as appendRows, c as fromCSV, d as fromJSON, f as pickSheet, h as toJSON, l as inferValue, n as insertRows, o as editCells, p as readTable, s as diff, t as deleteRows, u as toCSV } from "./rows-Biu_ddwz.js";
4
- import { i as readInput } from "./node-files-CsQVpKgP.js";
2
+ import { On as XlvError, Vt as suggest, _ as isoDate, b as readWorkbook, dn as parseRange, g as inspect } from "./options-Ba1iWD-Z.js";
3
+ import { a as appendRows, c as fromCSV, d as fromJSON, f as pickSheet, h as toJSON, l as inferValue, n as insertRows, o as editCells, p as readTable, s as diff, t as deleteRows, u as toCSV } from "./rows-IWKIxHt9.js";
4
+ import { i as readInput } from "./node-files-CDb6TyZb.js";
5
5
  import { existsSync, readFileSync } from "node:fs";
6
6
  import { chmod, lstat, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
7
7
  import process from "node:process";
@@ -935,7 +935,7 @@ function welcome(out, version, commands) {
935
935
  "",
936
936
  `${out.bold("Commands:")} ${commands.map((c) => c.name).join(", ")}`,
937
937
  `${out.bold("More:")} xlvane help <command> · Docs: ${DOCS_URL}`,
938
- `For AI agents and scripts: add --json to any command (${DOCS_IN_PACKAGE}/cli-json.md)`,
938
+ `For AI agents and scripts: add --json to any command (${DOCS_IN_PACKAGE}/cli-json.md), or run "xlvane mcp"`,
939
939
  ""
940
940
  ].join("\n");
941
941
  }
@@ -1844,6 +1844,75 @@ function renderReport(out, file, r, verbose) {
1844
1844
  if (r.warnings.length > 0) lines.push("", ...warningsBlock(out, r.warnings));
1845
1845
  return lines.join("\n");
1846
1846
  }
1847
+ // src/cli/commands/mcp.ts
1848
+ /** The package that holds the MCP server; xlvane does not depend on it (docs/PLAN.md section 3). */
1849
+ const MCP_PACKAGE = "@xlvane/mcp";
1850
+ /**
1851
+ * Whether loading failed because @xlvane/mcp itself is missing. A missing dependency of an
1852
+ * installed @xlvane/mcp has the same error code but names that dependency (D-I04).
1853
+ */
1854
+ function isModuleNotFound(error) {
1855
+ const code = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
1856
+ const message = error instanceof Error ? error.message : "";
1857
+ return (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") && (message.includes(`'@xlvane/mcp'`) || message.includes(`"@xlvane/mcp"`));
1858
+ }
1859
+ /** Options of the xlvane command line itself, which the server does not take. */
1860
+ const OWN_OPTIONS = /* @__PURE__ */ new Set([
1861
+ "--quiet",
1862
+ "-q",
1863
+ "--verbose"
1864
+ ]);
1865
+ const mcpCommand = {
1866
+ name: "mcp",
1867
+ summary: "Start the MCP server for AI agents",
1868
+ description: "Starts the Model Context Protocol server from the separate package @xlvane/mcp over stdin and stdout, so that an AI agent can inspect, read, convert and compare spreadsheets through tools instead of code. The arguments after \"mcp\" are passed to the server: --root <dir> (required, repeatable) names a directory the tools may use, --allow-write adds the tools that write files, and --max-file-size <bytes>, --max-rows <n> and --max-response-chars <n> set its limits. --json is not available, because stdout carries the protocol. If @xlvane/mcp is not installed, the command prints how to install it. The exit code is the server's: 0 when the client closed the connection, 2 for wrong arguments, 3 for a directory that cannot be used.",
1869
+ usage: "[server options]",
1870
+ positionals: {
1871
+ min: 0,
1872
+ max: Number.POSITIVE_INFINITY,
1873
+ names: []
1874
+ },
1875
+ passThrough: true,
1876
+ options: {},
1877
+ examples: [{
1878
+ command: "xlvane mcp --root ./data",
1879
+ description: "Serve the files in ./data, read-only"
1880
+ }, {
1881
+ command: "xlvane mcp --root ./data --allow-write",
1882
+ description: "Also allow writing files there"
1883
+ }],
1884
+ related: ["inspect", "read"],
1885
+ async run(ctx) {
1886
+ if (ctx.json) throw usageError("\"xlvane mcp\" does not take --json: the server uses stdout for the protocol.", "Run \"xlvane mcp --root <dir>\" without --json; the server reports its own errors as MCP results.", {
1887
+ command: "mcp",
1888
+ option: "--json"
1889
+ });
1890
+ let mod;
1891
+ try {
1892
+ mod = await ctx.io.importModule(MCP_PACKAGE);
1893
+ } catch (error) {
1894
+ if (!isModuleNotFound(error)) throw error;
1895
+ throw new XlvError("XLV_E_NOT_INSTALLED", `The MCP server is in the separate package ${MCP_PACKAGE}, which is not installed.`, {
1896
+ hint: `Install it next to xlvane with "npm install ${MCP_PACKAGE}", then run "xlvane mcp" again.`,
1897
+ details: { package: MCP_PACKAGE },
1898
+ cause: error
1899
+ });
1900
+ }
1901
+ if (typeof mod.runCli !== "function") throw new XlvError("XLV_E_NOT_SUPPORTED", `The installed ${MCP_PACKAGE} does not contain the MCP server yet.`, {
1902
+ hint: `Update ${MCP_PACKAGE} to a version that provides the server.`,
1903
+ details: {
1904
+ package: MCP_PACKAGE,
1905
+ feature: "runCli"
1906
+ }
1907
+ });
1908
+ const code = await mod.runCli(ctx.argv.filter((a) => !OWN_OPTIONS.has(a)));
1909
+ return {
1910
+ result: { exitCode: code },
1911
+ exitCode: code === 0 || code === 1 || code === 2 ? code : 3,
1912
+ render: () => ""
1913
+ };
1914
+ }
1915
+ };
1847
1916
  // src/cli/commands/migrate.ts
1848
1917
  /** The dependency value that installs @xlvane/compat under the name exceljs (npm alias). */
1849
1918
  const ALIAS = "npm:@xlvane/compat@^1";
@@ -2421,7 +2490,8 @@ const COMMANDS = [
2421
2490
  };
2422
2491
  }
2423
2492
  },
2424
- migrateCommand
2493
+ migrateCommand,
2494
+ mcpCommand
2425
2495
  ];
2426
2496
  /** Exit codes (docs/cli-json.md). */
2427
2497
  const EXIT = {
@@ -2474,8 +2544,11 @@ async function run(argv, io) {
2474
2544
  stdout(commandHelp(out, spec));
2475
2545
  return EXIT.ok;
2476
2546
  }
2477
- const args = parseCommandArgs(spec, rest);
2478
- checkPositionals(spec, args);
2547
+ const args = spec.passThrough ? {
2548
+ positionals: rest,
2549
+ values: {}
2550
+ } : parseCommandArgs(spec, rest);
2551
+ if (!spec.passThrough) checkPositionals(spec, args);
2479
2552
  const quiet = args.values["quiet"] === true;
2480
2553
  const ctx = {
2481
2554
  io,
@@ -2605,6 +2678,7 @@ function suggestCommand(error, first, rest, spec) {
2605
2678
  const at = rest.findIndex((a, i) => a === path && rest[i - 1] !== "-o" && rest[i - 1] !== "--output");
2606
2679
  if (at >= 0) return commandLine([spec.name, ...rest.map((a, i) => i === at ? suggestions[0] : a)]);
2607
2680
  }
2681
+ if (error.code === "XLV_E_NOT_INSTALLED" && typeof d["package"] === "string") return `npm install ${d["package"]}`;
2608
2682
  return null;
2609
2683
  }
2610
2684
  /** Where the problem is, as one line; `null` when the message already says it all. */
@@ -2667,6 +2741,7 @@ run(process.argv.slice(2), {
2667
2741
  stdoutIsTTY: process.stdout.isTTY === true,
2668
2742
  stderrIsTTY: process.stderr.isTTY === true,
2669
2743
  columns: process.stdout.columns,
2744
+ importModule: (specifier) => import(specifier),
2670
2745
  version: version()
2671
2746
  }).then((code) => {
2672
2747
  process.exitCode = code;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as InspectOptions, $n as verifyPassword, $t as DataValidationOperator, A as toJSON, An as Hyperlink, At as Workbook, B as FormulaResult, Bn as PrintErrors, Bt as CfValue, C as TableRow, Cn as ImageAnchorInput, Ct as Sheet, D as fromJSON, Dn as SheetImage, Dt as SheetState, E as WriteTableOptions, En as ImagePositionInput, Et as SheetProperties, F as CellInput, Fn as PageOrder, Ft as TableDefinitionColumn, G as SheetPropertiesOptions, Gn as SheetProtectionOptions, Gt as ConditionalFormatRule, H as NewSheet, Hn as PrintTitles, Ht as CfValueType, I as ColumnOptions, In as PageOrientation, It as TableInput, J as WriteWorkbookOptions, Jn as HashPasswordOptions, Jt as DataBarAxisPosition, K as SheetViewOptions, Kn as WorkbookProtection, Kt as ConditionalFormatRuleInput, L as CreateWorkbookOptions, Ln as PageSetup, Lt as TableStyleOptions, M as StandardSchemaV1, Mn as HeaderFooter, Mt as WorkbookView, N as AddSheetOptions, Nn as PageBreaks, Nt as TableColumnInput, O as readTable, On as WorkbookImage, Ot as SheetView, P as CalculationOptions, Pn as PageMargins, Pt as TableDefinition, Q as InspectDefinedName, Qn as legacyPasswordHash, Qt as DataValidationImeMode, R as ERROR_VALUES, Rn as PageSetupOptions, Rt as TotalsRowFunction, S as TableResult, Sn as ImageAnchor, St as RowInfo, T as ToJSONOptions, Tn as ImageOptions, Tt as SheetLayout, U as NewWorkbook, Un as SheetProtection, Ut as ConditionalFormat, V as FreezeOptions, Vn as PrintOptions, Vt as CfValueInput, W as RowOptions, Wn as SheetProtectionFlags, Wt as ConditionalFormatOperator, X as writeWorkbook, Xn as PasswordVerifier, Xt as DataValidation, Y as createWorkbook, Yn as PasswordHash, Yt as DataBarDirection, Z as InspectColumn, Zn as hashPassword, Zt as DataValidationErrorStyle, _ as JsonTable, _n as ReadingOrder, _r as DefinedNameOptions, _t as DateSystem, a as WriteWorkbookStreamOptions, an as BorderEdge, ar as XlvDetails, at as ReadOptions, b as TableColumnSpec, bn as VerticalAlignment, bt as FrozenPanes, c as OpenWorkbookStreamOptions, cn as CellStyle, cr as XlvErrorInit, ct as NoteBox, d as StreamRow, dn as FontScheme, dr as XlvWarning, dt as NoteMargins, en as DataValidationRule, er as ShaAlgorithm, et as InspectReport, f as StreamSheetInfo, fn as FontStyle, fr as XlvWarningCode, ft as Cell, g as readTableStream, gn as ProtectionStyle, gr as DefinedName, gt as Conformance, h as openWorkbookStream, hn as PatternType, hr as ReadLimits, ht as ColumnInfo, i as WriteTableStreamOptions, in as AlignmentStyle, ir as XlvDetailValue, it as inspect, j as writeTable, jn as HyperlinkTarget, jt as WorkbookFormat, k as readTableAsync, kn as imageFormat, kt as SplitPanes, l as ReadTableStreamOptions, ln as Color, lr as XlvErrorJSON, lt as NoteBoxInput, m as WorkbookStream, mn as HorizontalAlignment, mr as DEFAULT_READ_LIMITS, mt as CellValue, n as StreamRowInput, nn as IconSetType, nr as ERROR_CODES, nt as InspectTypeCounts, o as writeTableStream, on as BorderLineStyle, or as XlvError, ot as readWorkbook, p as TableStreamItem, pn as GradientFill, pr as isXlvError, pt as CellType, q as WorkbookViewOptions, qn as WorkbookProtectionOptions, qt as ConditionalFormatType, r as StreamSheetSpec, rn as TimePeriod, rr as WARNING_CODES, rt as InspectValue, s as writeWorkbookStream, sn as BorderStyle, sr as XlvErrorCode, st as Note, t as StreamDefinedName, tn as DataValidationType, tr as WorkbookProperties, tt as InspectSheet, u as STREAM_LIMIT_DEFAULTS, un as FillStyle, ur as XlvLocation, ut as NoteInput, v as ReadTableOptions, vn as UnderlineStyle, vt as Formula, w as TableValue, wn as ImageFormat, wt as SheetKind, x as TableIssue, xn as AnchorMarker, xt as RichTextRun, y as TableColumn, yn as VerticalAlignRun, yt as FormulaKind, z as ErrorValue, zn as PrintCellComments, zt as CfIcon } from "./stream-write-CaGFWPhB.js";
1
+ import { $ as InspectOptions, $n as verifyPassword, $t as DataValidationOperator, A as toJSON, An as Hyperlink, At as Workbook, B as FormulaResult, Bn as PrintErrors, Bt as CfValue, C as TableRow, Cn as ImageAnchorInput, Ct as Sheet, D as fromJSON, Dn as SheetImage, Dt as SheetState, E as WriteTableOptions, En as ImagePositionInput, Et as SheetProperties, F as CellInput, Fn as PageOrder, Ft as TableDefinitionColumn, G as SheetPropertiesOptions, Gn as SheetProtectionOptions, Gt as ConditionalFormatRule, H as NewSheet, Hn as PrintTitles, Ht as CfValueType, I as ColumnOptions, In as PageOrientation, It as TableInput, J as WriteWorkbookOptions, Jn as HashPasswordOptions, Jt as DataBarAxisPosition, K as SheetViewOptions, Kn as WorkbookProtection, Kt as ConditionalFormatRuleInput, L as CreateWorkbookOptions, Ln as PageSetup, Lt as TableStyleOptions, M as StandardSchemaV1, Mn as HeaderFooter, Mt as WorkbookView, N as AddSheetOptions, Nn as PageBreaks, Nt as TableColumnInput, O as readTable, On as WorkbookImage, Ot as SheetView, P as CalculationOptions, Pn as PageMargins, Pt as TableDefinition, Q as InspectDefinedName, Qn as legacyPasswordHash, Qt as DataValidationImeMode, R as ERROR_VALUES, Rn as PageSetupOptions, Rt as TotalsRowFunction, S as TableResult, Sn as ImageAnchor, St as RowInfo, T as ToJSONOptions, Tn as ImageOptions, Tt as SheetLayout, U as NewWorkbook, Un as SheetProtection, Ut as ConditionalFormat, V as FreezeOptions, Vn as PrintOptions, Vt as CfValueInput, W as RowOptions, Wn as SheetProtectionFlags, Wt as ConditionalFormatOperator, X as writeWorkbook, Xn as PasswordVerifier, Xt as DataValidation, Y as createWorkbook, Yn as PasswordHash, Yt as DataBarDirection, Z as InspectColumn, Zn as hashPassword, Zt as DataValidationErrorStyle, _ as JsonTable, _n as ReadingOrder, _r as DefinedNameOptions, _t as DateSystem, a as WriteWorkbookStreamOptions, an as BorderEdge, ar as XlvDetails, at as ReadOptions, b as TableColumnSpec, bn as VerticalAlignment, bt as FrozenPanes, c as OpenWorkbookStreamOptions, cn as CellStyle, cr as XlvErrorInit, ct as NoteBox, d as StreamRow, dn as FontScheme, dr as XlvWarning, dt as NoteMargins, en as DataValidationRule, er as ShaAlgorithm, et as InspectReport, f as StreamSheetInfo, fn as FontStyle, fr as XlvWarningCode, ft as Cell, g as readTableStream, gn as ProtectionStyle, gr as DefinedName, gt as Conformance, h as openWorkbookStream, hn as PatternType, hr as ReadLimits, ht as ColumnInfo, i as WriteTableStreamOptions, in as AlignmentStyle, ir as XlvDetailValue, it as inspect, j as writeTable, jn as HyperlinkTarget, jt as WorkbookFormat, k as readTableAsync, kn as imageFormat, kt as SplitPanes, l as ReadTableStreamOptions, ln as Color, lr as XlvErrorJSON, lt as NoteBoxInput, m as WorkbookStream, mn as HorizontalAlignment, mr as DEFAULT_READ_LIMITS, mt as CellValue, n as StreamRowInput, nn as IconSetType, nr as ERROR_CODES, nt as InspectTypeCounts, o as writeTableStream, on as BorderLineStyle, or as XlvError, ot as readWorkbook, p as TableStreamItem, pn as GradientFill, pr as isXlvError, pt as CellType, q as WorkbookViewOptions, qn as WorkbookProtectionOptions, qt as ConditionalFormatType, r as StreamSheetSpec, rn as TimePeriod, rr as WARNING_CODES, rt as InspectValue, s as writeWorkbookStream, sn as BorderStyle, sr as XlvErrorCode, st as Note, t as StreamDefinedName, tn as DataValidationType, tr as WorkbookProperties, tt as InspectSheet, u as STREAM_LIMIT_DEFAULTS, un as FillStyle, ur as XlvLocation, ut as NoteInput, v as ReadTableOptions, vn as UnderlineStyle, vt as Formula, w as TableValue, wn as ImageFormat, wt as SheetKind, x as TableIssue, xn as AnchorMarker, xt as RichTextRun, y as TableColumn, yn as VerticalAlignRun, yt as FormulaKind, z as ErrorValue, zn as PrintCellComments, zt as CfIcon } from "./stream-write-BVaFkgwO.js";
2
2
  /**
3
3
  * Options for {@link toCSV}.
4
4
  *
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Dn as WARNING_CODES, En as ERROR_CODES, Gt as hashPassword, Kt as legacyPasswordHash, On as XlvError, Qt as imageFormat, Rt as DEFAULT_READ_LIMITS, b as readWorkbook, c as NewSheet, f as createWorkbook, g as inspect, kn as isXlvError, l as NewWorkbook, m as writeWorkbook, qt as verifyPassword, s as ERROR_VALUES, z as shiftFormula } from "./options-Ba6r4zP1.js";
2
- import { a as appendRows, c as fromCSV, d as fromJSON, g as writeTable, h as toJSON, i as adjustRange, m as readTableAsync, n as insertRows, o as editCells, p as readTable, r as adjustFormula, s as diff, t as deleteRows, u as toCSV } from "./rows-Biu_ddwz.js";
3
- import { a as readTableStream, i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS, t as writeTableStream } from "./stream-write-CtWyTd44.js";
1
+ import { Dn as WARNING_CODES, En as ERROR_CODES, Gt as hashPassword, Kt as legacyPasswordHash, On as XlvError, Qt as imageFormat, Rt as DEFAULT_READ_LIMITS, b as readWorkbook, c as NewSheet, f as createWorkbook, g as inspect, kn as isXlvError, l as NewWorkbook, m as writeWorkbook, qt as verifyPassword, s as ERROR_VALUES, z as shiftFormula } from "./options-Ba1iWD-Z.js";
2
+ import { a as appendRows, c as fromCSV, d as fromJSON, g as writeTable, h as toJSON, i as adjustRange, m as readTableAsync, n as insertRows, o as editCells, p as readTable, r as adjustFormula, s as diff, t as deleteRows, u as toCSV } from "./rows-IWKIxHt9.js";
3
+ import { a as readTableStream, i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS, t as writeTableStream } from "./stream-write-BGuUjlXo.js";
4
4
  export { DEFAULT_READ_LIMITS, ERROR_CODES, ERROR_VALUES, NewSheet, NewWorkbook, STREAM_LIMIT_DEFAULTS, WARNING_CODES, XlvError, adjustFormula, adjustRange, appendRows, createWorkbook, deleteRows, diff, editCells, fromCSV, fromJSON, hashPassword, imageFormat, insertRows, inspect, isXlvError, legacyPasswordHash, openWorkbookStream, readTable, readTableAsync, readTableStream, readWorkbook, shiftFormula, toCSV, toJSON, verifyPassword, writeTable, writeTableStream, writeWorkbook, writeWorkbookStream };
@@ -1,4 +1,4 @@
1
- import { Bt as resolveLimits, On as XlvError } from "./options-Ba6r4zP1.js";
1
+ import { Bt as resolveLimits, On as XlvError } from "./options-Ba1iWD-Z.js";
2
2
  import { readFile, stat } from "node:fs/promises";
3
3
  // src/util/node-files.ts
4
4
  /** The path as shown in messages. */
package/dist/node.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as InspectOptions, At as Workbook, J as WriteWorkbookOptions, U as NewWorkbook, a as WriteWorkbookStreamOptions, at as ReadOptions, c as OpenWorkbookStreamOptions, et as InspectReport, m as WorkbookStream } from "./stream-write-CaGFWPhB.js";
1
+ import { $ as InspectOptions, At as Workbook, J as WriteWorkbookOptions, U as NewWorkbook, a as WriteWorkbookStreamOptions, at as ReadOptions, c as OpenWorkbookStreamOptions, et as InspectReport, m as WorkbookStream } from "./stream-write-BVaFkgwO.js";
2
2
  /**
3
3
  * Reads an XLSX file from disk. Node.js only; in other runtimes pass the bytes to
4
4
  * `readWorkbook` from `xlvane`. The file size is checked against `limits.maxInputBytes`
package/dist/node.js CHANGED
@@ -1,6 +1,6 @@
1
- import { Bt as resolveLimits, On as XlvError, b as readWorkbook, g as inspect, m as writeWorkbook } from "./options-Ba6r4zP1.js";
2
- import { i as readInput, n as describePath, r as fileError, t as checkFile } from "./node-files-CsQVpKgP.js";
3
- import { i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS } from "./stream-write-CtWyTd44.js";
1
+ import { Bt as resolveLimits, On as XlvError, b as readWorkbook, g as inspect, m as writeWorkbook } from "./options-Ba1iWD-Z.js";
2
+ import { i as readInput, n as describePath, r as fileError, t as checkFile } from "./node-files-CDb6TyZb.js";
3
+ import { i as openWorkbookStream, n as writeWorkbookStream, r as STREAM_LIMIT_DEFAULTS } from "./stream-write-BGuUjlXo.js";
4
4
  import { openAsBlob } from "node:fs";
5
5
  import { open, unlink, writeFile } from "node:fs/promises";
6
6
  // src/node.ts
@@ -50,7 +50,9 @@ const ERROR_CODES = [
50
50
  "XLV_E_CSV_MALFORMED",
51
51
  "XLV_E_NOT_SUPPORTED",
52
52
  "XLV_E_USAGE",
53
- "XLV_E_INTERNAL"
53
+ "XLV_E_NOT_INSTALLED",
54
+ "XLV_E_INTERNAL",
55
+ "XLV_E_PATH_NOT_ALLOWED"
54
56
  ];
55
57
  /**
56
58
  * Every warning code xlvane can report. Warnings never stop reading; they describe something
@@ -521,7 +523,7 @@ var Parser = class {
521
523
  const dashes = s.indexOf("--", Math.max(at + 4, this.tokenFrom));
522
524
  done = dashes !== -1 && dashes + 2 < length;
523
525
  if (!done) {
524
- this.tokenFrom = Math.max(at + 4, length - 1);
526
+ this.tokenFrom = dashes !== -1 ? dashes : Math.max(at + 4, length - 1);
525
527
  if (length - (at + 4) > this.options.limits.maxXmlTextLength + 2) this.limit("maxXmlTextLength", COMMENT_TOO_LONG, at);
526
528
  }
527
529
  } else if (length - at < 9) done = false;
@@ -1,4 +1,4 @@
1
- import { $ as fillXml, At as EMPTY_STYLES, B as tokenize, Bt as resolveLimits, Cn as encodeXstring, Ct as relationshipsPartName, Ft as normalizeStyle, G as DEFAULT_FONT, H as X14_DV_URI, I as WarningCollector, It as stableKey, J as borderXml, Lt as isDateFormat, M as openZip, Mt as READING_ORDERS, Nt as checkStyleCount, On as XlvError, Pt as mergeStyles, Rt as DEFAULT_READ_LIMITS, Sn as parseXml, St as openPackage, Tn as escapeText, Tt as zipNameToPartName, V as X14_CF_URI, Vt as suggest, _ as isoDate, _n as childrenNamed, an as MAX_COLUMNS, at as reusableBuiltinNumFmt, b as readWorkbook, bn as decodeXml, bt as parseIsoDateTime, cn as formatCellRef, dn as parseRange, et as fontXml, f as createWorkbook, ft as stringItemXml, gn as childNamed, h as detectHeader, i as readOptions, in as relationshipTypes, jt as parseStyles, ln as formatRange, m as writeWorkbook, mt as textElement, n as oneOfOption, nn as SML_NS, on as MAX_ROWS, q as attr, r as openInput, rn as classifyRelationship, sn as columnLetters, t as booleanOption, tn as REL_NS, tt as formatNumber, un as parseCellRef, vn as parseXmlTree, vt as writeZip, wn as escapeAttr, wt as partKey, x as toBytes, xn as normalizeLineEnds, xt as parseSharedStrings, z as shiftFormula, zt as checkOutputPositions } from "./options-Ba6r4zP1.js";
1
+ import { $ as fillXml, At as EMPTY_STYLES, B as tokenize, Bt as resolveLimits, Cn as encodeXstring, Ct as relationshipsPartName, Ft as normalizeStyle, G as DEFAULT_FONT, H as X14_DV_URI, I as WarningCollector, It as stableKey, J as borderXml, Lt as isDateFormat, M as openZip, Mt as READING_ORDERS, Nt as checkStyleCount, On as XlvError, Pt as mergeStyles, Rt as DEFAULT_READ_LIMITS, Sn as parseXml, St as openPackage, Tn as escapeText, Tt as zipNameToPartName, V as X14_CF_URI, Vt as suggest, _ as isoDate, _n as childrenNamed, an as MAX_COLUMNS, at as reusableBuiltinNumFmt, b as readWorkbook, bn as decodeXml, bt as parseIsoDateTime, cn as formatCellRef, dn as parseRange, et as fontXml, f as createWorkbook, ft as stringItemXml, gn as childNamed, h as detectHeader, i as readOptions, in as relationshipTypes, jt as parseStyles, ln as formatRange, m as writeWorkbook, mt as textElement, n as oneOfOption, nn as SML_NS, on as MAX_ROWS, q as attr, r as openInput, rn as classifyRelationship, sn as columnLetters, t as booleanOption, tn as REL_NS, tt as formatNumber, un as parseCellRef, vn as parseXmlTree, vt as writeZip, wn as escapeAttr, wt as partKey, x as toBytes, xn as normalizeLineEnds, xt as parseSharedStrings, z as shiftFormula, zt as checkOutputPositions } from "./options-Ba1iWD-Z.js";
2
2
  // src/table.ts
3
3
  const READ_OPTIONS = [
4
4
  "sheet",
@@ -1,4 +1,4 @@
1
- import { $t as metricsOf, A as limitExceeded, Bt as resolveLimits, C as Bytes, D as TAIL_BYTES, Dt as normalizeTable, E as NotLoaded, Et as TABLE_CONTENT_TYPE, F as validateLocalHeaders, Ft as normalizeStyle, Ht as printNames, I as WarningCollector, Jt as DRAWING_CONTENT_TYPE, K as SheetRels, L as sheetNotFound, N as readCentralDirectory, O as checkSource$1, On as XlvError, Ot as checkDefinedName, P as unsupported, Q as createSharedStrings, R as createWorksheetParser, Rt as DEFAULT_READ_LIMITS, S as workbookPartsToLoad, St as openPackage, T as HEAD_BYTES, Ut as printXml, Wt as sheetProtectionXml, X as cellXml, Xt as MediaParts, Y as buildStyles, Yt as IMAGE_CONTENT_TYPES, Z as contentTypesXml, Zt as drawingParts, _ as isoDate, _t as FormulaGroups, a as DATE_FORMAT, an as MAX_COLUMNS, cn as formatCellRef, ct as sheetHead, d as convertCellInput, dt as sheetTail, en as resolveImage, f as createWorkbook, fn as APP_PROPERTIES_PART, gt as workbookXml, h as detectHeader, hn as corePropertiesXml, ht as workbookRelsXml, i as readOptions, it as noteParts, j as locateCentralDirectory, k as corrupt, kt as checkUniqueName, lt as sheetRelsPartName, mn as appPropertiesXml, n as oneOfOption, nt as hyperlinksXml, o as DATE_TIME_FORMAT, on as MAX_ROWS, ot as rootRelsXml, p as sortedNotes, pn as CORE_PROPERTIES_PART, pt as tableParts, rn as classifyRelationship, rt as nameTitles, sn as columnLetters, st as rowStart, u as checkBookViews, ut as sheetRulesXml, v as analyzeWorkbook, w as CORRUPT_HINT, wt as partKey, y as readNotes, yn as createXmlByteStreamParser, yt as crc32, zt as checkOutputPositions } from "./options-Ba6r4zP1.js";
1
+ import { $t as metricsOf, A as limitExceeded, Bt as resolveLimits, C as Bytes, D as TAIL_BYTES, Dt as normalizeTable, E as NotLoaded, Et as TABLE_CONTENT_TYPE, F as validateLocalHeaders, Ft as normalizeStyle, Ht as printNames, I as WarningCollector, Jt as DRAWING_CONTENT_TYPE, K as SheetRels, L as sheetNotFound, N as readCentralDirectory, O as checkSource$1, On as XlvError, Ot as checkDefinedName, P as unsupported, Q as createSharedStrings, R as createWorksheetParser, Rt as DEFAULT_READ_LIMITS, S as workbookPartsToLoad, St as openPackage, T as HEAD_BYTES, Ut as printXml, Wt as sheetProtectionXml, X as cellXml, Xt as MediaParts, Y as buildStyles, Yt as IMAGE_CONTENT_TYPES, Z as contentTypesXml, Zt as drawingParts, _ as isoDate, _t as FormulaGroups, a as DATE_FORMAT, an as MAX_COLUMNS, cn as formatCellRef, ct as sheetHead, d as convertCellInput, dt as sheetTail, en as resolveImage, f as createWorkbook, fn as APP_PROPERTIES_PART, gt as workbookXml, h as detectHeader, hn as corePropertiesXml, ht as workbookRelsXml, i as readOptions, it as noteParts, j as locateCentralDirectory, k as corrupt, kt as checkUniqueName, lt as sheetRelsPartName, mn as appPropertiesXml, n as oneOfOption, nt as hyperlinksXml, o as DATE_TIME_FORMAT, on as MAX_ROWS, ot as rootRelsXml, p as sortedNotes, pn as CORE_PROPERTIES_PART, pt as tableParts, rn as classifyRelationship, rt as nameTitles, sn as columnLetters, st as rowStart, u as checkBookViews, ut as sheetRulesXml, v as analyzeWorkbook, w as CORRUPT_HINT, wt as partKey, y as readNotes, yn as createXmlByteStreamParser, yt as crc32, zt as checkOutputPositions } from "./options-Ba1iWD-Z.js";
2
2
  import { Deflate, Inflate } from "fflate";
3
3
  // src/zip/stream.ts
4
4
  /**
@@ -112,7 +112,7 @@ declare const DEFAULT_READ_LIMITS: Readonly<ReadLimits>;
112
112
  * console.log(ERROR_CODES.includes('XLV_E_SHEET_NOT_FOUND')); // true
113
113
  * ```
114
114
  */
115
- declare const ERROR_CODES: readonly ["XLV_E_INVALID_INPUT", "XLV_E_INVALID_OPTION", "XLV_E_INVALID_ARGUMENT", "XLV_E_LIMIT_EXCEEDED", "XLV_E_NOT_ZIP", "XLV_E_UNSUPPORTED_CONTAINER", "XLV_E_ZIP_CORRUPT", "XLV_E_ZIP_UNSUPPORTED", "XLV_E_XML_MALFORMED", "XLV_E_XML_DTD_FORBIDDEN", "XLV_E_XML_ENTITY_FORBIDDEN", "XLV_E_XML_ENCODING", "XLV_E_PART_MISSING", "XLV_E_PART_INVALID", "XLV_E_INVALID_CELL_REF", "XLV_E_SHEET_NOT_FOUND", "XLV_E_TABLE_NOT_FOUND", "XLV_E_FILE_READ", "XLV_E_INVALID_VALUE", "XLV_E_INVALID_STYLE", "XLV_E_INVALID_SHEET_NAME", "XLV_E_DUPLICATE_SHEET_NAME", "XLV_E_INVALID_DEFINED_NAME", "XLV_E_INVALID_HYPERLINK", "XLV_E_INVALID_TABLE", "XLV_E_INVALID_IMAGE", "XLV_E_OVERLAPPING_MERGE", "XLV_E_FILE_EXISTS", "XLV_E_FILE_WRITE", "XLV_E_HEADER_NOT_FOUND", "XLV_E_SCHEMA_INVALID", "XLV_E_ASYNC_SCHEMA", "XLV_E_INVALID_ROWS", "XLV_E_JSON_INVALID", "XLV_E_CSV_MALFORMED", "XLV_E_NOT_SUPPORTED", "XLV_E_USAGE", "XLV_E_INTERNAL"];
115
+ declare const ERROR_CODES: readonly ["XLV_E_INVALID_INPUT", "XLV_E_INVALID_OPTION", "XLV_E_INVALID_ARGUMENT", "XLV_E_LIMIT_EXCEEDED", "XLV_E_NOT_ZIP", "XLV_E_UNSUPPORTED_CONTAINER", "XLV_E_ZIP_CORRUPT", "XLV_E_ZIP_UNSUPPORTED", "XLV_E_XML_MALFORMED", "XLV_E_XML_DTD_FORBIDDEN", "XLV_E_XML_ENTITY_FORBIDDEN", "XLV_E_XML_ENCODING", "XLV_E_PART_MISSING", "XLV_E_PART_INVALID", "XLV_E_INVALID_CELL_REF", "XLV_E_SHEET_NOT_FOUND", "XLV_E_TABLE_NOT_FOUND", "XLV_E_FILE_READ", "XLV_E_INVALID_VALUE", "XLV_E_INVALID_STYLE", "XLV_E_INVALID_SHEET_NAME", "XLV_E_DUPLICATE_SHEET_NAME", "XLV_E_INVALID_DEFINED_NAME", "XLV_E_INVALID_HYPERLINK", "XLV_E_INVALID_TABLE", "XLV_E_INVALID_IMAGE", "XLV_E_OVERLAPPING_MERGE", "XLV_E_FILE_EXISTS", "XLV_E_FILE_WRITE", "XLV_E_HEADER_NOT_FOUND", "XLV_E_SCHEMA_INVALID", "XLV_E_ASYNC_SCHEMA", "XLV_E_INVALID_ROWS", "XLV_E_JSON_INVALID", "XLV_E_CSV_MALFORMED", "XLV_E_NOT_SUPPORTED", "XLV_E_USAGE", "XLV_E_NOT_INSTALLED", "XLV_E_INTERNAL", "XLV_E_PATH_NOT_ALLOWED"];
116
116
  /**
117
117
  * Every warning code xlvane can report. Warnings never stop reading; they describe something
118
118
  * in the file that the caller may want to know about. Each one is described in docs/errors.md.
@@ -0,0 +1,43 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "mcp.schema.json",
4
+ "title": "xlvane mcp --json (errors only; the server itself speaks MCP)",
5
+ "oneOf": [
6
+ {
7
+ "type": "object",
8
+ "properties": {
9
+ "xlvane": {
10
+ "const": 1
11
+ },
12
+ "command": {
13
+ "const": "mcp"
14
+ },
15
+ "ok": {
16
+ "const": true
17
+ },
18
+ "result": {
19
+ "type": "object",
20
+ "properties": {
21
+ "exitCode": {
22
+ "type": "integer"
23
+ }
24
+ },
25
+ "required": [
26
+ "exitCode"
27
+ ],
28
+ "additionalProperties": false
29
+ }
30
+ },
31
+ "required": [
32
+ "xlvane",
33
+ "command",
34
+ "ok",
35
+ "result"
36
+ ],
37
+ "additionalProperties": false
38
+ },
39
+ {
40
+ "$ref": "common.schema.json#/$defs/errorEnvelope"
41
+ }
42
+ ]
43
+ }
package/docs/cli-json.md CHANGED
@@ -53,7 +53,7 @@ The error envelope is defined in [cli-json/common.schema.json](cli-json/common.s
53
53
  | Code | Meaning |
54
54
  |---|---|
55
55
  | 0 | Success. |
56
- | 1 | The command ran, and a check found something: `diff` found differences, or `validate` found problems. |
56
+ | 1 | The command ran, and a check found something: `diff` found differences, or `validate` found problems. `mcp` returns the exit code of the server (0, or 2 and 3 as below). |
57
57
  | 2 | Usage error (`XLV_E_USAGE`): unknown command or option, missing or extra argument, invalid option value. |
58
58
  | 3 | Input or file error: the file cannot be read, is not a valid workbook, the sheet does not exist, the output exists without `--force`, and so on. |
59
59
 
@@ -69,3 +69,4 @@ The error envelope is defined in [cli-json/common.schema.json](cli-json/common.s
69
69
  | `diff` | [cli-json/diff.schema.json](cli-json/diff.schema.json) | The `diff()` result: `equal`, `sheetsAdded`, `sheetsRemoved`, `sheets` (cell changes with `before` and `after`), `summary`. Every change is included. |
70
70
  | `validate` | [cli-json/validate.schema.json](cli-json/validate.schema.json) | `file`, `ok`, `sheet`, `rowsChecked`, `problems` (`kind`, `column`, `cell`, `row`, `message`), `warnings`. |
71
71
  | `migrate` | [cli-json/migrate.schema.json](cli-json/migrate.schema.json) | `directory`, `packageJson`, `changes` (`section`, `from`, `to`), `alreadyMigrated`, `enginesNode`, `filesScanned`, `scanLimited`, `findings` (`file`, `line`, `column`, `api`, `status`), `written`. |
72
+ | `mcp` | [cli-json/mcp.schema.json](cli-json/mcp.schema.json) | `--json` is refused with a usage error (exit code 2), printed as this document, because stdout carries the MCP protocol. |
package/docs/errors.md CHANGED
@@ -97,6 +97,8 @@ Some limits also bound work derived from a small file (1.1.1, D-H01):
97
97
  - `maxXmlTextLength`: also the length of an XML comment or processing instruction.
98
98
  - `maxSharedStringChars`: also the text of shared formulas, counted apart from shared strings: the length of each sharing cell's formula, as moved to that cell.
99
99
 
100
+ The MCP server (`@xlvane/mcp`) returns it as a tool error for a file larger than `--max-file-size` (`details.limit` `maxFileBytes`) and for a result longer than `--max-response-chars` (`details.limit` `maxResponseChars`; `read_table` instead returns the rows that fit).
101
+
100
102
  `fromCSV` (and `xlvane convert`/`create` with CSV input) throws it for text with more fields than `maxCells` (default 5 000 000, `details.limit` `maxCells`), more than 16 384 fields on a line or more than 1 048 576 lines.
101
103
 
102
104
  `NewSheet.validate` throws it when a sheet would get more than 65534 data validations ([MS-OI29500] §2.1.614 g; `details.limit` `dataValidations`). When reading, the conditional formatting and data validations of one sheet count against `maxXmlTreeElements`.
@@ -272,10 +274,18 @@ For `insertRows`/`deleteRows`, insert or delete the rows in a spreadsheet applic
272
274
  The `xlvane` command line was used incorrectly: an unknown command or option, a missing or extra argument, an option without its value, or an option value that is not allowed. `details` names the command and the option or argument; `details.suggestions` lists close matches ("Did you mean ...?"). Exit code 2.
273
275
  **Fix:** run `xlvane help <command>` for the usage and examples of the command.
274
276
 
277
+ ### XLV_E_NOT_INSTALLED
278
+ `xlvane mcp` needs the separate package `@xlvane/mcp`, which could not be loaded. `details.package` names it.
279
+ **Fix:** install it next to xlvane, for example `npm install @xlvane/mcp`.
280
+
275
281
  ### XLV_E_INTERNAL
276
282
  The `xlvane` command line caught an error that is not an `XlvError`. This is a bug in xlvane. `details.name` is the error's name; `--verbose` prints the stack trace.
277
283
  **Fix:** report it with the command and, if possible, the input file (see SECURITY.md for files that must stay private).
278
284
 
285
+ ### XLV_E_PATH_NOT_ALLOWED
286
+ The MCP server (`@xlvane/mcp`) was asked to read or write a path outside the directories it was started with (`--root`), including paths that leave them through `..` or a symbolic link, or to write through a symbolic link. Nothing was read or written. `details.path` is the path as given and `details.roots` lists the allowed directories.
287
+ **Fix:** use a path inside one of the listed directories, or restart the server with another `--root`.
288
+
279
289
  ## Warnings
280
290
 
281
291
  ### XLV_W_DIMENSION_MISMATCH
package/llms-full.txt CHANGED
@@ -1,4 +1,4 @@
1
- # xlvane 1.1.1: documentation in one file
1
+ # xlvane 1.2.1: documentation in one file
2
2
 
3
3
  This file joins the README of the xlvane package, the Agent Skill and the documentation in docs/. It is generated by scripts/package-docs.mjs; the separate files are in the same package.
4
4
 
@@ -64,7 +64,7 @@ xlvane help edit # usage and examples of one command
64
64
  - `--json` prints one JSON document per command with a documented schema ([docs/cli-json.md](https://github.com/DevXord/xlvane/blob/main/docs/cli-json.md)). Exit codes: 0 success, 1 a check found something (`diff`, `validate`), 2 usage error, 3 input or file error.
65
65
  - Colour (red errors, yellow warnings, green results, bold headings) is used only on a terminal and never carries information alone; `NO_COLOR` or `TERM=dumb` turn it off, `FORCE_COLOR=1` turns it on. Control characters from files, such as an escape character in a cell, are shown as `\x1b` and never reach the terminal.
66
66
  - Tables and summaries go to separate streams: `xlvane read report.xlsx > out.txt` writes only the table; the row count and warnings notes go to stderr.
67
- - `xlvane migrate` prepares a project for `@xlvane/compat`.
67
+ - `xlvane migrate` prepares a project for `@xlvane/compat`, and `xlvane mcp` starts the MCP server from `@xlvane/mcp` (a separate package; [its README](https://github.com/DevXord/xlvane/blob/main/packages/mcp/README.md)).
68
68
 
69
69
  ## Reading a workbook
70
70
 
@@ -420,21 +420,22 @@ License: MIT
420
420
 
421
421
  ---
422
422
  name: xlvane
423
- description: Read, inspect, write, edit, convert, compare and validate Excel XLSX files with the xlvane library or its xlvane command line. Use when a task involves .xlsx files, sheets turned into JSON or CSV, spreadsheet reports, or checking changes to a workbook.
423
+ description: Read, inspect, write, edit, convert, compare and validate Excel XLSX files with the xlvane library, its xlvane command line or its MCP server. Use when a task involves .xlsx files, sheets turned into JSON or CSV, spreadsheet reports, or checking changes to a workbook.
424
424
  license: MIT
425
- compatibility: Node.js 22 or later. The library core works on Uint8Array and has no Node.js dependencies; the CLI and the file helpers in xlvane/node need Node.js.
425
+ compatibility: Node.js 22 or later. The library core works on Uint8Array and has no Node.js dependencies; the CLI, the file helpers in xlvane/node and the MCP server need Node.js.
426
426
  ---
427
427
 
428
428
  # xlvane: XLSX files
429
429
 
430
430
  xlvane reads, writes and edits `.xlsx` files. It treats input files as untrusted (size and ZIP limits, no external entities, macros are never run, links are never followed). It does not calculate formulas: it reads the cached results stored in the file and writes the formula text you give.
431
431
 
432
- Two ways to use it, with the same behaviour:
432
+ Three ways to use it, with the same behaviour:
433
433
 
434
434
  | Way | When | Start |
435
435
  |---|---|---|
436
436
  | Library `xlvane` | You write JavaScript or TypeScript code | `npm install xlvane` |
437
437
  | Command line `xlvane` | You run shell commands | `npx xlvane help` |
438
+ | MCP server `@xlvane/mcp` | Your client calls MCP tools | `npx @xlvane/mcp --root <dir>` |
438
439
 
439
440
  ## Recommended order of work
440
441
 
@@ -610,6 +611,10 @@ xlvane validate report.xlsx --columns "Region:string,Revenue:number"
610
611
 
611
612
  Add `--json` to any command for one JSON document with a documented schema (`docs/cli-json.md` in the package). Exit codes: 0 success, 1 a check found something, 2 usage error, 3 input or file error. Nothing is overwritten without `--force`; commands that write accept `--dry-run`.
612
613
 
614
+ ## MCP server
615
+
616
+ `npx @xlvane/mcp --root ./data` serves the tools `inspect_workbook`, `read_table`, `diff` and `validate` for files inside `./data` only. With `--allow-write` it also serves `write_table`, `edit_cells` and `convert`; they create new files and replace an existing file only when the call passes `"overwrite": true`. Paths outside the roots, also through `..` or symbolic links, are refused with `XLV_E_PATH_NOT_ALLOWED`. A result is at most 1 Mi characters of JSON (`--max-response-chars`): `read_table` then returns the rows that fit, with `truncated: true` and `nextOffset` for the next call.
617
+
613
618
  ## Errors
614
619
 
615
620
  Every error is an `XlvError` with a stable `code` (`XLV_E_*`), a `location` (sheet, cell, part), a `hint` that says what to do, and `details` (for example the list of available sheets). Read the hint and correct the call; the codes are described in `docs/errors.md` in the package. Warnings (`XLV_W_*`) never stop reading; check `workbook.warnings` or `inspect(...).warnings`.
@@ -730,6 +735,8 @@ Some limits also bound work derived from a small file (1.1.1, D-H01):
730
735
  - `maxXmlTextLength`: also the length of an XML comment or processing instruction.
731
736
  - `maxSharedStringChars`: also the text of shared formulas, counted apart from shared strings: the length of each sharing cell's formula, as moved to that cell.
732
737
 
738
+ The MCP server (`@xlvane/mcp`) returns it as a tool error for a file larger than `--max-file-size` (`details.limit` `maxFileBytes`) and for a result longer than `--max-response-chars` (`details.limit` `maxResponseChars`; `read_table` instead returns the rows that fit).
739
+
733
740
  `fromCSV` (and `xlvane convert`/`create` with CSV input) throws it for text with more fields than `maxCells` (default 5 000 000, `details.limit` `maxCells`), more than 16 384 fields on a line or more than 1 048 576 lines.
734
741
 
735
742
  `NewSheet.validate` throws it when a sheet would get more than 65534 data validations ([MS-OI29500] §2.1.614 g; `details.limit` `dataValidations`). When reading, the conditional formatting and data validations of one sheet count against `maxXmlTreeElements`.
@@ -905,10 +912,18 @@ For `insertRows`/`deleteRows`, insert or delete the rows in a spreadsheet applic
905
912
  The `xlvane` command line was used incorrectly: an unknown command or option, a missing or extra argument, an option without its value, or an option value that is not allowed. `details` names the command and the option or argument; `details.suggestions` lists close matches ("Did you mean ...?"). Exit code 2.
906
913
  **Fix:** run `xlvane help <command>` for the usage and examples of the command.
907
914
 
915
+ ### XLV_E_NOT_INSTALLED
916
+ `xlvane mcp` needs the separate package `@xlvane/mcp`, which could not be loaded. `details.package` names it.
917
+ **Fix:** install it next to xlvane, for example `npm install @xlvane/mcp`.
918
+
908
919
  ### XLV_E_INTERNAL
909
920
  The `xlvane` command line caught an error that is not an `XlvError`. This is a bug in xlvane. `details.name` is the error's name; `--verbose` prints the stack trace.
910
921
  **Fix:** report it with the command and, if possible, the input file (see SECURITY.md for files that must stay private).
911
922
 
923
+ ### XLV_E_PATH_NOT_ALLOWED
924
+ The MCP server (`@xlvane/mcp`) was asked to read or write a path outside the directories it was started with (`--root`), including paths that leave them through `..` or a symbolic link, or to write through a symbolic link. Nothing was read or written. `details.path` is the path as given and `details.roots` lists the allowed directories.
925
+ **Fix:** use a path inside one of the listed directories, or restart the server with another `--root`.
926
+
912
927
  ## Warnings
913
928
 
914
929
  ### XLV_W_DIMENSION_MISMATCH
@@ -1202,7 +1217,7 @@ The error envelope is defined in [cli-json/common.schema.json](cli-json/common.s
1202
1217
  | Code | Meaning |
1203
1218
  |---|---|
1204
1219
  | 0 | Success. |
1205
- | 1 | The command ran, and a check found something: `diff` found differences, or `validate` found problems. |
1220
+ | 1 | The command ran, and a check found something: `diff` found differences, or `validate` found problems. `mcp` returns the exit code of the server (0, or 2 and 3 as below). |
1206
1221
  | 2 | Usage error (`XLV_E_USAGE`): unknown command or option, missing or extra argument, invalid option value. |
1207
1222
  | 3 | Input or file error: the file cannot be read, is not a valid workbook, the sheet does not exist, the output exists without `--force`, and so on. |
1208
1223
 
@@ -1218,6 +1233,7 @@ The error envelope is defined in [cli-json/common.schema.json](cli-json/common.s
1218
1233
  | `diff` | [cli-json/diff.schema.json](cli-json/diff.schema.json) | The `diff()` result: `equal`, `sheetsAdded`, `sheetsRemoved`, `sheets` (cell changes with `before` and `after`), `summary`. Every change is included. |
1219
1234
  | `validate` | [cli-json/validate.schema.json](cli-json/validate.schema.json) | `file`, `ok`, `sheet`, `rowsChecked`, `problems` (`kind`, `column`, `cell`, `row`, `message`), `warnings`. |
1220
1235
  | `migrate` | [cli-json/migrate.schema.json](cli-json/migrate.schema.json) | `directory`, `packageJson`, `changes` (`section`, `from`, `to`), `alreadyMigrated`, `enginesNode`, `filesScanned`, `scanLimited`, `findings` (`file`, `line`, `column`, `api`, `status`), `written`. |
1236
+ | `mcp` | [cli-json/mcp.schema.json](cli-json/mcp.schema.json) | `--json` is refused with a usage error (exit code 2), printed as this document, because stdout carries the MCP protocol. |
1221
1237
 
1222
1238
  <!-- file: docs/exceljs-compat.md -->
1223
1239
 
@@ -2655,6 +2671,52 @@ A workbook loaded with `xlsx.load()` is written again by `xlsx.writeBuffer()` (`
2655
2671
  ]
2656
2672
  }
2657
2673
 
2674
+ <!-- file: docs/cli-json/mcp.schema.json -->
2675
+
2676
+ {
2677
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
2678
+ "$id": "mcp.schema.json",
2679
+ "title": "xlvane mcp --json (errors only; the server itself speaks MCP)",
2680
+ "oneOf": [
2681
+ {
2682
+ "type": "object",
2683
+ "properties": {
2684
+ "xlvane": {
2685
+ "const": 1
2686
+ },
2687
+ "command": {
2688
+ "const": "mcp"
2689
+ },
2690
+ "ok": {
2691
+ "const": true
2692
+ },
2693
+ "result": {
2694
+ "type": "object",
2695
+ "properties": {
2696
+ "exitCode": {
2697
+ "type": "integer"
2698
+ }
2699
+ },
2700
+ "required": [
2701
+ "exitCode"
2702
+ ],
2703
+ "additionalProperties": false
2704
+ }
2705
+ },
2706
+ "required": [
2707
+ "xlvane",
2708
+ "command",
2709
+ "ok",
2710
+ "result"
2711
+ ],
2712
+ "additionalProperties": false
2713
+ },
2714
+ {
2715
+ "$ref": "common.schema.json#/$defs/errorEnvelope"
2716
+ }
2717
+ ]
2718
+ }
2719
+
2658
2720
  <!-- file: docs/cli-json/migrate.schema.json -->
2659
2721
 
2660
2722
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xlvane",
3
- "version": "1.1.1",
3
+ "version": "1.2.1",
4
4
  "description": "Read, inspect and write XLSX files; input is treated as untrusted. ESM only, one runtime dependency (fflate).",
5
5
  "keywords": [
6
6
  "xlsx",
@@ -1,20 +1,21 @@
1
1
  ---
2
2
  name: xlvane
3
- description: Read, inspect, write, edit, convert, compare and validate Excel XLSX files with the xlvane library or its xlvane command line. Use when a task involves .xlsx files, sheets turned into JSON or CSV, spreadsheet reports, or checking changes to a workbook.
3
+ description: Read, inspect, write, edit, convert, compare and validate Excel XLSX files with the xlvane library, its xlvane command line or its MCP server. Use when a task involves .xlsx files, sheets turned into JSON or CSV, spreadsheet reports, or checking changes to a workbook.
4
4
  license: MIT
5
- compatibility: Node.js 22 or later. The library core works on Uint8Array and has no Node.js dependencies; the CLI and the file helpers in xlvane/node need Node.js.
5
+ compatibility: Node.js 22 or later. The library core works on Uint8Array and has no Node.js dependencies; the CLI, the file helpers in xlvane/node and the MCP server need Node.js.
6
6
  ---
7
7
 
8
8
  # xlvane: XLSX files
9
9
 
10
10
  xlvane reads, writes and edits `.xlsx` files. It treats input files as untrusted (size and ZIP limits, no external entities, macros are never run, links are never followed). It does not calculate formulas: it reads the cached results stored in the file and writes the formula text you give.
11
11
 
12
- Two ways to use it, with the same behaviour:
12
+ Three ways to use it, with the same behaviour:
13
13
 
14
14
  | Way | When | Start |
15
15
  |---|---|---|
16
16
  | Library `xlvane` | You write JavaScript or TypeScript code | `npm install xlvane` |
17
17
  | Command line `xlvane` | You run shell commands | `npx xlvane help` |
18
+ | MCP server `@xlvane/mcp` | Your client calls MCP tools | `npx @xlvane/mcp --root <dir>` |
18
19
 
19
20
  ## Recommended order of work
20
21
 
@@ -190,6 +191,10 @@ xlvane validate report.xlsx --columns "Region:string,Revenue:number"
190
191
 
191
192
  Add `--json` to any command for one JSON document with a documented schema (`docs/cli-json.md` in the package). Exit codes: 0 success, 1 a check found something, 2 usage error, 3 input or file error. Nothing is overwritten without `--force`; commands that write accept `--dry-run`.
192
193
 
194
+ ## MCP server
195
+
196
+ `npx @xlvane/mcp --root ./data` serves the tools `inspect_workbook`, `read_table`, `diff` and `validate` for files inside `./data` only. With `--allow-write` it also serves `write_table`, `edit_cells` and `convert`; they create new files and replace an existing file only when the call passes `"overwrite": true`. Paths outside the roots, also through `..` or symbolic links, are refused with `XLV_E_PATH_NOT_ALLOWED`. A result is at most 1 Mi characters of JSON (`--max-response-chars`): `read_table` then returns the rows that fit, with `truncated: true` and `nextOffset` for the next call.
197
+
193
198
  ## Errors
194
199
 
195
200
  Every error is an `XlvError` with a stable `code` (`XLV_E_*`), a `location` (sheet, cell, part), a `hint` that says what to do, and `details` (for example the list of available sheets). Read the hint and correct the call; the codes are described in `docs/errors.md` in the package. Warnings (`XLV_W_*`) never stop reading; check `workbook.warnings` or `inspect(...).warnings`.