xlsx-for-ai 2.20.0 → 2.22.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 +7 -0
- package/lib/client.js +5 -1
- package/mcp.js +73 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -189,6 +189,13 @@ For custom MCP clients, the binary is `xlsx-for-ai-mcp` (stdio transport). Overr
|
|
|
189
189
|
| `xlsx_form_controls` | Interactive widgets — checkboxes, buttons, drop-downs, spinners, scroll bars, list boxes — with linked cell + bounds. |
|
|
190
190
|
| `xlsx_macros` | VBA macro presence + module-name heuristics + safety advice (does NOT extract source by policy). |
|
|
191
191
|
|
|
192
|
+
### Integrations
|
|
193
|
+
|
|
194
|
+
| Tool | What it does |
|
|
195
|
+
|---|---|
|
|
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
|
+
|
|
192
199
|
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.
|
|
193
200
|
|
|
194
201
|
---
|
package/lib/client.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
const { readConfig } = require('./config');
|
|
15
|
+
const { version: CLIENT_VERSION } = require('../package.json');
|
|
15
16
|
|
|
16
17
|
const DEFAULT_API = 'https://api.xlsx-for-ai.dev';
|
|
17
18
|
const TIMEOUT_MS = 30_000;
|
|
@@ -32,7 +33,10 @@ async function fetchWithTimeout(url, init) {
|
|
|
32
33
|
|
|
33
34
|
async function post(path, body, opts = {}) {
|
|
34
35
|
const url = apiBase() + path;
|
|
35
|
-
const headers = {
|
|
36
|
+
const headers = {
|
|
37
|
+
'Content-Type': 'application/json',
|
|
38
|
+
'X-Client-Version': CLIENT_VERSION,
|
|
39
|
+
};
|
|
36
40
|
|
|
37
41
|
if (opts.auth !== false) {
|
|
38
42
|
const cfg = readConfig();
|
package/mcp.js
CHANGED
|
@@ -827,6 +827,51 @@ const TOOLS = [
|
|
|
827
827
|
required: ['file_path'],
|
|
828
828
|
},
|
|
829
829
|
},
|
|
830
|
+
|
|
831
|
+
{
|
|
832
|
+
name: 'xlsx_post_slack',
|
|
833
|
+
description:
|
|
834
|
+
'xlsx-for-ai — read, write, diff, redact, supervise .xlsx files locally.\n' +
|
|
835
|
+
'This tool: upload a local .xlsx file to a Slack channel as a file attachment, with an optional accompanying message. BYOA — the agent must pass the user\'s Slack bot token (xoxb-…). The token is forwarded to Slack and never stored server-side.\n' +
|
|
836
|
+
'Posts via Slack\'s 3-step external upload flow (files.getUploadURLExternal → upload → files.completeUploadExternal), which is the only sanctioned path as of 2024+.\n\n' +
|
|
837
|
+
'USE WHEN: the user asks "post this workbook to #channel," "share this with the team in Slack," or any other outbound-file-to-Slack request. The agent has just produced or modified a workbook and wants to deliver it. ' +
|
|
838
|
+
'Free tier — counts against the 10k/mo cap.\n\n' +
|
|
839
|
+
'DO NOT USE WHEN: the file lives in a Slack channel and you want to READ it (that\'s the inbound Manual-Mode-Detector pattern, not this). Or when there is no Slack bot token available — the user must have installed a Slack app with files:write scope.',
|
|
840
|
+
inputSchema: {
|
|
841
|
+
type: 'object',
|
|
842
|
+
properties: {
|
|
843
|
+
file_path: { type: 'string', description: 'Absolute path to the .xlsx file to post.' },
|
|
844
|
+
channel: { type: 'string', description: 'Slack channel ID (C…/G…) the file should land in. Channel names like #general are NOT accepted — resolve to a channel ID first.' },
|
|
845
|
+
slack_token: { type: 'string', description: 'Slack bot token (xoxb-…). Forwarded to Slack; never persisted by us.' },
|
|
846
|
+
message: { type: 'string', description: 'Optional: message to post alongside the file (Slack\'s initial_comment).' },
|
|
847
|
+
filename: { type: 'string', description: 'Optional: filename Slack will display. Defaults to the basename of file_path.' },
|
|
848
|
+
},
|
|
849
|
+
required: ['file_path', 'channel', 'slack_token'],
|
|
850
|
+
},
|
|
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
|
+
},
|
|
830
875
|
];
|
|
831
876
|
|
|
832
877
|
// ---------------------------------------------------------------------------
|
|
@@ -1040,6 +1085,34 @@ async function dispatchTool(name, args) {
|
|
|
1040
1085
|
});
|
|
1041
1086
|
}
|
|
1042
1087
|
|
|
1088
|
+
// xlsx_post_slack: outbound file-to-Slack. Top-level fields, not the
|
|
1089
|
+
// standard {file_b64, options} shape — channel + slack_token + message
|
|
1090
|
+
// + filename live alongside file_b64 in the server route's body schema.
|
|
1091
|
+
if (name === 'xlsx_post_slack') {
|
|
1092
|
+
const body = {
|
|
1093
|
+
file_b64: fileToB64(args.file_path),
|
|
1094
|
+
channel: args.channel,
|
|
1095
|
+
slack_token: args.slack_token,
|
|
1096
|
+
};
|
|
1097
|
+
if (args.message !== undefined) body.message = args.message;
|
|
1098
|
+
body.filename = args.filename || path.basename(args.file_path);
|
|
1099
|
+
return callTool('xlsx_post_slack', body);
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// xlsx_post_teams: outbound file-to-Teams. Same shape as Slack but with
|
|
1103
|
+
// Microsoft Graph fields (team_id + channel_id + graph_token).
|
|
1104
|
+
if (name === 'xlsx_post_teams') {
|
|
1105
|
+
const body = {
|
|
1106
|
+
file_b64: fileToB64(args.file_path),
|
|
1107
|
+
team_id: args.team_id,
|
|
1108
|
+
channel_id: args.channel_id,
|
|
1109
|
+
graph_token: args.graph_token,
|
|
1110
|
+
};
|
|
1111
|
+
if (args.message !== undefined) body.message = args.message;
|
|
1112
|
+
body.filename = args.filename || path.basename(args.file_path);
|
|
1113
|
+
return callTool('xlsx_post_teams', body);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1043
1116
|
// All other tools (list_sheets, schema, hyperlinks, conditional_formats,
|
|
1044
1117
|
// styles, etc.) — single-file relay. Forward any common option keys the
|
|
1045
1118
|
// 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.22.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": {
|