xlvane 1.1.0 → 1.2.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/llms-full.txt CHANGED
@@ -1,4 +1,4 @@
1
- # xlvane 1.1.0: documentation in one file
1
+ # xlvane 1.2.0: 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
 
@@ -391,10 +391,10 @@ Limits can be changed per call, for example `readWorkbook(bytes, { limits: { max
391
391
  | `maxXmlDepth` | 128 | deeply nested XML |
392
392
  | `maxXmlAttributes` | 256 | elements with huge numbers of attributes |
393
393
  | `maxXmlNameLength` | 1 024 | huge element or attribute names |
394
- | `maxXmlTextLength` | 8 Mi characters | huge text nodes or attribute values |
394
+ | `maxXmlTextLength` | 8 Mi characters | huge text nodes, attribute values, comments or processing instructions |
395
395
  | `maxXmlTreeElements` | 1 000 000 | huge workbook, styles or relationship parts (elements plus attributes) |
396
- | `maxCells` | 5 000 000 | workbooks too large to hold in memory (measured: about 180 bytes per numeric cell, Node.js 26) |
397
- | `maxSharedStringChars` | 512 Mi characters | many cells pointing at one huge shared string (a few MB that become many GB when values are copied) |
396
+ | `maxCells` | 5 000 000 | workbooks too large to hold in memory (measured: about 180 bytes per numeric cell, Node.js 26); also bounds the output of `toCSV`, `readTable`, `toJSON` and `readTableStream` to `max(maxCells, 16 × cells read)` positions |
397
+ | `maxSharedStringChars` | 512 Mi characters | many cells pointing at one huge shared string (a few MB that become many GB when values are copied); counted separately, the same for cells sharing one huge formula |
398
398
 
399
399
  ## Package size
400
400
 
@@ -409,6 +409,7 @@ Limits can be changed per call, for example `readWorkbook(bytes, { limits: { max
409
409
 
410
410
  ## Links
411
411
 
412
+ - Website with the guide and an in-browser demo: [xlvane.github.io](https://xlvane.github.io)
412
413
  - Changes in each version: [CHANGELOG.md](https://github.com/DevXord/xlvane/blob/main/CHANGELOG.md)
413
414
  - Bugs and questions: [GitHub issues](https://github.com/DevXord/xlvane/issues)
414
415
  - Reporting a vulnerability: [SECURITY.md](https://github.com/DevXord/xlvane/blob/main/SECURITY.md)
@@ -419,21 +420,22 @@ License: MIT
419
420
 
420
421
  ---
421
422
  name: xlvane
422
- 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.
423
424
  license: MIT
424
- 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.
425
426
  ---
426
427
 
427
428
  # xlvane: XLSX files
428
429
 
429
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.
430
431
 
431
- Two ways to use it, with the same behaviour:
432
+ Three ways to use it, with the same behaviour:
432
433
 
433
434
  | Way | When | Start |
434
435
  |---|---|---|
435
436
  | Library `xlvane` | You write JavaScript or TypeScript code | `npm install xlvane` |
436
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>` |
437
439
 
438
440
  ## Recommended order of work
439
441
 
@@ -609,6 +611,10 @@ xlvane validate report.xlsx --columns "Region:string,Revenue:number"
609
611
 
610
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`.
611
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
+
612
618
  ## Errors
613
619
 
614
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`.
@@ -693,11 +699,13 @@ Each code links to its section, which says what to do. The CLI prints the code a
693
699
  | [`XLV_W_MACROS_PRESENT`](#xlv_w_macros_present) | The workbook contains a VBA project or Excel 4.0 macro sheets. |
694
700
  | [`XLV_W_EXTERNAL_LINKS`](#xlv_w_external_links) | The workbook links to other workbooks. |
695
701
  | [`XLV_W_DUPLICATE_CELL`](#xlv_w_duplicate_cell) | A sheet defines the same cell more than once. |
702
+ | [`XLV_W_LIMIT_REACHED`](#xlv_w_limit_reached) | Reading stopped computing something derived from the file because the work would be far out of proportion to its data. |
696
703
  | [`XLV_W_INVALID_VALUE`](#xlv_w_invalid_value) | A value does not match its declared type and is returned in a safe form, for example a numeric cell whose text is not a number (returned … |
697
704
  | [`XLV_W_UNUSUAL_HYPERLINK`](#xlv_w_unusual_hyperlink) | A sheet has hyperlinks whose external target uses a scheme other than `http`, `https` or `mailto`, for example `file:`, `javascript:` or … |
698
705
  | [`XLV_W_DRAWING_CONTENT_NOT_READ`](#xlv_w_drawing_content_not_read) | The drawing of a sheet holds objects other than pictures: charts, shapes, connectors, group shapes, content parts or alternate content. |
699
706
  | [`XLV_W_THREADED_COMMENTS`](#xlv_w_threaded_comments) | A sheet has threaded comments, the conversations of current Excel versions ([MS-XLSX] §2.3.7). |
700
707
  | [`XLV_W_SHEET_PART_MISSING`](#xlv_w_sheet_part_missing) | A sheet listed in the workbook has no part (the relationship or the part itself is missing). |
708
+ | [`XLV_W_SHEET_PART_SHARED`](#xlv_w_sheet_part_shared) | Two or more sheets listed in the workbook lead to the same worksheet part, or relate to the same comments, VML or table part. |
701
709
  | [`XLV_W_PART_MISSING`](#xlv_w_part_missing) | The workbook points to a styles or shared strings part that does not exist. |
702
710
  | [`XLV_W_FORMULAS_NOT_RECALCULATED`](#xlv_w_formulas_not_recalculated) | Reported by `editCells` and `appendRows` when the workbook contains formulas. |
703
711
  | [`XLV_W_INVALID_CELL_REF`](#xlv_w_invalid_cell_ref) | A worksheet contains a row whose number is not a whole number from 1 to 1048576, a cell whose `r` reference is not a valid A1 reference … |
@@ -721,6 +729,14 @@ An argument of a method of `@xlvane/compat` is not valid, in a case where excelj
721
729
  ### XLV_E_LIMIT_EXCEEDED
722
730
  The file exceeds one of the resource limits (`ReadLimits`): input size, number of ZIP entries, decompressed size of one entry or of all entries, compression ratio, XML nesting depth, attribute count, name or text length, number of elements in a tree-parsed part, or number of cells. `details.limit` names the limit and `details.value` its current value. Sizes are measured on the bytes actually produced by decompression, so a file cannot avoid a limit by declaring false sizes.
723
731
 
732
+ Some limits also bound work derived from a small file (1.1.1, D-H01):
733
+
734
+ - `maxCells` (`details.limit` `maxCells`, `details.value` the budget): `toCSV`, `readTable`, `toJSON`, `readTableStream`, `xlvane read` and `xlvane convert` write at most `max(maxCells, 16 × cells read)` positions (rows × columns of the output), so a few cells far apart cannot make them produce a value for every position between; `@xlvane/compat`'s `xlsx.load` creates at most as many cells for merged ranges, tables and column definitions, and looks up at most 64 Mi rows (or 16 per cell read) for row settings up to the sheets' dimensions. Pass a smaller `range`, or raise `maxCells` for a trusted file.
735
+ - `maxXmlTextLength`: also the length of an XML comment or processing instruction.
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.
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
+
724
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.
725
741
 
726
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`.
@@ -794,6 +810,7 @@ A part exists but has the wrong structure: for example the workbook part's root
794
810
  | `target-mode` | `TargetMode` is neither `Internal` nor `External` |
795
811
  | `internal-target` | an internal relationship target cannot be resolved to a part name |
796
812
  | `equivalent-part-names` | two ZIP entries map to equivalent part names (e.g. a raw UTF-8 name and its percent-encoded form) |
813
+
797
814
  **Fix:** check that the file is an Excel workbook (not a Word or PowerPoint document) and re-save it in a spreadsheet application.
798
815
 
799
816
  ### XLV_E_INVALID_CELL_REF
@@ -895,10 +912,18 @@ For `insertRows`/`deleteRows`, insert or delete the rows in a spreadsheet applic
895
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.
896
913
  **Fix:** run `xlvane help <command>` for the usage and examples of the command.
897
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
+
898
919
  ### XLV_E_INTERNAL
899
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.
900
921
  **Fix:** report it with the command and, if possible, the input file (see SECURITY.md for files that must stay private).
901
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
+
902
927
  ## Warnings
903
928
 
904
929
  ### XLV_W_DIMENSION_MISMATCH
@@ -921,6 +946,10 @@ Some merged ranges have values in cells other than the top-left one. Spreadsheet
921
946
  `editCells` or `appendRows` wrote a value into a cell of a merged range other than its top-left cell. The value is stored, but spreadsheet applications show only the top-left cell of a merged range, so the value is not visible. `cells` lists the cells written (up to ten); the message names the first one and its merged range.
922
947
  **Fix:** write the value into the top-left cell of the range (named in the message), or unmerge the range first.
923
948
 
949
+ ### XLV_W_LIMIT_REACHED
950
+ Reading stopped computing something derived from the file because the work would be far out of proportion to its data, and the file is read without it. Today: hyperlinks whose ranges cover far more positions than the sheet has cells (more than 16 visits per cell plus 1 000 000); `sheet.hyperlinks` lists every link, but `cell.hyperlink` is not set for the cells of the remaining links (D-H01).
951
+ **Fix:** nothing, if the file comes from an unknown source: this protects the reader. Look up a cell's link in `sheet.hyperlinks` by its range.
952
+
924
953
  ### XLV_W_VERY_HIDDEN_SHEET
925
954
  A sheet has the state `veryHidden`: spreadsheet applications offer no menu command to unhide it, so users usually do not know it exists.
926
955
  **Fix:** nothing, if the sheet is expected; `inspect` lists it with its state, and `workbook.sheets` includes it.
@@ -957,6 +986,10 @@ A sheet has threaded comments, the conversations of current Excel versions ([MS-
957
986
  A sheet listed in the workbook has no part (the relationship or the part itself is missing). The sheet is returned with `part: null` and no cells.
958
987
  **Fix:** re-save the file in the application that made it; the sheet's cells are not in the file.
959
988
 
989
+ ### XLV_W_SHEET_PART_SHARED
990
+ Two or more sheets listed in the workbook lead to the same worksheet part, or relate to the same comments, VML or table part (part names compared without regard to case, as OPC requires). Spreadsheet applications write one such part per sheet; reading a shared part again for every sheet would decompress and parse it many times, outside the limit on decompressed bytes. The part is read for the first of these sheets only: for a worksheet part, the others are returned with `part: null` and no cells; for a comments, VML or table part, the others are read without its notes or table. A sheet that relates to one table part twice gets that table once. The location names the sheet and the part.
991
+ **Fix:** re-save the file in the application that made it, and check whether the sheets returned without cells should hold data.
992
+
960
993
  ### XLV_W_PART_MISSING
961
994
  The workbook points to a styles or shared strings part that does not exist. Reading continues without it: without styles, date-formatted numbers are returned as numbers; without shared strings, shared-string cells are treated as empty.
962
995
  **Fix:** re-save the file in the application that made it; check number formats and text cells of the result.
@@ -1184,7 +1217,7 @@ The error envelope is defined in [cli-json/common.schema.json](cli-json/common.s
1184
1217
  | Code | Meaning |
1185
1218
  |---|---|
1186
1219
  | 0 | Success. |
1187
- | 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). |
1188
1221
  | 2 | Usage error (`XLV_E_USAGE`): unknown command or option, missing or extra argument, invalid option value. |
1189
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. |
1190
1223
 
@@ -1200,6 +1233,7 @@ The error envelope is defined in [cli-json/common.schema.json](cli-json/common.s
1200
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. |
1201
1234
  | `validate` | [cli-json/validate.schema.json](cli-json/validate.schema.json) | `file`, `ok`, `sheet`, `rowsChecked`, `problems` (`kind`, `column`, `cell`, `row`, `message`), `warnings`. |
1202
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. |
1203
1237
 
1204
1238
  <!-- file: docs/exceljs-compat.md -->
1205
1239
 
@@ -1243,7 +1277,7 @@ Status: **supported** means the same behaviour as exceljs for the cases covered
1243
1277
  | `xlsx.write(stream)` | supported | | `lib/xlsx/xlsx.js` L643 |
1244
1278
  | `xlsx.createInputStream()` | supported | Throws the deprecation error, as in exceljs 4. | `lib/xlsx/xlsx.js` L238 |
1245
1279
  | `csv.read(stream, options)`, `csv.readFile(path, options)` | supported | Adds a worksheet, with exceljs's options (`sheetName`, `dateFormats`, `map`, `parserOptions`: `delimiter`, `quote`, `escape`, `trim`/`ltrim`/`rtrim`, `ignoreEmpty`, `comment`, `skipLines`, `skipRows`, `maxRows`, `headers`, `renameHeaders`, `encoding`) and its default conversion of fields (X4-23), on xlvane's own parser (no fast-csv). Accepts a Node.js readable stream, a Web `ReadableStream` or any (async) iterable of strings or bytes. Differences: text of white space only stays text (exceljs reads `' '` as 0), `-Infinity` stays text (it cannot be stored), a leading byte order mark is dropped (exceljs keeps it in the first field), `headers: true` skips the header line (exceljs throws `data.map is not a function`), a missing file or a malformed line throws `XLV_E_FILE_READ` / `XLV_E_CSV_MALFORMED`. `readFile` needs `node:fs` (Node.js, Bun, Deno). Dates are parsed as dayjs 1.11 customParseFormat parses them in strict mode (D-E06): letters that are no token, such as an unbracketed `T` or `dddd`, are skipped, and each token is searched in the rest of the text. An unclosed quote is reported on the line where it opens; a `quote` or `escape` longer than one character throws `XLV_E_INVALID_OPTION`. | `lib/csv/csv.js` L32–98 |
1246
- | `csv.write(stream, options)`, `csv.writeFile(path, options)`, `csv.writeBuffer(options)` | supported | Writes one worksheet with exceljs's options (`sheetName`, `sheetId`, `dateFormat`, `dateUTC`, `map`, `includeEmptyRows`, `encoding`, `formatterOptions`: `delimiter`, `rowDelimiter`, `quote`, `escape`, `quoteColumns`, `headers`, `writeHeaders`, `includeEndRowDelimiter`, `writeBOM`) and fast-csv's quoting (X4-24); the cross-check sample gives the same text as exceljs 4.4.0. Differences: text that starts with `=`, `+`, `-`, `@`, tab, CR or LF is written with a leading `'` (CSV injection, docs/facts/csv.md CSV-10; `formulaInjection: "off"` writes it unchanged, as exceljs); a formula result of 0 or `false` is written (exceljs writes an empty field), a date result is formatted as a date and an error result as its text; one blank line per missing row also before the first row (exceljs writes one too few there); a `sheetName` or `sheetId` that does not exist throws `XLV_E_SHEET_NOT_FOUND` (exceljs writes an empty file); header names in `formatterOptions.headers` are escaped like values. With `headers`, an array row gives one field per header (longer rows cut, shorter ones end in empty fields), as fast-csv writes it; `dateFormat: ''` uses the default format, as dayjs does (D-E06). `writeFile` writes `utf8`, `utf16le` or `latin1` and needs `node:fs`. | `lib/csv/csv.js` L109–186 |
1280
+ | `csv.write(stream, options)`, `csv.writeFile(path, options)`, `csv.writeBuffer(options)` | supported | Writes one worksheet with exceljs's options (`sheetName`, `sheetId`, `dateFormat`, `dateUTC`, `map`, `includeEmptyRows`, `encoding`, `formatterOptions`: `delimiter`, `rowDelimiter`, `quote`, `escape`, `quoteColumns`, `headers`, `writeHeaders`, `includeEndRowDelimiter`, `writeBOM`) and fast-csv's quoting (X4-24); the cross-check sample gives the same text as exceljs 4.4.0. Differences: text that starts with `=`, `+`, `-`, `@`, tab, CR, LF or another control character, or with a full-width or small form of these signs, is written with a leading `'` (CSV injection, docs/facts/csv.md CSV-10, CSV-12; `formulaInjection: "off"` writes it unchanged, as exceljs); a formula result of 0 or `false` is written (exceljs writes an empty field), a date result is formatted as a date and an error result as its text; one blank line per missing row also before the first row (exceljs writes one too few there); a `sheetName` or `sheetId` that does not exist throws `XLV_E_SHEET_NOT_FOUND` (exceljs writes an empty file); header names in `formatterOptions.headers` are escaped like values. With `headers`, an array row gives one field per header (longer rows cut, shorter ones end in empty fields), as fast-csv writes it; `dateFormat: ''` uses the default format, as dayjs does (D-E06). `writeFile` writes `utf8`, `utf16le` or `latin1` and needs `node:fs`. | `lib/csv/csv.js` L109–186 |
1247
1281
  | `csv.createInputStream()` | supported | Throws the deprecation error, as in exceljs 4. | `lib/csv/csv.js` L101 |
1248
1282
  | `definedNames` (`add`, `addEx`, `remove`, `removeEx`, `removeAllNames`, `forEach`, `getNames`, `getNamesEx`, `getRanges`, `getMatrix`, `model`) | supported | As in exceljs, a name is a set of cells, written as rectangles with absolute references and no sheet scope; on reading, names that are not cell ranges (constants, formulas, `#REF!`) and the sheet scope (`localSheetId`) are dropped. Built-in `_xlnm.` names are not listed: print areas and titles are read into `pageSetup`, as in exceljs, and xlvane writes the autofilter name itself. Names exceljs accepts but Excel does not (for example `A1` or names starting with `_xl`) throw `XLV_E_INVALID_DEFINED_NAME` when the workbook is written. | `lib/doc/defined-names.js`; `lib/xlsx/xform/book/defined-name-xform.js`; `lib/xlsx/xform/book/workbook-xform.js` L187 |
1249
1283
  | `addImage(image)`, `getImage(id)` | supported | PNG, JPEG and GIF given as `buffer`, `base64` (a data URL is accepted, as in exceljs) or `filename`; the format is recognised from the bytes, `extension` is kept but not used (exceljs writes `image/jpg` for `extension: 'jpg'`). As in exceljs, a `filename` is read when the workbook is written (`xlsx.writeBuffer`/`writeFile`/`write` and the streaming `WorkbookWriter`), so a missing file fails there; outside Node.js, Bun and Deno it gives `XLV_E_NOT_SUPPORTED`. Other formats throw `XLV_E_INVALID_IMAGE`. Read back, each image part is one media entry `{ type, name, extension, buffer }`, `buffer` a `Uint8Array`. Identical images are stored once, with one relationship per drawing (exceljs writes one per use). | `lib/doc/workbook.js` L142–151; `lib/xlsx/xlsx.js` L421–442 (L426–429: `filename` read at write) |
@@ -2637,6 +2671,52 @@ A workbook loaded with `xlsx.load()` is written again by `xlsx.writeBuffer()` (`
2637
2671
  ]
2638
2672
  }
2639
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
+
2640
2720
  <!-- file: docs/cli-json/migrate.schema.json -->
2641
2721
 
2642
2722
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xlvane",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
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`.