@imenam/xls-reader 2.4.3 → 2.4.4

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.
Files changed (2) hide show
  1. package/README.md +170 -164
  2. package/package.json +2 -5
package/README.md CHANGED
@@ -1,164 +1,170 @@
1
- # @imenam/xls-reader
2
-
3
- An MCP (Model Context Protocol) server that lets AI agents read Excel files. It can list the sheets of a workbook and render any sheet as a Markdown table, with smart handling of empty rows, empty cells, and in-cell line breaks, plus a configurable size limit to keep responses LLM-friendly.
4
-
5
- Supports `.xlsx`, `.xls`, `.ods` and `.csv` (anything [SheetJS](https://sheetjs.com/) can read).
6
-
7
- ## Where the file comes from
8
-
9
- Both tools take the workbook either **by path** or **by content**:
10
-
11
- - `file_path` — a path on the machine *running the server*. This is what a caller provides.
12
- - `file_content` — the file itself, base64-encoded (a `data:…;base64,` prefix is accepted), with `file_name` to label the output.
13
-
14
- At least one of the two is required. When both are given, `file_content` wins.
15
-
16
- **When the server runs on another machine, the content is what must travel** — a path would point at a file the server cannot see. That translation is not the agent's job: the client-side relay does it. With [`@imenam/mcp-http-gateway`](https://www.npmjs.com/package/@imenam/mcp-http-gateway) in `--mcp` mode, the relay runs next to the agent, reads the file named by `file_path`, sends `file_content`, and hides `file_content` / `file_name` from the schema it publishes — so the agent only ever names a path. Enable it with `GATEWAY_INLINE_ROOTS`, which also confines *which* folders can be read; see that package's README.
17
-
18
- Over stdio on a single machine, `file_path` is read directly and nothing else is needed.
19
-
20
- ## Tools
21
-
22
- ### `list_sheets`
23
-
24
- Lists all sheet names (tabs) in a workbook.
25
-
26
- | Parameter | Type | Required | Description |
27
- |---|---|---|---|
28
- | `file_path` | `string` | ⚠️ | Path to the Excel file. Resolved on the server, or read by the relay (see above) |
29
- | `file_content` | `string` | ⚠️ | Base64 content of the file. Normally filled in by the relay, not by the agent |
30
- | `file_name` | `string` | ❌ | Original file name, used only for labelling. Filled in with `file_content` |
31
-
32
- Returns the sheet names, one per line.
33
-
34
- ### `get_sheet`
35
-
36
- Reads a sheet and returns its content as a Markdown table.
37
-
38
- | Parameter | Type | Required | Description |
39
- |---|---|---|---|
40
- | `file_path` | `string` | ⚠️ | Path to the Excel file. Resolved on the server, or read by the relay (see above) |
41
- | `file_content` | `string` | ⚠️ | Base64 content of the file. Normally filled in by the relay, not by the agent |
42
- | `file_name` | `string` | ❌ | Original file name, used only for labelling. Filled in with `file_content` |
43
- | `sheet_name` | `string` | ✅ | Name of the sheet to read |
44
- | `format` | `"markdown" \| "json"` | ❌ | Output format (default: `markdown`) |
45
- | `cell_budget` | `number` | ❌ | Maximum number of cells to return (cols × rows). Default: `2000` |
46
- | `max_cols` | `number` | ❌ | Override the maximum number of columns |
47
- | `max_rows` | `number` | ❌ | Override the maximum number of rows |
48
- | `header_row` | `boolean` | ❌ | Treat the first row as a column header (default: `true`) |
49
-
50
- #### Smart content handling
51
-
52
- - **Empty rows are section separators.** A fully empty row closes the current table and starts a new one; when `header_row` is enabled, the header is repeated on each section.
53
- - **Empty cells are kept as blanks** so columns stay aligned.
54
- - **In-cell line breaks** are converted to a literal `\n` so they don't break the Markdown table row.
55
- - **Dates and booleans** are rendered as readable text rather than Excel serial numbers.
56
-
57
- #### Output formats
58
-
59
- With `format: "markdown"` (default) you get one Markdown table per section.
60
-
61
- With `format: "json"` you get a structured object — better when the agent needs to *process* the data rather than read it. Native types are preserved (numbers, booleans, dates as ISO strings) and real line breaks are kept:
62
-
63
- ```json
64
- {
65
- "sheet": "Feuille1",
66
- "truncated": false,
67
- "groups": [
68
- [
69
- { "Nom": "Dupont", "Prénom": "Jean", "Age": 42 },
70
- { "Nom": "Martin", "Age": 35 }
71
- ]
72
- ]
73
- }
74
- ```
75
-
76
- - `groups` is an array of sections (one per block separated by an empty row).
77
- - With `header_row: true`, each row is an **object** keyed by column name; **empty cells are omitted**.
78
- - With `header_row: false`, each row is an **array** of values (empty cells become `null`).
79
- - When data is truncated, `truncated` is `true` and a `note` field explains what was omitted.
80
-
81
- To export without any size limit, use [`export_workbook`](#export_workbook), which writes a JSON file instead of returning it.
82
-
83
- #### Size limit
84
-
85
- By default the response is capped at `cell_budget = 2000` cells (`cols × rows`). With 10 columns you get ~200 rows; with 20 columns, ~100 rows. When data is truncated, a warning is appended telling you how much was omitted. Override with `cell_budget`, `max_cols`, or `max_rows` to read more (or less).
86
-
87
- ### `export_workbook`
88
-
89
- Exports a workbook as a JSON file, with **no size limit**, and writes it **on the agent machine**. Use it when the data is too large to return inline. By default the entire workbook is exported; provide `sheet_name` to export only one sheet.
90
-
91
- | Parameter | Type | Required | Description |
92
- |---|---|---|---|
93
- | `file_path` | `string` | ⚠️ | Path to the Excel file. Resolved on the server, or read by the relay (see above) |
94
- | `file_content` | `string` | ⚠️ | Base64 content of the file. Normally filled in by the relay, not by the agent |
95
- | `file_name` | `string` | ❌ | Original file name, used only for labelling. Filled in with `file_content` |
96
- | `sheet_name` | `string` | ❌ | Omit to export the whole workbook, or set it to export only that sheet |
97
- | `header_row` | `boolean` | ❌ | Treat the first row as a column header (default: `true`) |
98
- | `destination_path` | `string` | ✅ | **Absolute directory** on the agent machine. Created if missing |
99
- | `filename` | `string` | ✅ | Name the exported file gets there, e.g. `data.json`. No path separators |
100
- | `destination_overwrite` | `boolean` | ❌ | Replace the destination file if it exists (default: `false`) |
101
- | `destination_relay` | `boolean` | ❌ | Filled in by the relay, never by the agent |
102
-
103
- The exported file never passes through the conversation. When this MCP runs next to the agent (stdio), it writes the file itself. Behind [`@imenam/mcp-http-gateway`](https://www.npmjs.com/package/@imenam/mcp-http-gateway) it runs on the gateway's machine and cannot reach the agent's disk: it then returns the bytes, and the relay — which *does* run on the agent machine — writes them at `destination_path`. The relay keeps that path to itself and never forwards it, which is why the tool schema declares it optional; the tool rejects a call that lacks it when it has to write the file itself. That path requires `GATEWAY_INLINE_WRITE_ROOTS` in the relay's `env` block; without it the call fails explicitly rather than dropping the file on the wrong machine.
104
-
105
- The file content is:
106
-
107
- ```json
108
- {
109
- "file": "data.xlsx",
110
- "sheets": [
111
- { "sheet": "Feuille1", "groups": [ /* …same shape as json… */ ] },
112
- { "sheet": "Feuille2", "groups": [ /* … */ ] }
113
- ]
114
- }
115
- ```
116
-
117
- ## Installation
118
-
119
- ```bash
120
- npm install -g @imenam/xls-reader
121
- ```
122
-
123
- Or use it directly with `npx`:
124
-
125
- ```json
126
- {
127
- "xls-reader": {
128
- "command": "npx",
129
- "args": ["-y", "@imenam/xls-reader"]
130
- }
131
- }
132
- ```
133
-
134
- Or point to a local build:
135
-
136
- ```json
137
- {
138
- "xls-reader": {
139
- "command": "node",
140
- "args": ["/absolute/path/to/xls-reader/dist/index.js"]
141
- }
142
- }
143
- ```
144
-
145
- ## Configuration
146
-
147
- No environment variables are required. Optionally, set `MCP_LOG_DIR` to change where logs are written (default: `.xls-reader/logs` in the home directory of the user running the server). When the log file cannot be written, each log line is reported on stderr as `Critical: Failed to write to log file <path>: <reason>` and the server keeps running.
148
-
149
- ```env
150
- # .env
151
- MCP_LOG_DIR=/absolute/path/to/logs
152
- ```
153
-
154
- ## Development
155
-
156
- ```bash
157
- npm install
158
- npm run build # compile TypeScript to dist/
159
- npm run dev # run from source with tsx
160
- ```
161
-
162
- ## License
163
-
164
- MIT
1
+ # @imenam/xls-reader
2
+
3
+ An MCP (Model Context Protocol) server that lets AI agents read Excel files. It can list the sheets of a workbook and render any sheet as a Markdown table, with smart handling of empty rows, empty cells, and in-cell line breaks, plus a configurable size limit to keep responses LLM-friendly.
4
+
5
+ Supports `.xlsx`, `.xls`, `.ods` and `.csv` (anything [SheetJS](https://sheetjs.com/) can read).
6
+
7
+ ## Where the file comes from
8
+
9
+ Both tools take the workbook either **by path** or **by content**:
10
+
11
+ - `file_path` — a path on the machine *running the server*. This is what a caller provides.
12
+ - `file_content` — the file itself, base64-encoded (a `data:…;base64,` prefix is accepted), with `file_name` to label the output.
13
+
14
+ At least one of the two is required. When both are given, `file_content` wins.
15
+
16
+ **When the server runs on another machine, the content is what must travel** — a path would point at a file the server cannot see. That translation is not the agent's job: the client-side relay does it. With [`@imenam/mcp-http-gateway`](https://www.npmjs.com/package/@imenam/mcp-http-gateway) in `--mcp` mode, the relay runs next to the agent, reads the file named by `file_path`, sends `file_content`, and hides `file_content` / `file_name` from the schema it publishes — so the agent only ever names a path. Enable it with `GATEWAY_INLINE_ROOTS`, which also confines *which* folders can be read; see that package's README.
17
+
18
+ Over stdio on a single machine, `file_path` is read directly and nothing else is needed.
19
+
20
+ ## Tools
21
+
22
+ ### `list_sheets`
23
+
24
+ Lists all sheet names (tabs) in a workbook.
25
+
26
+ | Parameter | Type | Required | Description |
27
+ |---|---|---|---|
28
+ | `file_path` | `string` | ⚠️ | Path to the Excel file. Resolved on the server, or read by the relay (see above) |
29
+ | `file_content` | `string` | ⚠️ | Base64 content of the file. Normally filled in by the relay, not by the agent |
30
+ | `file_name` | `string` | ❌ | Original file name, used only for labelling. Filled in with `file_content` |
31
+
32
+ Returns the sheet names, one per line.
33
+
34
+ ### `get_sheet`
35
+
36
+ Reads a sheet and returns its content as a Markdown table.
37
+
38
+ | Parameter | Type | Required | Description |
39
+ |---|---|---|---|
40
+ | `file_path` | `string` | ⚠️ | Path to the Excel file. Resolved on the server, or read by the relay (see above) |
41
+ | `file_content` | `string` | ⚠️ | Base64 content of the file. Normally filled in by the relay, not by the agent |
42
+ | `file_name` | `string` | ❌ | Original file name, used only for labelling. Filled in with `file_content` |
43
+ | `sheet_name` | `string` | ✅ | Name of the sheet to read |
44
+ | `format` | `"markdown" \| "json"` | ❌ | Output format (default: `markdown`) |
45
+ | `cell_budget` | `number` | ❌ | Maximum number of cells to return (cols × rows). Default: `2000` |
46
+ | `max_cols` | `number` | ❌ | Override the maximum number of columns |
47
+ | `max_rows` | `number` | ❌ | Override the maximum number of rows |
48
+ | `header_row` | `boolean` | ❌ | Treat the first row as a column header (default: `true`) |
49
+
50
+ #### Smart content handling
51
+
52
+ - **Empty rows are section separators.** A fully empty row closes the current table and starts a new one; when `header_row` is enabled, the header is repeated on each section.
53
+ - **Empty cells are kept as blanks** so columns stay aligned.
54
+ - **In-cell line breaks** are converted to a literal `\n` so they don't break the Markdown table row.
55
+ - **Dates and booleans** are rendered as readable text rather than Excel serial numbers.
56
+
57
+ #### Output formats
58
+
59
+ With `format: "markdown"` (default) you get one Markdown table per section.
60
+
61
+ With `format: "json"` you get a structured object — better when the agent needs to *process* the data rather than read it. Native types are preserved (numbers, booleans, dates as ISO strings) and real line breaks are kept:
62
+
63
+ ```json
64
+ {
65
+ "sheet": "Feuille1",
66
+ "truncated": false,
67
+ "groups": [
68
+ [
69
+ { "Nom": "Dupont", "Prénom": "Jean", "Age": 42 },
70
+ { "Nom": "Martin", "Age": 35 }
71
+ ]
72
+ ]
73
+ }
74
+ ```
75
+
76
+ - `groups` is an array of sections (one per block separated by an empty row).
77
+ - With `header_row: true`, each row is an **object** keyed by column name; **empty cells are omitted**.
78
+ - With `header_row: false`, each row is an **array** of values (empty cells become `null`).
79
+ - When data is truncated, `truncated` is `true` and a `note` field explains what was omitted.
80
+
81
+ To export without any size limit, use [`export_workbook`](#export_workbook), which writes a JSON file instead of returning it.
82
+
83
+ #### Size limit
84
+
85
+ By default the response is capped at `cell_budget = 2000` cells (`cols × rows`). With 10 columns you get ~200 rows; with 20 columns, ~100 rows. When data is truncated, a warning is appended telling you how much was omitted. Override with `cell_budget`, `max_cols`, or `max_rows` to read more (or less).
86
+
87
+ ### `export_workbook`
88
+
89
+ Exports a workbook as a JSON file, with **no size limit**, and writes it **on the agent machine**. Use it when the data is too large to return inline. By default the entire workbook is exported; provide `sheet_name` to export only one sheet.
90
+
91
+ | Parameter | Type | Required | Description |
92
+ |---|---|---|---|
93
+ | `file_path` | `string` | ⚠️ | Path to the Excel file. Resolved on the server, or read by the relay (see above) |
94
+ | `file_content` | `string` | ⚠️ | Base64 content of the file. Normally filled in by the relay, not by the agent |
95
+ | `file_name` | `string` | ❌ | Original file name, used only for labelling. Filled in with `file_content` |
96
+ | `sheet_name` | `string` | ❌ | Omit to export the whole workbook, or set it to export only that sheet |
97
+ | `header_row` | `boolean` | ❌ | Treat the first row as a column header (default: `true`) |
98
+ | `destination_path` | `string` | ✅ | **Absolute directory** on the agent machine. Created if missing |
99
+ | `filename` | `string` | ✅ | Name the exported file gets there, e.g. `data.json`. No path separators |
100
+ | `destination_overwrite` | `boolean` | ❌ | Replace the destination file if it exists (default: `false`) |
101
+ | `destination_relay` | `boolean` | ❌ | Filled in by the relay, never by the agent |
102
+
103
+ The exported file never passes through the conversation. When this MCP runs next to the agent (stdio), it writes the file itself. Behind [`@imenam/mcp-http-gateway`](https://www.npmjs.com/package/@imenam/mcp-http-gateway) it runs on the gateway's machine and cannot reach the agent's disk: it then returns the bytes, and the relay — which *does* run on the agent machine — writes them at `destination_path`. The relay keeps that path to itself and never forwards it, which is why the tool schema declares it optional; the tool rejects a call that lacks it when it has to write the file itself. That path requires `GATEWAY_INLINE_WRITE_ROOTS` in the relay's `env` block; without it the call fails explicitly rather than dropping the file on the wrong machine.
104
+
105
+ The file content is:
106
+
107
+ ```json
108
+ {
109
+ "file": "data.xlsx",
110
+ "sheets": [
111
+ { "sheet": "Feuille1", "groups": [ /* …same shape as json… */ ] },
112
+ { "sheet": "Feuille2", "groups": [ /* … */ ] }
113
+ ]
114
+ }
115
+ ```
116
+
117
+ ## Installation
118
+
119
+ ```bash
120
+ npm install -g @imenam/xls-reader
121
+ ```
122
+
123
+ Or use it directly with `npx`:
124
+
125
+ ```json
126
+ {
127
+ "xls-reader": {
128
+ "command": "npx",
129
+ "args": ["-y", "@imenam/xls-reader"]
130
+ }
131
+ }
132
+ ```
133
+
134
+ Or point to a local build:
135
+
136
+ ```json
137
+ {
138
+ "xls-reader": {
139
+ "command": "node",
140
+ "args": ["/absolute/path/to/xls-reader/dist/index.js"]
141
+ }
142
+ }
143
+ ```
144
+
145
+ ## Configuration
146
+
147
+ No environment variables are required. Optionally, set `MCP_LOG_DIR` to change where logs are written (default: `.xls-reader/logs` in the home directory of the user running the server). When the log file cannot be written, each log line is reported on stderr as `Critical: Failed to write to log file <path>: <reason>` and the server keeps running.
148
+
149
+ ```env
150
+ # .env
151
+ MCP_LOG_DIR=/absolute/path/to/logs
152
+ ```
153
+
154
+ ## Development
155
+
156
+ ```bash
157
+ npm install
158
+ npm run build # compile TypeScript to dist/
159
+ npm run dev # run from source with tsx
160
+ ```
161
+
162
+ ## Publication
163
+
164
+ Chaque push sur `master`, merge de pull request compris, publie une nouvelle version de `@imenam/xls-reader` sur npm (`.github/workflows/publish.yml`) : `npm ci` et build, puis `npm version patch`, dont le commit et le tag sont poussés sur `master`, et `npm publish`. La publication passe par le trusted publishing de npm (OIDC, sans token), avec attestation de provenance. Un échec du build arrête le workflow avant la montée de version.
165
+
166
+ Sur npmjs.com, le paquet déclare ce workflow comme publieur de confiance (Settings → Trusted publishing → GitHub Actions : `Matthieu-Pesnot-Pin`, `xls-reader`, `publish.yml`, avec `npm publish` dans les actions autorisées). Le commit de version est poussé avec `GITHUB_TOKEN` : si `master` est protégée, la règle doit autoriser GitHub Actions à y pousser.
167
+
168
+ ## License
169
+
170
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imenam/xls-reader",
3
- "version": "2.4.3",
3
+ "version": "2.4.4",
4
4
  "description": "MCP server that lets AI agents read Excel files: list sheets and render any sheet as a Markdown table.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -14,10 +14,7 @@
14
14
  "build": "tsc",
15
15
  "start": "node dist/index.js",
16
16
  "dev": "tsx src/index.ts",
17
- "prepublishOnly": "npm run build",
18
- "release:patch": "npm version patch && npm publish --access public && git push origin master --follow-tags",
19
- "release:minor": "npm version minor && npm publish --access public && git push origin master --follow-tags",
20
- "release:major": "npm version major && npm publish --access public && git push origin master --follow-tags"
17
+ "prepublishOnly": "npm run build"
21
18
  },
22
19
  "keywords": [
23
20
  "mcp",