xlsx-for-ai 2.21.0 → 2.23.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/README.md +8 -0
- package/mcp.js +111 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -194,6 +194,14 @@ For custom MCP clients, the binary is `xlsx-for-ai-mcp` (stdio transport). Overr
|
|
|
194
194
|
| Tool | What it does |
|
|
195
195
|
|---|---|
|
|
196
196
|
| `xlsx_post_slack` | Post a workbook to a Slack channel as a file attachment with an optional message. BYOA — the agent supplies the user's Slack bot token (`xoxb-…`); the token is forwarded to Slack and never persisted. Uses Slack's external upload flow. |
|
|
197
|
+
| `xlsx_post_teams` | Post a workbook to a Microsoft Teams channel as a file attachment in a channel message, with an optional message. BYOA — the agent supplies the user's Microsoft Graph access token (JWT); the token is forwarded to Microsoft and never persisted. Uses Graph's filesFolder + upload-session + post-message flow. |
|
|
198
|
+
|
|
199
|
+
### Integrity verification
|
|
200
|
+
|
|
201
|
+
| Tool | What it does |
|
|
202
|
+
|---|---|
|
|
203
|
+
| `xlsx_stamp` | Sign a workbook with a cryptographic "integrity verification" stamp — Ed25519-signed claims (named factual checks + their pass/fail/skip status + a content hash) embedded in `docProps/custom.xml`. The stamp travels with the file across saves; a recipient can verify it later to confirm the file hasn't been tampered with since signing. Factual attestations only — never an opinion-shaped seal of approval. |
|
|
204
|
+
| `xlsx_verify_stamp` | Verify a workbook's embedded stamp. Returns (a) whether the Ed25519 signature is valid against the registered public key, (b) whether the workbook bytes match the hash IN the signed claims, and (c) the full check-result content of the stamp. Three distinct trust signals — signature integrity, content integrity, and what was originally attested. |
|
|
197
205
|
|
|
198
206
|
Tool responses include a citation footer and a `_meta` block (tool name, version, tier, request ID, `powered_by`). Both pass through verbatim; nothing is stripped.
|
|
199
207
|
|
package/mcp.js
CHANGED
|
@@ -849,6 +849,79 @@ const TOOLS = [
|
|
|
849
849
|
required: ['file_path', 'channel', 'slack_token'],
|
|
850
850
|
},
|
|
851
851
|
},
|
|
852
|
+
|
|
853
|
+
{
|
|
854
|
+
name: 'xlsx_post_teams',
|
|
855
|
+
description:
|
|
856
|
+
'xlsx-for-ai — read, write, diff, redact, supervise .xlsx files locally.\n' +
|
|
857
|
+
'This tool: upload a local .xlsx file to a Microsoft Teams channel as a file attachment in a channel message, with an optional accompanying message. BYOA — the agent must pass the user\'s Microsoft Graph access token (a JWT starting with "eyJ"). The token is forwarded to Microsoft Graph and never stored server-side.\n' +
|
|
858
|
+
'Uses Microsoft Graph\'s 4-step flow: locate the channel\'s filesFolder driveItem, create an upload session, upload the bytes, then post a chatMessage with the file as an inline attachment.\n\n' +
|
|
859
|
+
'USE WHEN: the user asks "post this workbook to my Teams channel," "share this with the team in Teams," or any other outbound-file-to-Teams request. The agent has just produced or modified a workbook and wants to deliver it to a Microsoft Teams channel. ' +
|
|
860
|
+
'Free tier — counts against the 10k/mo cap.\n\n' +
|
|
861
|
+
'DO NOT USE WHEN: posting to Slack (use xlsx_post_slack). Or when there is no Microsoft Graph token available — the user must have an Entra ID app registration with Group.ReadWrite.All or Files.ReadWrite.All + ChannelMessage.Send scopes, AND a valid access token for that app.',
|
|
862
|
+
inputSchema: {
|
|
863
|
+
type: 'object',
|
|
864
|
+
properties: {
|
|
865
|
+
file_path: { type: 'string', description: 'Absolute path to the .xlsx file to post.' },
|
|
866
|
+
team_id: { type: 'string', description: 'Microsoft Teams team ID (GUID). Find via Graph: GET /me/joinedTeams.' },
|
|
867
|
+
channel_id: { type: 'string', description: 'Microsoft Teams channel ID. Find via Graph: GET /teams/{team-id}/channels.' },
|
|
868
|
+
graph_token: { type: 'string', description: 'Microsoft Graph access token (JWT). Forwarded to Microsoft; never persisted by us. Must have file-upload + channel-message-send scopes.' },
|
|
869
|
+
message: { type: 'string', description: 'Optional: message to post alongside the file. Plain text; will be HTML-escaped server-side.' },
|
|
870
|
+
filename: { type: 'string', description: 'Optional: filename Teams will display. Defaults to the basename of file_path.' },
|
|
871
|
+
},
|
|
872
|
+
required: ['file_path', 'team_id', 'channel_id', 'graph_token'],
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
|
|
876
|
+
{
|
|
877
|
+
name: 'xlsx_stamp',
|
|
878
|
+
description:
|
|
879
|
+
'xlsx-for-ai — read, write, diff, redact, supervise .xlsx files locally.\n' +
|
|
880
|
+
'This tool: sign a workbook with a "workbook integrity verification" stamp — a cryptographic attestation embedded in docProps/custom.xml that says "this file was generated by these tools, passed these N specific checks, signed at this time, and hasn\'t been tampered with since." Factual claims only (never an opinion-shaped seal of approval). Returns the stamped workbook as base64 in _meta.file_b64; pass out_path to write to disk.\n' +
|
|
881
|
+
'The caller supplies the `checks` array (e.g., from a supervisor review): list of named tests, each with passed/failed/skipped status. Verifiers see the individual check results, not a single good/bad opinion.\n\n' +
|
|
882
|
+
'USE WHEN: the agent has just produced or reviewed a workbook and wants to attach provable provenance + check results that travel with the file. The recipient can later verify the stamp via xlsx_verify_stamp to confirm the file hasn\'t been modified and to see the original check results.\n\n' +
|
|
883
|
+
'DO NOT USE WHEN: the user just wants to share a file (use xlsx_post_slack / xlsx_post_teams). Or when there are no real checks to attest to (an empty checks array is allowed and means "we ran zero checks" — but the stamp\'s value is in the checks it records).',
|
|
884
|
+
inputSchema: {
|
|
885
|
+
type: 'object',
|
|
886
|
+
properties: {
|
|
887
|
+
file_path: { type: 'string', description: 'Absolute path to the .xlsx file to stamp.' },
|
|
888
|
+
checks: {
|
|
889
|
+
type: 'array',
|
|
890
|
+
description: 'Array of named checks, each with passed/failed/skipped status. These are the factual claims the stamp attests to.',
|
|
891
|
+
items: {
|
|
892
|
+
type: 'object',
|
|
893
|
+
properties: {
|
|
894
|
+
id: { type: 'string', description: 'Stable check identifier (e.g., "tieouts_consistent").' },
|
|
895
|
+
name: { type: 'string', description: 'Human-readable check name.' },
|
|
896
|
+
status: { type: 'string', enum: ['passed', 'failed', 'skipped'] },
|
|
897
|
+
detail: { type: 'string', description: 'Optional explanation, especially for failed/skipped status.' },
|
|
898
|
+
},
|
|
899
|
+
required: ['id', 'name', 'status'],
|
|
900
|
+
},
|
|
901
|
+
},
|
|
902
|
+
out_path: { type: 'string', description: 'Optional: write the stamped workbook to this absolute path. If omitted, the stamped bytes are returned in _meta.file_b64 only.' },
|
|
903
|
+
exclude_sheets: { type: 'array', items: { type: 'string' }, description: 'Optional: sheet names to exclude from the content hash. Use for scratch tabs that legitimately change without affecting attestation.' },
|
|
904
|
+
supervisor_version: { type: 'string', description: 'Optional: xlsx-supervisor version string to include in the stamp\'s generated_by claim (e.g., "xlsx-supervisor@1.4.0").' },
|
|
905
|
+
},
|
|
906
|
+
required: ['file_path', 'checks'],
|
|
907
|
+
},
|
|
908
|
+
},
|
|
909
|
+
|
|
910
|
+
{
|
|
911
|
+
name: 'xlsx_verify_stamp',
|
|
912
|
+
description:
|
|
913
|
+
'xlsx-for-ai — read, write, diff, redact, supervise .xlsx files locally.\n' +
|
|
914
|
+
'This tool: verify a workbook\'s embedded integrity-verification stamp. Returns whether the cryptographic signature is valid, whether the workbook bytes match what was signed (recomputed hash vs hash IN the stamp), and the full check-result content of the stamp.\n' +
|
|
915
|
+
'A workbook can fail verification three ways: (1) no stamp present (file was never stamped, or the stamp was stripped); (2) signature_valid=false (someone modified the claims after signing, or signed with a different key); (3) hash_matches=false (someone modified the workbook bytes after signing). Each is a distinct trust signal.\n\n' +
|
|
916
|
+
'USE WHEN: the agent (or a downstream verifier) needs to confirm a workbook hasn\'t been tampered with since it was signed, OR needs to surface the original check results that were attested to. Common scenario: incoming workbook from a counterparty, agent runs verify before trusting any of its values.',
|
|
917
|
+
inputSchema: {
|
|
918
|
+
type: 'object',
|
|
919
|
+
properties: {
|
|
920
|
+
file_path: { type: 'string', description: 'Absolute path to the .xlsx file to verify.' },
|
|
921
|
+
},
|
|
922
|
+
required: ['file_path'],
|
|
923
|
+
},
|
|
924
|
+
},
|
|
852
925
|
];
|
|
853
926
|
|
|
854
927
|
// ---------------------------------------------------------------------------
|
|
@@ -1076,6 +1149,44 @@ async function dispatchTool(name, args) {
|
|
|
1076
1149
|
return callTool('xlsx_post_slack', body);
|
|
1077
1150
|
}
|
|
1078
1151
|
|
|
1152
|
+
// xlsx_post_teams: outbound file-to-Teams. Same shape as Slack but with
|
|
1153
|
+
// Microsoft Graph fields (team_id + channel_id + graph_token).
|
|
1154
|
+
if (name === 'xlsx_post_teams') {
|
|
1155
|
+
const body = {
|
|
1156
|
+
file_b64: fileToB64(args.file_path),
|
|
1157
|
+
team_id: args.team_id,
|
|
1158
|
+
channel_id: args.channel_id,
|
|
1159
|
+
graph_token: args.graph_token,
|
|
1160
|
+
};
|
|
1161
|
+
if (args.message !== undefined) body.message = args.message;
|
|
1162
|
+
body.filename = args.filename || path.basename(args.file_path);
|
|
1163
|
+
return callTool('xlsx_post_teams', body);
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// xlsx_stamp: sign + embed an integrity-verification stamp. Returns the
|
|
1167
|
+
// stamped file as base64 in _meta.file_b64; if out_path is provided we
|
|
1168
|
+
// also write the bytes to disk (same pattern as xlsx_write / xlsx_redact).
|
|
1169
|
+
if (name === 'xlsx_stamp') {
|
|
1170
|
+
const body = {
|
|
1171
|
+
file_b64: fileToB64(args.file_path),
|
|
1172
|
+
checks: args.checks,
|
|
1173
|
+
};
|
|
1174
|
+
if (args.exclude_sheets !== undefined) body.exclude_sheets = args.exclude_sheets;
|
|
1175
|
+
if (args.supervisor_version !== undefined) {
|
|
1176
|
+
body.generated_by = { npm: 'xlsx-for-ai@' + require('./package.json').version, supervisor: args.supervisor_version };
|
|
1177
|
+
}
|
|
1178
|
+
const result = await callTool('xlsx_stamp', body);
|
|
1179
|
+
return applyFileB64(result, args.out_path);
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// xlsx_verify_stamp: extract + verify the integrity-verification stamp.
|
|
1183
|
+
// Returns structured result in _meta.{valid, signature_valid, hash_matches,
|
|
1184
|
+
// claims, workbook_hash_in_stamp, workbook_hash_recomputed, …}.
|
|
1185
|
+
if (name === 'xlsx_verify_stamp') {
|
|
1186
|
+
const body = { file_b64: fileToB64(args.file_path) };
|
|
1187
|
+
return callTool('xlsx_verify_stamp', body);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1079
1190
|
// All other tools (list_sheets, schema, hyperlinks, conditional_formats,
|
|
1080
1191
|
// styles, etc.) — single-file relay. Forward any common option keys the
|
|
1081
1192
|
// routes accept so we don't silently drop them. New keys added here as
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xlsx-for-ai",
|
|
3
3
|
"mcpName": "io.github.senoff/xlsx-for-ai",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.23.0",
|
|
5
5
|
"description": "The MCP server that makes LLMs reliable on real-world Excel spreadsheets. Thin npm client over a hosted API — read, write, diff, redact, and supervise .xlsx files from any MCP-aware agent.",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"bin": {
|