@softeria/ms-365-mcp-server 0.131.2 → 0.132.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/dist/endpoints.json +100 -3
- package/dist/generated/client.js +169 -4
- package/dist/normalize-tool-schema.js +112 -0
- package/dist/server.js +2 -0
- package/package.json +1 -1
- package/src/endpoints.json +100 -3
package/dist/endpoints.json
CHANGED
|
@@ -702,7 +702,102 @@
|
|
|
702
702
|
"isExcelOp": true,
|
|
703
703
|
"scopes": ["Files.ReadWrite"],
|
|
704
704
|
"skipEncoding": ["address"],
|
|
705
|
-
"llmTip": "Apply rangeFormat properties to a specific range. Required path param 'address' (e.g. 'A1:E5' or 'Sheet1!A1:E5'). Body: { horizontalAlignment, verticalAlignment, wrapText, columnWidth, rowHeight }.
|
|
705
|
+
"llmTip": "Apply rangeFormat properties to a specific range. Required path param 'address' (e.g. 'A1:E5' or 'Sheet1!A1:E5'). Body: { horizontalAlignment, verticalAlignment, wrapText, columnWidth, rowHeight }. Font, fill, and borders are NOT set here; use format-excel-range-font, format-excel-range-fill, and format-excel-range-border for those."
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/format",
|
|
709
|
+
"method": "get",
|
|
710
|
+
"toolName": "get-excel-range-format",
|
|
711
|
+
"presets": ["excel", "personal"],
|
|
712
|
+
"isExcelOp": true,
|
|
713
|
+
"scopes": ["Files.Read"],
|
|
714
|
+
"skipEncoding": ["address"],
|
|
715
|
+
"llmTip": "Reads a range's format: alignment, wrapText, columnWidth, rowHeight. Font, fill, and borders are nested and omitted by default; add font, fill, and borders to the $expand parameter to include them in one call. Cell styling often encodes meaning (a fill or font color flagging status such as tentative or reconciled), so expand these to interpret what the cells mean."
|
|
716
|
+
},
|
|
717
|
+
{
|
|
718
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/format/font",
|
|
719
|
+
"method": "patch",
|
|
720
|
+
"toolName": "format-excel-range-font",
|
|
721
|
+
"presets": ["excel", "personal"],
|
|
722
|
+
"isExcelOp": true,
|
|
723
|
+
"scopes": ["Files.ReadWrite"],
|
|
724
|
+
"skipEncoding": ["address"],
|
|
725
|
+
"llmTip": "Set font formatting on a range: bold, italic, underline, size, color, and font name.",
|
|
726
|
+
"requestBodySchema": {
|
|
727
|
+
"type": "object",
|
|
728
|
+
"description": "Font style applied to every cell in the range. Send only the properties you want to change.",
|
|
729
|
+
"properties": {
|
|
730
|
+
"bold": { "type": "boolean" },
|
|
731
|
+
"italic": { "type": "boolean" },
|
|
732
|
+
"underline": {
|
|
733
|
+
"type": "string",
|
|
734
|
+
"enum": ["None", "Single", "Double", "SingleAccountant", "DoubleAccountant"]
|
|
735
|
+
},
|
|
736
|
+
"size": { "type": "number", "description": "Font size in points." },
|
|
737
|
+
"color": {
|
|
738
|
+
"type": "string",
|
|
739
|
+
"description": "HTML color code for the text, e.g. #FF0000 or a named color like 'red'."
|
|
740
|
+
},
|
|
741
|
+
"name": { "type": "string", "description": "Font name, e.g. 'Calibri'." }
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/format/fill",
|
|
747
|
+
"method": "patch",
|
|
748
|
+
"toolName": "format-excel-range-fill",
|
|
749
|
+
"presets": ["excel", "personal"],
|
|
750
|
+
"isExcelOp": true,
|
|
751
|
+
"scopes": ["Files.ReadWrite"],
|
|
752
|
+
"skipEncoding": ["address"],
|
|
753
|
+
"llmTip": "Set the background fill color of a range's cells.",
|
|
754
|
+
"requestBodySchema": {
|
|
755
|
+
"type": "object",
|
|
756
|
+
"description": "Background fill applied to every cell in the range.",
|
|
757
|
+
"properties": {
|
|
758
|
+
"color": {
|
|
759
|
+
"type": "string",
|
|
760
|
+
"description": "HTML color code for the background, e.g. #FFFF00 or a named color like 'yellow'."
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/format/borders/{sideIndex}",
|
|
767
|
+
"method": "patch",
|
|
768
|
+
"toolName": "format-excel-range-border",
|
|
769
|
+
"presets": ["excel"],
|
|
770
|
+
"isExcelOp": true,
|
|
771
|
+
"scopes": ["Files.ReadWrite"],
|
|
772
|
+
"skipEncoding": ["address"],
|
|
773
|
+
"llmTip": "Sets one border side. The {sideIndex} path param selects which side: EdgeTop, EdgeBottom, EdgeLeft, EdgeRight, InsideVertical, InsideHorizontal, DiagonalDown, or DiagonalUp. To outline all four edges, call once per side.",
|
|
774
|
+
"requestBodySchema": {
|
|
775
|
+
"type": "object",
|
|
776
|
+
"description": "Line style for the chosen border side.",
|
|
777
|
+
"properties": {
|
|
778
|
+
"style": {
|
|
779
|
+
"type": "string",
|
|
780
|
+
"enum": [
|
|
781
|
+
"None",
|
|
782
|
+
"Continuous",
|
|
783
|
+
"Dash",
|
|
784
|
+
"DashDot",
|
|
785
|
+
"DashDotDot",
|
|
786
|
+
"Dot",
|
|
787
|
+
"Double",
|
|
788
|
+
"SlantDashDot"
|
|
789
|
+
]
|
|
790
|
+
},
|
|
791
|
+
"weight": {
|
|
792
|
+
"type": "string",
|
|
793
|
+
"enum": ["Hairline", "Thin", "Medium", "Thick"]
|
|
794
|
+
},
|
|
795
|
+
"color": {
|
|
796
|
+
"type": "string",
|
|
797
|
+
"description": "HTML color code for the line, e.g. #000000 or a named color like 'black'."
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
706
801
|
},
|
|
707
802
|
{
|
|
708
803
|
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range()/sort",
|
|
@@ -1100,14 +1195,16 @@
|
|
|
1100
1195
|
"method": "post",
|
|
1101
1196
|
"toolName": "create-todo-task",
|
|
1102
1197
|
"presets": ["personal", "tasks"],
|
|
1103
|
-
"scopes": ["Tasks.ReadWrite"]
|
|
1198
|
+
"scopes": ["Tasks.ReadWrite"],
|
|
1199
|
+
"llmTip": "Creates a new task in a Microsoft To Do list. Body: { title: \"...\" }; optional dueDateTime, reminderDateTime, importance, body (notes), recurrence, categories. Requires todoTaskListId from list-todo-task-lists."
|
|
1104
1200
|
},
|
|
1105
1201
|
{
|
|
1106
1202
|
"pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}",
|
|
1107
1203
|
"method": "patch",
|
|
1108
1204
|
"toolName": "update-todo-task",
|
|
1109
1205
|
"presets": ["personal", "tasks"],
|
|
1110
|
-
"scopes": ["Tasks.ReadWrite"]
|
|
1206
|
+
"scopes": ["Tasks.ReadWrite"],
|
|
1207
|
+
"llmTip": "Updates a Microsoft To Do task. Use this to mark a to-do item complete or done (body: { status: \"completed\" }), reopen it (status: \"notStarted\"), rename it (title), or change its due date (dueDateTime), reminder (reminderDateTime), importance, or notes (body). Requires todoTaskListId from list-todo-task-lists and todoTaskId from list-todo-tasks."
|
|
1111
1208
|
},
|
|
1112
1209
|
{
|
|
1113
1210
|
"pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}",
|
package/dist/generated/client.js
CHANGED
|
@@ -2593,6 +2593,7 @@ const microsoft_graph_listItem = z.object({
|
|
|
2593
2593
|
documentSetVersions: z.array(microsoft_graph_documentSetVersion).describe("Version information for a document set version created by a user.").optional(),
|
|
2594
2594
|
driveItem: microsoft_graph_driveItem.describe("[Note: Simplified from 45 properties to 25 most common ones]").optional(),
|
|
2595
2595
|
fields: microsoft_graph_fieldValueSet.optional(),
|
|
2596
|
+
permissions: z.array(microsoft_graph_permission).optional(),
|
|
2596
2597
|
versions: z.array(microsoft_graph_listItemVersion).describe("The list of previous versions of the list item.").optional()
|
|
2597
2598
|
}).passthrough();
|
|
2598
2599
|
const microsoft_graph_longRunningOperationStatus = z.enum([
|
|
@@ -2716,6 +2717,7 @@ const microsoft_graph_list = z.lazy(
|
|
|
2716
2717
|
drive: microsoft_graph_drive.optional(),
|
|
2717
2718
|
items: z.array(microsoft_graph_listItem).describe("All items contained in the list.").optional(),
|
|
2718
2719
|
operations: z.array(microsoft_graph_richLongRunningOperation).describe("The collection of long-running operations on the list.").optional(),
|
|
2720
|
+
permissions: z.array(microsoft_graph_permission).optional(),
|
|
2719
2721
|
subscriptions: z.array(microsoft_graph_subscription).describe("The set of subscriptions on the list.").optional()
|
|
2720
2722
|
}).passthrough()
|
|
2721
2723
|
);
|
|
@@ -4160,6 +4162,7 @@ const microsoft_graph_place = z.object({
|
|
|
4160
4162
|
label: z.string().describe("User-defined description of the place.").nullish(),
|
|
4161
4163
|
parentId: z.string().describe("The ID of a parent place.").nullish(),
|
|
4162
4164
|
phone: z.string().describe("The phone number of the place.").nullish(),
|
|
4165
|
+
placeId: z.string().describe("A stable service-level identifier for the place object used by Places workloads.").nullish(),
|
|
4163
4166
|
tags: z.array(z.string()).describe("Custom tags that are associated with the place for categorization or filtering.").optional(),
|
|
4164
4167
|
checkIns: z.array(microsoft_graph_checkInClaim).describe(
|
|
4165
4168
|
"A subresource of a place object that indicates the check-in status of an Outlook calendar event booked at the place."
|
|
@@ -4181,6 +4184,7 @@ const microsoft_graph_room = z.object({
|
|
|
4181
4184
|
label: z.string().describe("User-defined description of the place.").nullish(),
|
|
4182
4185
|
parentId: z.string().describe("The ID of a parent place.").nullish(),
|
|
4183
4186
|
phone: z.string().describe("The phone number of the place.").nullish(),
|
|
4187
|
+
placeId: z.string().describe("A stable service-level identifier for the place object used by Places workloads.").nullish(),
|
|
4184
4188
|
tags: z.array(z.string()).describe("Custom tags that are associated with the place for categorization or filtering.").optional(),
|
|
4185
4189
|
checkIns: z.array(microsoft_graph_checkInClaim).describe(
|
|
4186
4190
|
"A subresource of a place object that indicates the check-in status of an Outlook calendar event booked at the place."
|
|
@@ -4194,7 +4198,6 @@ const microsoft_graph_room = z.object({
|
|
|
4194
4198
|
floorLabel: z.string().describe("Specifies a descriptive label for the floor, for example, P.").nullish(),
|
|
4195
4199
|
floorNumber: z.number().gte(-2147483648).lte(2147483647).describe("Specifies the floor number that the room is on.").nullish(),
|
|
4196
4200
|
nickname: z.string().describe("Specifies a nickname for the room, for example, 'conf room'.").optional(),
|
|
4197
|
-
placeId: z.string().describe("An alternative immutable unique identifier of the room. Read-only.").nullish(),
|
|
4198
4201
|
teamsEnabledState: microsoft_graph_placeFeatureEnablement.optional(),
|
|
4199
4202
|
videoDeviceName: z.string().describe("Specifies the name of the video device in the room.").nullish()
|
|
4200
4203
|
}).passthrough();
|
|
@@ -4208,6 +4211,7 @@ const microsoft_graph_workspace = z.object({
|
|
|
4208
4211
|
label: z.string().describe("User-defined description of the place.").nullish(),
|
|
4209
4212
|
parentId: z.string().describe("The ID of a parent place.").nullish(),
|
|
4210
4213
|
phone: z.string().describe("The phone number of the place.").nullish(),
|
|
4214
|
+
placeId: z.string().describe("A stable service-level identifier for the place object used by Places workloads.").nullish(),
|
|
4211
4215
|
tags: z.array(z.string()).describe("Custom tags that are associated with the place for categorization or filtering.").optional(),
|
|
4212
4216
|
checkIns: z.array(microsoft_graph_checkInClaim).describe(
|
|
4213
4217
|
"A subresource of a place object that indicates the check-in status of an Outlook calendar event booked at the place."
|
|
@@ -4222,8 +4226,7 @@ const microsoft_graph_workspace = z.object({
|
|
|
4222
4226
|
mode: microsoft_graph_placeMode.optional(),
|
|
4223
4227
|
nickname: z.string().describe(
|
|
4224
4228
|
"A short, friendly name for the workspace, often used for easier identification or display in the UI."
|
|
4225
|
-
).optional()
|
|
4226
|
-
placeId: z.string().describe("An alternative immutable unique identifier of the workspace. Read-only.").nullish()
|
|
4229
|
+
).optional()
|
|
4227
4230
|
}).passthrough();
|
|
4228
4231
|
const microsoft_graph_roomList = z.object({
|
|
4229
4232
|
id: z.string().describe("The unique identifier for an entity. Read-only.").optional(),
|
|
@@ -4234,6 +4237,7 @@ const microsoft_graph_roomList = z.object({
|
|
|
4234
4237
|
label: z.string().describe("User-defined description of the place.").nullish(),
|
|
4235
4238
|
parentId: z.string().describe("The ID of a parent place.").nullish(),
|
|
4236
4239
|
phone: z.string().describe("The phone number of the place.").nullish(),
|
|
4240
|
+
placeId: z.string().describe("A stable service-level identifier for the place object used by Places workloads.").nullish(),
|
|
4237
4241
|
tags: z.array(z.string()).describe("Custom tags that are associated with the place for categorization or filtering.").optional(),
|
|
4238
4242
|
checkIns: z.array(microsoft_graph_checkInClaim).describe(
|
|
4239
4243
|
"A subresource of a place object that indicates the check-in status of an Outlook calendar event booked at the place."
|
|
@@ -4814,6 +4818,28 @@ const microsoft_graph_userCollectionResponse = z.object({
|
|
|
4814
4818
|
"@odata.nextLink": z.string().nullable(),
|
|
4815
4819
|
value: z.array(microsoft_graph_user)
|
|
4816
4820
|
}).partial().passthrough();
|
|
4821
|
+
const format_excel_range_font_Body = z.object({
|
|
4822
|
+
bold: z.boolean(),
|
|
4823
|
+
italic: z.boolean(),
|
|
4824
|
+
underline: z.enum(["None", "Single", "Double", "SingleAccountant", "DoubleAccountant"]),
|
|
4825
|
+
size: z.number().describe("Font size in points."),
|
|
4826
|
+
color: z.string().describe("HTML color code for the text, e.g. #FF0000 or a named color like 'red'."),
|
|
4827
|
+
name: z.string().describe("Font name, e.g. 'Calibri'.")
|
|
4828
|
+
}).partial().passthrough();
|
|
4829
|
+
const format_excel_range_border_Body = z.object({
|
|
4830
|
+
style: z.enum([
|
|
4831
|
+
"None",
|
|
4832
|
+
"Continuous",
|
|
4833
|
+
"Dash",
|
|
4834
|
+
"DashDot",
|
|
4835
|
+
"DashDotDot",
|
|
4836
|
+
"Dot",
|
|
4837
|
+
"Double",
|
|
4838
|
+
"SlantDashDot"
|
|
4839
|
+
]),
|
|
4840
|
+
weight: z.enum(["Hairline", "Thin", "Medium", "Thick"]),
|
|
4841
|
+
color: z.string().describe("HTML color code for the line, e.g. #000000 or a named color like 'black'.")
|
|
4842
|
+
}).partial().passthrough();
|
|
4817
4843
|
const schemas = {
|
|
4818
4844
|
microsoft_graph_chatType,
|
|
4819
4845
|
microsoft_graph_migrationMode,
|
|
@@ -5319,7 +5345,9 @@ const schemas = {
|
|
|
5319
5345
|
microsoft_graph_subscriptionCollectionResponse,
|
|
5320
5346
|
microsoft_graph_channelCollectionResponse,
|
|
5321
5347
|
microsoft_graph_teamsTabCollectionResponse,
|
|
5322
|
-
microsoft_graph_userCollectionResponse
|
|
5348
|
+
microsoft_graph_userCollectionResponse,
|
|
5349
|
+
format_excel_range_font_Body,
|
|
5350
|
+
format_excel_range_border_Body
|
|
5323
5351
|
};
|
|
5324
5352
|
const endpoints = makeApi([
|
|
5325
5353
|
{
|
|
@@ -6658,6 +6686,26 @@ Items with this property set should be removed from your local state.`,
|
|
|
6658
6686
|
],
|
|
6659
6687
|
response: z.void()
|
|
6660
6688
|
},
|
|
6689
|
+
{
|
|
6690
|
+
method: "get",
|
|
6691
|
+
path: `/drives/:driveId/items/:driveItemId/workbook/worksheets/:workbookWorksheetId/range(address=':address')/format`,
|
|
6692
|
+
alias: "get-excel-range-format",
|
|
6693
|
+
description: `Returns a format object, encapsulating the range's font, fill, borders, alignment, and other properties. Read-only.`,
|
|
6694
|
+
requestFormat: "json",
|
|
6695
|
+
parameters: [
|
|
6696
|
+
{
|
|
6697
|
+
name: "$select",
|
|
6698
|
+
type: "Query",
|
|
6699
|
+
schema: z.array(z.string()).describe("Select properties to be returned").optional()
|
|
6700
|
+
},
|
|
6701
|
+
{
|
|
6702
|
+
name: "$expand",
|
|
6703
|
+
type: "Query",
|
|
6704
|
+
schema: z.array(z.string()).describe("Expand related entities").optional()
|
|
6705
|
+
}
|
|
6706
|
+
],
|
|
6707
|
+
response: z.void()
|
|
6708
|
+
},
|
|
6661
6709
|
{
|
|
6662
6710
|
method: "patch",
|
|
6663
6711
|
path: `/drives/:driveId/items/:driveItemId/workbook/worksheets/:workbookWorksheetId/range(address=':address')/format`,
|
|
@@ -6674,6 +6722,123 @@ Items with this property set should be removed from your local state.`,
|
|
|
6674
6722
|
],
|
|
6675
6723
|
response: z.void()
|
|
6676
6724
|
},
|
|
6725
|
+
{
|
|
6726
|
+
method: "patch",
|
|
6727
|
+
path: `/drives/:driveId/items/:driveItemId/workbook/worksheets/:workbookWorksheetId/range(address=':address')/format/borders/:sideIndex`,
|
|
6728
|
+
alias: "format-excel-range-border",
|
|
6729
|
+
description: `Sets one border side. The {sideIndex} path param selects which side: EdgeTop, EdgeBottom, EdgeLeft, EdgeRight, InsideVertical, InsideHorizontal, DiagonalDown, or DiagonalUp. To outline all four edges, call once per side.`,
|
|
6730
|
+
requestFormat: "json",
|
|
6731
|
+
parameters: [
|
|
6732
|
+
{
|
|
6733
|
+
name: "body",
|
|
6734
|
+
description: `Operation payload`,
|
|
6735
|
+
type: "Body",
|
|
6736
|
+
schema: format_excel_range_border_Body
|
|
6737
|
+
},
|
|
6738
|
+
{
|
|
6739
|
+
name: "driveId",
|
|
6740
|
+
type: "Path",
|
|
6741
|
+
schema: z.string().describe("Path parameter: drive-id")
|
|
6742
|
+
},
|
|
6743
|
+
{
|
|
6744
|
+
name: "driveItemId",
|
|
6745
|
+
type: "Path",
|
|
6746
|
+
schema: z.string().describe("Path parameter: driveItem-id")
|
|
6747
|
+
},
|
|
6748
|
+
{
|
|
6749
|
+
name: "workbookWorksheetId",
|
|
6750
|
+
type: "Path",
|
|
6751
|
+
schema: z.string().describe("Path parameter: workbookWorksheet-id")
|
|
6752
|
+
},
|
|
6753
|
+
{
|
|
6754
|
+
name: "address",
|
|
6755
|
+
type: "Path",
|
|
6756
|
+
schema: z.string().describe("Path parameter: address")
|
|
6757
|
+
},
|
|
6758
|
+
{
|
|
6759
|
+
name: "sideIndex",
|
|
6760
|
+
type: "Path",
|
|
6761
|
+
schema: z.string().describe("Path parameter: sideIndex")
|
|
6762
|
+
}
|
|
6763
|
+
],
|
|
6764
|
+
response: z.void()
|
|
6765
|
+
},
|
|
6766
|
+
{
|
|
6767
|
+
method: "patch",
|
|
6768
|
+
path: `/drives/:driveId/items/:driveItemId/workbook/worksheets/:workbookWorksheetId/range(address=':address')/format/fill`,
|
|
6769
|
+
alias: "format-excel-range-fill",
|
|
6770
|
+
description: `Set the background fill color of a range's cells.`,
|
|
6771
|
+
requestFormat: "json",
|
|
6772
|
+
parameters: [
|
|
6773
|
+
{
|
|
6774
|
+
name: "body",
|
|
6775
|
+
description: `Operation payload`,
|
|
6776
|
+
type: "Body",
|
|
6777
|
+
schema: z.object({
|
|
6778
|
+
color: z.string().describe(
|
|
6779
|
+
"HTML color code for the background, e.g. #FFFF00 or a named color like 'yellow'."
|
|
6780
|
+
)
|
|
6781
|
+
}).partial().passthrough()
|
|
6782
|
+
},
|
|
6783
|
+
{
|
|
6784
|
+
name: "driveId",
|
|
6785
|
+
type: "Path",
|
|
6786
|
+
schema: z.string().describe("Path parameter: drive-id")
|
|
6787
|
+
},
|
|
6788
|
+
{
|
|
6789
|
+
name: "driveItemId",
|
|
6790
|
+
type: "Path",
|
|
6791
|
+
schema: z.string().describe("Path parameter: driveItem-id")
|
|
6792
|
+
},
|
|
6793
|
+
{
|
|
6794
|
+
name: "workbookWorksheetId",
|
|
6795
|
+
type: "Path",
|
|
6796
|
+
schema: z.string().describe("Path parameter: workbookWorksheet-id")
|
|
6797
|
+
},
|
|
6798
|
+
{
|
|
6799
|
+
name: "address",
|
|
6800
|
+
type: "Path",
|
|
6801
|
+
schema: z.string().describe("Path parameter: address")
|
|
6802
|
+
}
|
|
6803
|
+
],
|
|
6804
|
+
response: z.void()
|
|
6805
|
+
},
|
|
6806
|
+
{
|
|
6807
|
+
method: "patch",
|
|
6808
|
+
path: `/drives/:driveId/items/:driveItemId/workbook/worksheets/:workbookWorksheetId/range(address=':address')/format/font`,
|
|
6809
|
+
alias: "format-excel-range-font",
|
|
6810
|
+
description: `Set font formatting on a range: bold, italic, underline, size, color, and font name.`,
|
|
6811
|
+
requestFormat: "json",
|
|
6812
|
+
parameters: [
|
|
6813
|
+
{
|
|
6814
|
+
name: "body",
|
|
6815
|
+
description: `Operation payload`,
|
|
6816
|
+
type: "Body",
|
|
6817
|
+
schema: format_excel_range_font_Body
|
|
6818
|
+
},
|
|
6819
|
+
{
|
|
6820
|
+
name: "driveId",
|
|
6821
|
+
type: "Path",
|
|
6822
|
+
schema: z.string().describe("Path parameter: drive-id")
|
|
6823
|
+
},
|
|
6824
|
+
{
|
|
6825
|
+
name: "driveItemId",
|
|
6826
|
+
type: "Path",
|
|
6827
|
+
schema: z.string().describe("Path parameter: driveItem-id")
|
|
6828
|
+
},
|
|
6829
|
+
{
|
|
6830
|
+
name: "workbookWorksheetId",
|
|
6831
|
+
type: "Path",
|
|
6832
|
+
schema: z.string().describe("Path parameter: workbookWorksheet-id")
|
|
6833
|
+
},
|
|
6834
|
+
{
|
|
6835
|
+
name: "address",
|
|
6836
|
+
type: "Path",
|
|
6837
|
+
schema: z.string().describe("Path parameter: address")
|
|
6838
|
+
}
|
|
6839
|
+
],
|
|
6840
|
+
response: z.void()
|
|
6841
|
+
},
|
|
6677
6842
|
{
|
|
6678
6843
|
method: "post",
|
|
6679
6844
|
path: `/drives/:driveId/items/:driveItemId/workbook/worksheets/:workbookWorksheetId/range(address=':address')/insert`,
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import logger from "./logger.js";
|
|
3
|
+
function unescapePointer(token) {
|
|
4
|
+
return token.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
5
|
+
}
|
|
6
|
+
function isBadRef(value) {
|
|
7
|
+
return typeof value === "string" && value.startsWith("#/") && !value.startsWith("#/$defs/");
|
|
8
|
+
}
|
|
9
|
+
function collectBadRefTargets(node, targets) {
|
|
10
|
+
if (!node || typeof node !== "object") return;
|
|
11
|
+
if (Array.isArray(node)) {
|
|
12
|
+
for (const item of node) collectBadRefTargets(item, targets);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
for (const [key, value] of Object.entries(node)) {
|
|
16
|
+
if (key === "$ref" && isBadRef(value)) {
|
|
17
|
+
targets.add(value.slice(1));
|
|
18
|
+
} else {
|
|
19
|
+
collectBadRefTargets(value, targets);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function resolvePointer(root, pointer) {
|
|
24
|
+
const tokens = pointer.split("/").slice(1).map(unescapePointer);
|
|
25
|
+
if (tokens.length === 0) return null;
|
|
26
|
+
let parent = null;
|
|
27
|
+
let key = "";
|
|
28
|
+
let cur = root;
|
|
29
|
+
for (const token of tokens) {
|
|
30
|
+
if (!cur || typeof cur !== "object") return null;
|
|
31
|
+
parent = cur;
|
|
32
|
+
key = Array.isArray(cur) ? Number(token) : token;
|
|
33
|
+
cur = cur[key];
|
|
34
|
+
if (cur === void 0) return null;
|
|
35
|
+
}
|
|
36
|
+
return parent === null ? null : { parent, key, obj: cur };
|
|
37
|
+
}
|
|
38
|
+
function repointRefs(node, nameFor) {
|
|
39
|
+
if (!node || typeof node !== "object") return;
|
|
40
|
+
if (Array.isArray(node)) {
|
|
41
|
+
for (const item of node) repointRefs(item, nameFor);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const record = node;
|
|
45
|
+
for (const [key, value] of Object.entries(record)) {
|
|
46
|
+
if (key === "$ref" && isBadRef(value)) {
|
|
47
|
+
const name = nameFor.get(value.slice(1));
|
|
48
|
+
if (name) record.$ref = `#/$defs/${name}`;
|
|
49
|
+
} else {
|
|
50
|
+
repointRefs(value, nameFor);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function normalizeToolSchemaRefs(schema) {
|
|
55
|
+
const targets = /* @__PURE__ */ new Set();
|
|
56
|
+
collectBadRefTargets(schema, targets);
|
|
57
|
+
if (targets.size === 0) return schema;
|
|
58
|
+
const clone = structuredClone(schema);
|
|
59
|
+
const slots = /* @__PURE__ */ new Map();
|
|
60
|
+
for (const pointer of [...targets].sort()) {
|
|
61
|
+
const slot = resolvePointer(clone, pointer);
|
|
62
|
+
if (slot) slots.set(pointer, slot);
|
|
63
|
+
}
|
|
64
|
+
if (slots.size === 0) return schema;
|
|
65
|
+
const takenNames = new Set(
|
|
66
|
+
clone.$defs && typeof clone.$defs === "object" ? Object.keys(clone.$defs) : []
|
|
67
|
+
);
|
|
68
|
+
const nameFor = /* @__PURE__ */ new Map();
|
|
69
|
+
let index = 0;
|
|
70
|
+
for (const pointer of slots.keys()) {
|
|
71
|
+
let name = `def${index++}`;
|
|
72
|
+
while (takenNames.has(name)) name = `def${index++}`;
|
|
73
|
+
takenNames.add(name);
|
|
74
|
+
nameFor.set(pointer, name);
|
|
75
|
+
}
|
|
76
|
+
const defs = {};
|
|
77
|
+
for (const [pointer, slot] of slots) {
|
|
78
|
+
defs[nameFor.get(pointer)] = slot.obj;
|
|
79
|
+
}
|
|
80
|
+
for (const [pointer, slot] of slots) {
|
|
81
|
+
slot.parent[slot.key] = {
|
|
82
|
+
$ref: `#/$defs/${nameFor.get(pointer)}`
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
repointRefs(clone, nameFor);
|
|
86
|
+
for (const name of Object.keys(defs)) repointRefs(defs[name], nameFor);
|
|
87
|
+
const existingDefs = clone.$defs ?? {};
|
|
88
|
+
clone.$defs = { ...existingDefs, ...defs };
|
|
89
|
+
return clone;
|
|
90
|
+
}
|
|
91
|
+
function installToolSchemaRefNormalization(server) {
|
|
92
|
+
const lowLevel = server.server;
|
|
93
|
+
const handlers = lowLevel._requestHandlers;
|
|
94
|
+
const original = handlers?.get("tools/list");
|
|
95
|
+
if (!original) {
|
|
96
|
+
logger.warn("Skipping tool-schema $ref normalization: tools/list handler not found");
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
lowLevel.setRequestHandler(ListToolsRequestSchema, async (request, extra) => {
|
|
100
|
+
const result = await original(request, extra);
|
|
101
|
+
for (const tool of result.tools ?? []) {
|
|
102
|
+
if (tool.inputSchema && typeof tool.inputSchema === "object") {
|
|
103
|
+
tool.inputSchema = normalizeToolSchemaRefs(tool.inputSchema);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
export {
|
|
110
|
+
installToolSchemaRefNormalization,
|
|
111
|
+
normalizeToolSchemaRefs
|
|
112
|
+
};
|
package/dist/server.js
CHANGED
|
@@ -9,6 +9,7 @@ import logger, { enableConsoleLogging } from "./logger.js";
|
|
|
9
9
|
import { registerAuthTools } from "./auth-tools.js";
|
|
10
10
|
import { registerGraphTools, registerDiscoveryTools } from "./graph-tools.js";
|
|
11
11
|
import { buildMcpServerInstructions } from "./mcp-instructions.js";
|
|
12
|
+
import { installToolSchemaRefNormalization } from "./normalize-tool-schema.js";
|
|
12
13
|
import GraphClient from "./graph-client.js";
|
|
13
14
|
import {
|
|
14
15
|
buildScopesFromEndpoints,
|
|
@@ -102,6 +103,7 @@ class MicrosoftGraphServer {
|
|
|
102
103
|
this.options.allowedScopes
|
|
103
104
|
);
|
|
104
105
|
}
|
|
106
|
+
installToolSchemaRefNormalization(server);
|
|
105
107
|
return server;
|
|
106
108
|
}
|
|
107
109
|
async initialize(version) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softeria/ms-365-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.132.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",
|
package/src/endpoints.json
CHANGED
|
@@ -702,7 +702,102 @@
|
|
|
702
702
|
"isExcelOp": true,
|
|
703
703
|
"scopes": ["Files.ReadWrite"],
|
|
704
704
|
"skipEncoding": ["address"],
|
|
705
|
-
"llmTip": "Apply rangeFormat properties to a specific range. Required path param 'address' (e.g. 'A1:E5' or 'Sheet1!A1:E5'). Body: { horizontalAlignment, verticalAlignment, wrapText, columnWidth, rowHeight }.
|
|
705
|
+
"llmTip": "Apply rangeFormat properties to a specific range. Required path param 'address' (e.g. 'A1:E5' or 'Sheet1!A1:E5'). Body: { horizontalAlignment, verticalAlignment, wrapText, columnWidth, rowHeight }. Font, fill, and borders are NOT set here; use format-excel-range-font, format-excel-range-fill, and format-excel-range-border for those."
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/format",
|
|
709
|
+
"method": "get",
|
|
710
|
+
"toolName": "get-excel-range-format",
|
|
711
|
+
"presets": ["excel", "personal"],
|
|
712
|
+
"isExcelOp": true,
|
|
713
|
+
"scopes": ["Files.Read"],
|
|
714
|
+
"skipEncoding": ["address"],
|
|
715
|
+
"llmTip": "Reads a range's format: alignment, wrapText, columnWidth, rowHeight. Font, fill, and borders are nested and omitted by default; add font, fill, and borders to the $expand parameter to include them in one call. Cell styling often encodes meaning (a fill or font color flagging status such as tentative or reconciled), so expand these to interpret what the cells mean."
|
|
716
|
+
},
|
|
717
|
+
{
|
|
718
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/format/font",
|
|
719
|
+
"method": "patch",
|
|
720
|
+
"toolName": "format-excel-range-font",
|
|
721
|
+
"presets": ["excel", "personal"],
|
|
722
|
+
"isExcelOp": true,
|
|
723
|
+
"scopes": ["Files.ReadWrite"],
|
|
724
|
+
"skipEncoding": ["address"],
|
|
725
|
+
"llmTip": "Set font formatting on a range: bold, italic, underline, size, color, and font name.",
|
|
726
|
+
"requestBodySchema": {
|
|
727
|
+
"type": "object",
|
|
728
|
+
"description": "Font style applied to every cell in the range. Send only the properties you want to change.",
|
|
729
|
+
"properties": {
|
|
730
|
+
"bold": { "type": "boolean" },
|
|
731
|
+
"italic": { "type": "boolean" },
|
|
732
|
+
"underline": {
|
|
733
|
+
"type": "string",
|
|
734
|
+
"enum": ["None", "Single", "Double", "SingleAccountant", "DoubleAccountant"]
|
|
735
|
+
},
|
|
736
|
+
"size": { "type": "number", "description": "Font size in points." },
|
|
737
|
+
"color": {
|
|
738
|
+
"type": "string",
|
|
739
|
+
"description": "HTML color code for the text, e.g. #FF0000 or a named color like 'red'."
|
|
740
|
+
},
|
|
741
|
+
"name": { "type": "string", "description": "Font name, e.g. 'Calibri'." }
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
{
|
|
746
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/format/fill",
|
|
747
|
+
"method": "patch",
|
|
748
|
+
"toolName": "format-excel-range-fill",
|
|
749
|
+
"presets": ["excel", "personal"],
|
|
750
|
+
"isExcelOp": true,
|
|
751
|
+
"scopes": ["Files.ReadWrite"],
|
|
752
|
+
"skipEncoding": ["address"],
|
|
753
|
+
"llmTip": "Set the background fill color of a range's cells.",
|
|
754
|
+
"requestBodySchema": {
|
|
755
|
+
"type": "object",
|
|
756
|
+
"description": "Background fill applied to every cell in the range.",
|
|
757
|
+
"properties": {
|
|
758
|
+
"color": {
|
|
759
|
+
"type": "string",
|
|
760
|
+
"description": "HTML color code for the background, e.g. #FFFF00 or a named color like 'yellow'."
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')/format/borders/{sideIndex}",
|
|
767
|
+
"method": "patch",
|
|
768
|
+
"toolName": "format-excel-range-border",
|
|
769
|
+
"presets": ["excel"],
|
|
770
|
+
"isExcelOp": true,
|
|
771
|
+
"scopes": ["Files.ReadWrite"],
|
|
772
|
+
"skipEncoding": ["address"],
|
|
773
|
+
"llmTip": "Sets one border side. The {sideIndex} path param selects which side: EdgeTop, EdgeBottom, EdgeLeft, EdgeRight, InsideVertical, InsideHorizontal, DiagonalDown, or DiagonalUp. To outline all four edges, call once per side.",
|
|
774
|
+
"requestBodySchema": {
|
|
775
|
+
"type": "object",
|
|
776
|
+
"description": "Line style for the chosen border side.",
|
|
777
|
+
"properties": {
|
|
778
|
+
"style": {
|
|
779
|
+
"type": "string",
|
|
780
|
+
"enum": [
|
|
781
|
+
"None",
|
|
782
|
+
"Continuous",
|
|
783
|
+
"Dash",
|
|
784
|
+
"DashDot",
|
|
785
|
+
"DashDotDot",
|
|
786
|
+
"Dot",
|
|
787
|
+
"Double",
|
|
788
|
+
"SlantDashDot"
|
|
789
|
+
]
|
|
790
|
+
},
|
|
791
|
+
"weight": {
|
|
792
|
+
"type": "string",
|
|
793
|
+
"enum": ["Hairline", "Thin", "Medium", "Thick"]
|
|
794
|
+
},
|
|
795
|
+
"color": {
|
|
796
|
+
"type": "string",
|
|
797
|
+
"description": "HTML color code for the line, e.g. #000000 or a named color like 'black'."
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
706
801
|
},
|
|
707
802
|
{
|
|
708
803
|
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range()/sort",
|
|
@@ -1100,14 +1195,16 @@
|
|
|
1100
1195
|
"method": "post",
|
|
1101
1196
|
"toolName": "create-todo-task",
|
|
1102
1197
|
"presets": ["personal", "tasks"],
|
|
1103
|
-
"scopes": ["Tasks.ReadWrite"]
|
|
1198
|
+
"scopes": ["Tasks.ReadWrite"],
|
|
1199
|
+
"llmTip": "Creates a new task in a Microsoft To Do list. Body: { title: \"...\" }; optional dueDateTime, reminderDateTime, importance, body (notes), recurrence, categories. Requires todoTaskListId from list-todo-task-lists."
|
|
1104
1200
|
},
|
|
1105
1201
|
{
|
|
1106
1202
|
"pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}",
|
|
1107
1203
|
"method": "patch",
|
|
1108
1204
|
"toolName": "update-todo-task",
|
|
1109
1205
|
"presets": ["personal", "tasks"],
|
|
1110
|
-
"scopes": ["Tasks.ReadWrite"]
|
|
1206
|
+
"scopes": ["Tasks.ReadWrite"],
|
|
1207
|
+
"llmTip": "Updates a Microsoft To Do task. Use this to mark a to-do item complete or done (body: { status: \"completed\" }), reopen it (status: \"notStarted\"), rename it (title), or change its due date (dueDateTime), reminder (reminderDateTime), importance, or notes (body). Requires todoTaskListId from list-todo-task-lists and todoTaskId from list-todo-tasks."
|
|
1111
1208
|
},
|
|
1112
1209
|
{
|
|
1113
1210
|
"pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}",
|