@softeria/ms-365-mcp-server 0.87.1 → 0.88.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.
@@ -14,6 +14,46 @@ export function createAndSaveSimplifiedOpenAPI(endpointsFile, openapiFile, opena
14
14
  }
15
15
  }
16
16
 
17
+ // Synthesize operations that the Graph REST API supports but are missing from
18
+ // Microsoft's published OpenAPI metadata (e.g. PATCH on range(address='{address}')
19
+ // for cell-value writes — documented in Excel API but not in the OpenAPI spec).
20
+ for (const endpoint of endpoints) {
21
+ const pathSpec = openApiSpec.paths[endpoint.pathPattern];
22
+ const methodLower = endpoint.method.toLowerCase();
23
+ if (pathSpec && !pathSpec[methodLower]) {
24
+ pathSpec[methodLower] = {
25
+ tags: ['drives.driveItem'],
26
+ summary: endpoint.llmTip || `${endpoint.toolName} (synthesized)`,
27
+ description: endpoint.llmTip || `${endpoint.toolName} (synthesized)`,
28
+ operationId: endpoint.toolName,
29
+ requestBody:
30
+ methodLower === 'get' || methodLower === 'delete'
31
+ ? undefined
32
+ : {
33
+ description: 'Operation payload',
34
+ required: true,
35
+ content: {
36
+ 'application/json': {
37
+ schema: { type: 'object', additionalProperties: true },
38
+ },
39
+ },
40
+ },
41
+ responses: {
42
+ '2XX': {
43
+ description: 'Success',
44
+ content: {
45
+ 'application/json': {
46
+ schema: { type: 'object', additionalProperties: true },
47
+ },
48
+ },
49
+ },
50
+ '4XX': { $ref: '#/components/responses/error' },
51
+ '5XX': { $ref: '#/components/responses/error' },
52
+ },
53
+ };
54
+ }
55
+ }
56
+
17
57
  for (const [key, value] of Object.entries(openApiSpec.paths)) {
18
58
  const e = endpoints.filter((ep) => ep.pathPattern === key);
19
59
  if (e.length === 0) {
@@ -556,6 +556,59 @@
556
556
  "scopes": ["Files.Read"],
557
557
  "skipEncoding": ["address"]
558
558
  },
559
+ {
560
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')",
561
+ "method": "patch",
562
+ "toolName": "update-excel-range",
563
+ "isExcelOp": true,
564
+ "scopes": ["Files.ReadWrite"],
565
+ "skipEncoding": ["address"],
566
+ "llmTip": "Set cell values, formulas, or number format on any range — does NOT require the worksheet to be a formal Excel table. Body: { values: [['v1','v2','v3']] } for a single row, or [['a','b'],['c','d']] for multi-row. Use this for append (target the next empty row's address, e.g. 'A172:H172'), update (target a single cell like 'H42'), or prepend-style edits (read existing, concatenate, write back). Number of inner-array values must match the column count of the address."
567
+ },
568
+ {
569
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/insert",
570
+ "method": "post",
571
+ "toolName": "insert-excel-range",
572
+ "isExcelOp": true,
573
+ "scopes": ["Files.ReadWrite"],
574
+ "skipEncoding": ["address"],
575
+ "llmTip": "Insert blank cells at the given range, shifting existing content. Body: { shift: 'Down' } or { shift: 'Right' }. Use 'Down' to insert blank rows above existing data."
576
+ },
577
+ {
578
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/delete",
579
+ "method": "post",
580
+ "toolName": "delete-excel-range",
581
+ "isExcelOp": true,
582
+ "scopes": ["Files.ReadWrite"],
583
+ "skipEncoding": ["address"],
584
+ "llmTip": "Delete cells at the given range, shifting remaining content. Body: { shift: 'Up' } or { shift: 'Left' }. Use 'Up' to delete entire rows."
585
+ },
586
+ {
587
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/tables/{workbookTable-id}/rows/itemAt(index={index})",
588
+ "method": "patch",
589
+ "toolName": "update-excel-table-row",
590
+ "isExcelOp": true,
591
+ "scopes": ["Files.ReadWrite"],
592
+ "skipEncoding": ["index"],
593
+ "llmTip": "Update a single row in a formal Excel table by zero-based row index. Body: { values: [[...]] } with one inner array matching the column count."
594
+ },
595
+ {
596
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/tables/{workbookTable-id}/rows/itemAt(index={index})",
597
+ "method": "delete",
598
+ "toolName": "delete-excel-table-row",
599
+ "isExcelOp": true,
600
+ "scopes": ["Files.ReadWrite"],
601
+ "skipEncoding": ["index"],
602
+ "llmTip": "Delete a single row from a formal Excel table by zero-based row index."
603
+ },
604
+ {
605
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/tables/add",
606
+ "method": "post",
607
+ "toolName": "create-excel-table",
608
+ "isExcelOp": true,
609
+ "scopes": ["Files.ReadWrite"],
610
+ "llmTip": "Convert a worksheet range into a formal Excel table. Body: { address: 'A1:H171', hasHeaders: true }. Required before using add-excel-table-rows / update-excel-table-row / delete-excel-table-row on a plain-cells sheet."
611
+ },
559
612
  {
560
613
  "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets",
561
614
  "method": "get",
@@ -1358,6 +1358,7 @@ const microsoft_graph_workbookRange = z.object({
1358
1358
  sort: microsoft_graph_workbookRangeSort.optional(),
1359
1359
  worksheet: microsoft_graph_workbookWorksheet.optional()
1360
1360
  }).passthrough();
1361
+ const create_excel_table_Body = z.object({ address: z.string().nullable(), hasHeaders: z.boolean().default(false) }).partial().passthrough();
1361
1362
  const microsoft_graph_assignedLabel = z.object({
1362
1363
  displayName: z.string().describe("The display name of the label. Read-only.").nullish(),
1363
1364
  labelId: z.string().describe("The unique identifier of the label.").nullish()
@@ -4461,6 +4462,7 @@ const schemas = {
4461
4462
  microsoft_graph_workbookRangeFormat,
4462
4463
  microsoft_graph_workbookRangeSort,
4463
4464
  microsoft_graph_workbookRange,
4465
+ create_excel_table_Body,
4464
4466
  microsoft_graph_assignedLabel,
4465
4467
  microsoft_graph_licenseProcessingState,
4466
4468
  microsoft_graph_group,
@@ -5737,6 +5739,30 @@ Items with this property set should be removed from your local state.`,
5737
5739
  ],
5738
5740
  response: z.void()
5739
5741
  },
5742
+ {
5743
+ method: "patch",
5744
+ path: "/drives/:driveId/items/:driveItemId/workbook/tables/:workbookTableId/rows/itemAt(index=:index)",
5745
+ alias: "update-excel-table-row",
5746
+ description: `Update a single row in a formal Excel table by zero-based row index. Body: { values: [[...]] } with one inner array matching the column count.`,
5747
+ requestFormat: "json",
5748
+ parameters: [
5749
+ {
5750
+ name: "body",
5751
+ description: `Operation payload`,
5752
+ type: "Body",
5753
+ schema: z.object({}).partial().passthrough().passthrough()
5754
+ }
5755
+ ],
5756
+ response: z.void()
5757
+ },
5758
+ {
5759
+ method: "delete",
5760
+ path: "/drives/:driveId/items/:driveItemId/workbook/tables/:workbookTableId/rows/itemAt(index=:index)",
5761
+ alias: "delete-excel-table-row",
5762
+ description: `Delete a single row from a formal Excel table by zero-based row index.`,
5763
+ requestFormat: "json",
5764
+ response: z.void()
5765
+ },
5740
5766
  {
5741
5767
  method: "get",
5742
5768
  path: "/drives/:driveId/items/:driveItemId/workbook/worksheets",
@@ -5845,6 +5871,70 @@ Items with this property set should be removed from your local state.`,
5845
5871
  requestFormat: "json",
5846
5872
  response: z.void()
5847
5873
  },
5874
+ {
5875
+ method: "patch",
5876
+ path: `/drives/:driveId/items/:driveItemId/workbook/worksheets/:workbookWorksheetId/range(address=':address')`,
5877
+ alias: "update-excel-range",
5878
+ description: `Set cell values, formulas, or number format on any range \u2014 does NOT require the worksheet to be a formal Excel table. Body: { values: [['v1','v2','v3']] } for a single row, or [['a','b'],['c','d']] for multi-row. Use this for append (target the next empty row's address, e.g. 'A172:H172'), update (target a single cell like 'H42'), or prepend-style edits (read existing, concatenate, write back). Number of inner-array values must match the column count of the address.`,
5879
+ requestFormat: "json",
5880
+ parameters: [
5881
+ {
5882
+ name: "body",
5883
+ description: `Operation payload`,
5884
+ type: "Body",
5885
+ schema: z.object({}).partial().passthrough().passthrough()
5886
+ }
5887
+ ],
5888
+ response: z.void()
5889
+ },
5890
+ {
5891
+ method: "post",
5892
+ path: `/drives/:driveId/items/:driveItemId/workbook/worksheets/:workbookWorksheetId/range(address=':address')/delete`,
5893
+ alias: "delete-excel-range",
5894
+ description: `Invoke action delete`,
5895
+ requestFormat: "json",
5896
+ parameters: [
5897
+ {
5898
+ name: "body",
5899
+ description: `Action parameters`,
5900
+ type: "Body",
5901
+ schema: z.object({ shift: z.string() }).partial().passthrough()
5902
+ }
5903
+ ],
5904
+ response: z.void()
5905
+ },
5906
+ {
5907
+ method: "post",
5908
+ path: `/drives/:driveId/items/:driveItemId/workbook/worksheets/:workbookWorksheetId/range(address=':address')/insert`,
5909
+ alias: "insert-excel-range",
5910
+ description: `Invoke action insert`,
5911
+ requestFormat: "json",
5912
+ parameters: [
5913
+ {
5914
+ name: "body",
5915
+ description: `Action parameters`,
5916
+ type: "Body",
5917
+ schema: z.object({ shift: z.string() }).partial().passthrough()
5918
+ }
5919
+ ],
5920
+ response: z.void()
5921
+ },
5922
+ {
5923
+ method: "post",
5924
+ path: "/drives/:driveId/items/:driveItemId/workbook/worksheets/:workbookWorksheetId/tables/add",
5925
+ alias: "create-excel-table",
5926
+ description: `Create a new table. The range source address determines the worksheet under which the table will be added. If the table can't be added (for example, because the address is invalid, or the table would overlap with another table), an error is generated.`,
5927
+ requestFormat: "json",
5928
+ parameters: [
5929
+ {
5930
+ name: "body",
5931
+ description: `Action parameters`,
5932
+ type: "Body",
5933
+ schema: create_excel_table_Body
5934
+ }
5935
+ ],
5936
+ response: z.void()
5937
+ },
5848
5938
  {
5849
5939
  method: "get",
5850
5940
  path: "/drives/:driveId/root",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softeria/ms-365-mcp-server",
3
- "version": "0.87.1",
3
+ "version": "0.88.0",
4
4
  "description": " A Model Context Protocol (MCP) server for interacting with Microsoft 365 and Office services through the Graph API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -556,6 +556,59 @@
556
556
  "scopes": ["Files.Read"],
557
557
  "skipEncoding": ["address"]
558
558
  },
559
+ {
560
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')",
561
+ "method": "patch",
562
+ "toolName": "update-excel-range",
563
+ "isExcelOp": true,
564
+ "scopes": ["Files.ReadWrite"],
565
+ "skipEncoding": ["address"],
566
+ "llmTip": "Set cell values, formulas, or number format on any range — does NOT require the worksheet to be a formal Excel table. Body: { values: [['v1','v2','v3']] } for a single row, or [['a','b'],['c','d']] for multi-row. Use this for append (target the next empty row's address, e.g. 'A172:H172'), update (target a single cell like 'H42'), or prepend-style edits (read existing, concatenate, write back). Number of inner-array values must match the column count of the address."
567
+ },
568
+ {
569
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/insert",
570
+ "method": "post",
571
+ "toolName": "insert-excel-range",
572
+ "isExcelOp": true,
573
+ "scopes": ["Files.ReadWrite"],
574
+ "skipEncoding": ["address"],
575
+ "llmTip": "Insert blank cells at the given range, shifting existing content. Body: { shift: 'Down' } or { shift: 'Right' }. Use 'Down' to insert blank rows above existing data."
576
+ },
577
+ {
578
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/delete",
579
+ "method": "post",
580
+ "toolName": "delete-excel-range",
581
+ "isExcelOp": true,
582
+ "scopes": ["Files.ReadWrite"],
583
+ "skipEncoding": ["address"],
584
+ "llmTip": "Delete cells at the given range, shifting remaining content. Body: { shift: 'Up' } or { shift: 'Left' }. Use 'Up' to delete entire rows."
585
+ },
586
+ {
587
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/tables/{workbookTable-id}/rows/itemAt(index={index})",
588
+ "method": "patch",
589
+ "toolName": "update-excel-table-row",
590
+ "isExcelOp": true,
591
+ "scopes": ["Files.ReadWrite"],
592
+ "skipEncoding": ["index"],
593
+ "llmTip": "Update a single row in a formal Excel table by zero-based row index. Body: { values: [[...]] } with one inner array matching the column count."
594
+ },
595
+ {
596
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/tables/{workbookTable-id}/rows/itemAt(index={index})",
597
+ "method": "delete",
598
+ "toolName": "delete-excel-table-row",
599
+ "isExcelOp": true,
600
+ "scopes": ["Files.ReadWrite"],
601
+ "skipEncoding": ["index"],
602
+ "llmTip": "Delete a single row from a formal Excel table by zero-based row index."
603
+ },
604
+ {
605
+ "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/tables/add",
606
+ "method": "post",
607
+ "toolName": "create-excel-table",
608
+ "isExcelOp": true,
609
+ "scopes": ["Files.ReadWrite"],
610
+ "llmTip": "Convert a worksheet range into a formal Excel table. Body: { address: 'A1:H171', hasHeaders: true }. Required before using add-excel-table-rows / update-excel-table-row / delete-excel-table-row on a plain-cells sheet."
611
+ },
559
612
  {
560
613
  "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets",
561
614
  "method": "get",