@makeshkumar/mcp-xl-reader 1.0.1 → 1.0.3

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/dist/index.js +110 -29
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -133,13 +133,12 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
133
133
  },
134
134
  {
135
135
  name: "find_excel_files",
136
- description: "Finds all .xlsx files in a given directory.",
136
+ description: "Finds all .xlsx files in a given directory. If directoryPath is omitted, it automatically searches the allowed directories or current working directory.",
137
137
  inputSchema: {
138
138
  type: "object",
139
139
  properties: {
140
- directoryPath: { type: "string", description: "Absolute path to the directory to search." }
141
- },
142
- required: ["directoryPath"]
140
+ directoryPath: { type: "string", description: "Absolute path to the directory to search (optional)." }
141
+ }
143
142
  }
144
143
  },
145
144
  {
@@ -183,6 +182,34 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
183
182
  },
184
183
  required: ["filePath", "cellAddress", "newValue"]
185
184
  }
185
+ },
186
+ {
187
+ name: "add_worksheet_with_data",
188
+ description: "Creates a new worksheet in an existing workbook and populates it with an array of JSON rows. Great for generating summary reports.",
189
+ inputSchema: {
190
+ type: "object",
191
+ properties: {
192
+ filePath: { type: "string" },
193
+ sheetName: { type: "string", description: "Name of the new sheet to create." },
194
+ columns: {
195
+ type: "array",
196
+ items: {
197
+ type: "object",
198
+ properties: {
199
+ header: { type: "string" },
200
+ key: { type: "string" }
201
+ }
202
+ },
203
+ description: "Array of column definitions, e.g., [{header: 'Name', key: 'name'}]"
204
+ },
205
+ rows: {
206
+ type: "array",
207
+ items: { type: "object" },
208
+ description: "Array of JSON objects representing the rows to insert."
209
+ }
210
+ },
211
+ required: ["filePath", "sheetName", "columns", "rows"]
212
+ }
186
213
  }
187
214
  ]
188
215
  };
@@ -195,15 +222,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
195
222
  content: [{ type: "text", text: "Invalid arguments provided." }]
196
223
  };
197
224
  }
198
- if (name === "find_excel_files") {
199
- if (!args.directoryPath) {
200
- return {
201
- isError: true,
202
- content: [{ type: "text", text: "Missing required directoryPath parameter." }]
203
- };
204
- }
205
- }
206
- else {
225
+ if (name !== "find_excel_files") {
207
226
  if (!args.filePath) {
208
227
  return {
209
228
  isError: true,
@@ -211,12 +230,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
211
230
  };
212
231
  }
213
232
  }
214
- let absolutePath;
233
+ let absolutePath = "";
215
234
  try {
216
- if (name === "find_excel_files") {
217
- absolutePath = await validateDirectoryPath(args.directoryPath);
218
- }
219
- else {
235
+ if (name !== "find_excel_files") {
220
236
  absolutePath = await validateFilePath(args.filePath);
221
237
  }
222
238
  }
@@ -230,18 +246,52 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
230
246
  const workbook = new ExcelJS.Workbook();
231
247
  switch (name) {
232
248
  case "find_excel_files": {
233
- // Read all files recursively in the given directory
234
- const files = await fs.readdir(absolutePath, { recursive: true, withFileTypes: true });
235
- const excelFiles = files
236
- .filter(dirent => dirent.isFile() && dirent.name.toLowerCase().endsWith('.xlsx'))
237
- // fs.readdir with recursive=true returns relative paths in dirent.name or dirent.parentPath
238
- .map(dirent => {
239
- const d = dirent;
240
- const parentPath = d.parentPath || d.path || absolutePath;
241
- return path.resolve(parentPath, dirent.name);
242
- });
249
+ let directoriesToSearch = [];
250
+ if (args && args.directoryPath) {
251
+ directoriesToSearch.push(await validateDirectoryPath(args.directoryPath));
252
+ }
253
+ else {
254
+ const allowedDirectories = process.env.ALLOWED_DIRECTORIES ? process.env.ALLOWED_DIRECTORIES.split(',') : [];
255
+ if (allowedDirectories.length > 0) {
256
+ for (const dir of allowedDirectories) {
257
+ try {
258
+ directoriesToSearch.push(await validateDirectoryPath(dir.trim()));
259
+ }
260
+ catch (e) {
261
+ // ignore invalid ones
262
+ }
263
+ }
264
+ }
265
+ else {
266
+ // fallback to current working directory
267
+ directoriesToSearch.push(process.cwd());
268
+ }
269
+ }
270
+ if (directoriesToSearch.length === 0) {
271
+ return {
272
+ isError: true,
273
+ content: [{ type: "text", text: "No valid directories to search." }]
274
+ };
275
+ }
276
+ const allExcelFiles = [];
277
+ for (const dir of directoriesToSearch) {
278
+ try {
279
+ const files = await fs.readdir(dir, { recursive: true, withFileTypes: true });
280
+ const excelFiles = files
281
+ .filter(dirent => dirent.isFile() && dirent.name.toLowerCase().endsWith('.xlsx'))
282
+ .map(dirent => {
283
+ const d = dirent;
284
+ const parentPath = d.parentPath || d.path || dir;
285
+ return path.resolve(parentPath, dirent.name);
286
+ });
287
+ allExcelFiles.push(...excelFiles);
288
+ }
289
+ catch (e) {
290
+ // Skip if one directory fails
291
+ }
292
+ }
243
293
  return {
244
- content: [{ type: "text", text: JSON.stringify(excelFiles, null, 2) }]
294
+ content: [{ type: "text", text: JSON.stringify(allExcelFiles, null, 2) }]
245
295
  };
246
296
  }
247
297
  case "list_sheets": {
@@ -376,6 +426,37 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
376
426
  content: [{ type: "text", text: `Successfully updated cell ${cellAddress} to ${newValue}` }]
377
427
  };
378
428
  }
429
+ case "add_worksheet_with_data": {
430
+ const { sheetName, columns, rows } = args;
431
+ await workbook.xlsx.readFile(absolutePath);
432
+ // Check if sheet exists to avoid crashing
433
+ if (workbook.getWorksheet(sheetName)) {
434
+ throw new Error(`A worksheet named '${sheetName}' already exists in this file.`);
435
+ }
436
+ const ws = workbook.addWorksheet(sheetName);
437
+ // Set columns
438
+ if (Array.isArray(columns)) {
439
+ ws.columns = columns.map(col => ({
440
+ header: col.header,
441
+ key: col.key,
442
+ width: 20 // Default reasonable width
443
+ }));
444
+ }
445
+ // Add data rows
446
+ if (Array.isArray(rows)) {
447
+ rows.forEach(rowData => {
448
+ ws.addRow(rowData);
449
+ });
450
+ }
451
+ // Make the header bold to look professional
452
+ const headerRow = ws.getRow(1);
453
+ headerRow.font = { bold: true };
454
+ headerRow.commit();
455
+ await workbook.xlsx.writeFile(absolutePath);
456
+ return {
457
+ content: [{ type: "text", text: `Successfully generated new reporting sheet '${sheetName}' with ${rows.length} rows of data and saved it to the file.` }]
458
+ };
459
+ }
379
460
  default:
380
461
  throw new Error(`Unknown tool: ${name}`);
381
462
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makeshkumar/mcp-xl-reader",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "scripts": {