@dashflow/ms365-mcp-server 1.0.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/.env.example +54 -0
- package/.releaserc.json +9 -0
- package/Dockerfile +22 -0
- package/LICENSE +21 -0
- package/README.md +590 -0
- package/bin/generate-graph-client.mjs +59 -0
- package/bin/modules/download-openapi.mjs +40 -0
- package/bin/modules/extract-descriptions.mjs +48 -0
- package/bin/modules/generate-mcp-tools.mjs +46 -0
- package/bin/modules/simplified-openapi.mjs +694 -0
- package/dist/auth-tools.js +202 -0
- package/dist/auth.js +422 -0
- package/dist/cli.js +78 -0
- package/dist/cloud-config.js +49 -0
- package/dist/endpoints.json +596 -0
- package/dist/generated/endpoint-types.js +0 -0
- package/dist/generated/hack.js +42 -0
- package/dist/graph-client.js +208 -0
- package/dist/graph-tools.js +401 -0
- package/dist/index.js +76 -0
- package/dist/lib/microsoft-auth.js +73 -0
- package/dist/logger.js +42 -0
- package/dist/oauth-provider.js +51 -0
- package/dist/request-context.js +9 -0
- package/dist/secrets.js +68 -0
- package/dist/server.js +387 -0
- package/dist/tool-categories.js +93 -0
- package/dist/version.js +10 -0
- package/eslint.config.js +43 -0
- package/glama.json +4 -0
- package/package.json +79 -0
- package/remove-recursive-refs.js +294 -0
- package/src/endpoints.json +596 -0
- package/src/generated/README.md +56 -0
- package/src/generated/endpoint-types.ts +27 -0
- package/src/generated/hack.ts +49 -0
- package/test-calendar-fix.js +62 -0
- package/test-real-calendar.js +96 -0
- package/tsup.config.ts +30 -0
|
@@ -0,0 +1,596 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"pathPattern": "/me/messages",
|
|
4
|
+
"method": "get",
|
|
5
|
+
"toolName": "list-mail-messages",
|
|
6
|
+
"scopes": ["Mail.Read"],
|
|
7
|
+
"llmTip": "CRITICAL: When searching emails, the $search parameter value MUST be wrapped in double quotes. Format: $search=\"your search query here\". Use KQL (Keyword Query Language) syntax to search specific properties: 'from:', 'subject:', 'body:', 'to:', 'cc:', 'bcc:', 'attachment:', 'hasAttachments:', 'importance:', 'received:', 'sent:'. Examples: $search=\"from:john@example.com\" | $search=\"subject:meeting AND hasAttachments:true\" | $search=\"body:urgent AND received>=2024-01-01\" | $search=\"from:john AND importance:high\". Remember: ALWAYS wrap the entire search expression in double quotes! Reference: https://learn.microsoft.com/en-us/graph/search-query-parameter"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"pathPattern": "/me/mailFolders",
|
|
11
|
+
"method": "get",
|
|
12
|
+
"toolName": "list-mail-folders",
|
|
13
|
+
"scopes": ["Mail.Read"]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"pathPattern": "/me/mailFolders/{mailFolder-id}/messages",
|
|
17
|
+
"method": "get",
|
|
18
|
+
"toolName": "list-mail-folder-messages",
|
|
19
|
+
"scopes": ["Mail.Read"],
|
|
20
|
+
"llmTip": "CRITICAL: When searching emails, the $search parameter value MUST be wrapped in double quotes. Format: $search=\"your search query here\". Use KQL (Keyword Query Language) syntax to search specific properties: 'from:', 'subject:', 'body:', 'to:', 'cc:', 'bcc:', 'attachment:', 'hasAttachments:', 'importance:', 'received:', 'sent:'. Examples: $search=\"from:john@example.com\" | $search=\"subject:meeting AND hasAttachments:true\" | $search=\"body:urgent AND received>=2024-01-01\" | $search=\"from:alice AND importance:high\". Remember: ALWAYS wrap the entire search expression in double quotes! Reference: https://learn.microsoft.com/en-us/graph/search-query-parameter"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"pathPattern": "/me/messages/{message-id}",
|
|
24
|
+
"method": "get",
|
|
25
|
+
"toolName": "get-mail-message",
|
|
26
|
+
"scopes": ["Mail.Read"]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"pathPattern": "/me/sendMail",
|
|
30
|
+
"method": "post",
|
|
31
|
+
"toolName": "send-mail",
|
|
32
|
+
"scopes": ["Mail.Send"],
|
|
33
|
+
"llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients."
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"pathPattern": "/users/{user-id}/messages",
|
|
37
|
+
"method": "get",
|
|
38
|
+
"toolName": "list-shared-mailbox-messages",
|
|
39
|
+
"workScopes": ["Mail.Read.Shared"],
|
|
40
|
+
"llmTip": "CRITICAL: When searching emails, the $search parameter value MUST be wrapped in double quotes. Format: $search=\"your search query here\". Use KQL (Keyword Query Language) syntax to search specific properties: 'from:', 'subject:', 'body:', 'to:', 'cc:', 'bcc:', 'attachment:', 'hasAttachments:', 'importance:', 'received:', 'sent:'. Examples: $search=\"from:john@example.com\" | $search=\"subject:meeting AND hasAttachments:true\" | $search=\"body:urgent AND received>=2024-01-01\" | $search=\"from:alice AND importance:high\". Remember: ALWAYS wrap the entire search expression in double quotes! Reference: https://learn.microsoft.com/en-us/graph/search-query-parameter"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"pathPattern": "/users/{user-id}/mailFolders/{mailFolder-id}/messages",
|
|
44
|
+
"method": "get",
|
|
45
|
+
"toolName": "list-shared-mailbox-folder-messages",
|
|
46
|
+
"workScopes": ["Mail.Read.Shared"],
|
|
47
|
+
"llmTip": "CRITICAL: When searching emails, the $search parameter value MUST be wrapped in double quotes. Format: $search=\"your search query here\". Use KQL (Keyword Query Language) syntax to search specific properties: 'from:', 'subject:', 'body:', 'to:', 'cc:', 'bcc:', 'attachment:', 'hasAttachments:', 'importance:', 'received:', 'sent:'. Examples: $search=\"from:john@example.com\" | $search=\"subject:meeting AND hasAttachments:true\" | $search=\"body:urgent AND received>=2024-01-01\" | $search=\"from:alice AND importance:high\". Remember: ALWAYS wrap the entire search expression in double quotes! Reference: https://learn.microsoft.com/en-us/graph/search-query-parameter"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"pathPattern": "/users/{user-id}/messages/{message-id}",
|
|
51
|
+
"method": "get",
|
|
52
|
+
"toolName": "get-shared-mailbox-message",
|
|
53
|
+
"workScopes": ["Mail.Read.Shared"]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"pathPattern": "/users/{user-id}/sendMail",
|
|
57
|
+
"method": "post",
|
|
58
|
+
"toolName": "send-shared-mailbox-mail",
|
|
59
|
+
"workScopes": ["Mail.Send.Shared"],
|
|
60
|
+
"llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"pathPattern": "/users",
|
|
64
|
+
"method": "get",
|
|
65
|
+
"toolName": "list-users",
|
|
66
|
+
"workScopes": ["User.Read.All"],
|
|
67
|
+
"llmTip": "CRITICAL: This request requires the ConsistencyLevel header set to eventual. When searching users, the $search parameter value MUST be wrapped in double quotes. Format: $search=\"your search query here\". Use KQL (Keyword Query Language) syntax to search specific properties: 'displayName:'. Examples: $search=\"displayName:john\" | $search=\"displayName:john\" OR \"displayName:jane\". Remember: ALWAYS wrap the entire search expression in double quotes and set the ConsistencyLevel header to eventual! Reference: https://learn.microsoft.com/en-us/graph/search-query-parameter"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"pathPattern": "/me/messages",
|
|
71
|
+
"method": "post",
|
|
72
|
+
"toolName": "create-draft-email",
|
|
73
|
+
"scopes": ["Mail.ReadWrite"]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"pathPattern": "/me/messages/{message-id}",
|
|
77
|
+
"method": "delete",
|
|
78
|
+
"toolName": "delete-mail-message",
|
|
79
|
+
"scopes": ["Mail.ReadWrite"]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"pathPattern": "/me/messages/{message-id}/move",
|
|
83
|
+
"method": "post",
|
|
84
|
+
"toolName": "move-mail-message",
|
|
85
|
+
"scopes": ["Mail.ReadWrite"]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"pathPattern": "/me/messages/{message-id}",
|
|
89
|
+
"method": "patch",
|
|
90
|
+
"toolName": "update-mail-message",
|
|
91
|
+
"scopes": ["Mail.ReadWrite"]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"pathPattern": "/me/messages/{message-id}/attachments",
|
|
95
|
+
"method": "post",
|
|
96
|
+
"toolName": "add-mail-attachment",
|
|
97
|
+
"scopes": ["Mail.ReadWrite"]
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"pathPattern": "/me/messages/{message-id}/attachments",
|
|
101
|
+
"method": "get",
|
|
102
|
+
"toolName": "list-mail-attachments",
|
|
103
|
+
"scopes": ["Mail.Read"]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"pathPattern": "/me/messages/{message-id}/attachments/{attachment-id}",
|
|
107
|
+
"method": "get",
|
|
108
|
+
"toolName": "get-mail-attachment",
|
|
109
|
+
"scopes": ["Mail.Read"]
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"pathPattern": "/me/messages/{message-id}/attachments/{attachment-id}",
|
|
113
|
+
"method": "delete",
|
|
114
|
+
"toolName": "delete-mail-attachment",
|
|
115
|
+
"scopes": ["Mail.ReadWrite"]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"pathPattern": "/me/events",
|
|
119
|
+
"method": "get",
|
|
120
|
+
"toolName": "list-calendar-events",
|
|
121
|
+
"scopes": ["Calendars.Read"],
|
|
122
|
+
"supportsTimezone": true
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"pathPattern": "/me/events/{event-id}",
|
|
126
|
+
"method": "get",
|
|
127
|
+
"toolName": "get-calendar-event",
|
|
128
|
+
"scopes": ["Calendars.Read"],
|
|
129
|
+
"supportsTimezone": true
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"pathPattern": "/me/events",
|
|
133
|
+
"method": "post",
|
|
134
|
+
"toolName": "create-calendar-event",
|
|
135
|
+
"scopes": ["Calendars.ReadWrite"],
|
|
136
|
+
"llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients."
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"pathPattern": "/me/events/{event-id}",
|
|
140
|
+
"method": "patch",
|
|
141
|
+
"toolName": "update-calendar-event",
|
|
142
|
+
"scopes": ["Calendars.ReadWrite"],
|
|
143
|
+
"llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients."
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"pathPattern": "/me/events/{event-id}",
|
|
147
|
+
"method": "delete",
|
|
148
|
+
"toolName": "delete-calendar-event",
|
|
149
|
+
"scopes": ["Calendars.ReadWrite"]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"pathPattern": "/me/calendars/{calendar-id}/events",
|
|
153
|
+
"method": "get",
|
|
154
|
+
"toolName": "list-specific-calendar-events",
|
|
155
|
+
"scopes": ["Calendars.Read"],
|
|
156
|
+
"supportsTimezone": true
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"pathPattern": "/me/calendars/{calendar-id}/events/{event-id}",
|
|
160
|
+
"method": "get",
|
|
161
|
+
"toolName": "get-specific-calendar-event",
|
|
162
|
+
"scopes": ["Calendars.Read"],
|
|
163
|
+
"supportsTimezone": true
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
"pathPattern": "/me/calendars/{calendar-id}/events",
|
|
167
|
+
"method": "post",
|
|
168
|
+
"toolName": "create-specific-calendar-event",
|
|
169
|
+
"scopes": ["Calendars.ReadWrite"],
|
|
170
|
+
"llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients."
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"pathPattern": "/me/calendars/{calendar-id}/events/{event-id}",
|
|
174
|
+
"method": "patch",
|
|
175
|
+
"toolName": "update-specific-calendar-event",
|
|
176
|
+
"scopes": ["Calendars.ReadWrite"],
|
|
177
|
+
"llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients."
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"pathPattern": "/me/calendars/{calendar-id}/events/{event-id}",
|
|
181
|
+
"method": "delete",
|
|
182
|
+
"toolName": "delete-specific-calendar-event",
|
|
183
|
+
"scopes": ["Calendars.ReadWrite"]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"pathPattern": "/me/calendarView",
|
|
187
|
+
"method": "get",
|
|
188
|
+
"toolName": "get-calendar-view",
|
|
189
|
+
"scopes": ["Calendars.Read"],
|
|
190
|
+
"supportsTimezone": true
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"pathPattern": "/me/calendars",
|
|
194
|
+
"method": "get",
|
|
195
|
+
"toolName": "list-calendars",
|
|
196
|
+
"scopes": ["Calendars.Read"]
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"pathPattern": "/me/findMeetingTimes",
|
|
200
|
+
"method": "post",
|
|
201
|
+
"toolName": "find-meeting-times",
|
|
202
|
+
"workScopes": ["Calendars.Read.Shared"]
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"pathPattern": "/me/drives",
|
|
206
|
+
"method": "get",
|
|
207
|
+
"toolName": "list-drives",
|
|
208
|
+
"scopes": ["Files.Read"]
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"pathPattern": "/drives/{drive-id}/root",
|
|
212
|
+
"method": "get",
|
|
213
|
+
"toolName": "get-drive-root-item",
|
|
214
|
+
"scopes": ["Files.Read"]
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"pathPattern": "/drives/{drive-id}/root",
|
|
218
|
+
"method": "get",
|
|
219
|
+
"toolName": "get-root-folder",
|
|
220
|
+
"scopes": ["Files.Read"]
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/children",
|
|
224
|
+
"method": "get",
|
|
225
|
+
"toolName": "list-folder-files",
|
|
226
|
+
"scopes": ["Files.Read"]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/content",
|
|
230
|
+
"method": "get",
|
|
231
|
+
"toolName": "download-onedrive-file-content",
|
|
232
|
+
"scopes": ["Files.Read"],
|
|
233
|
+
"returnDownloadUrl": true
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}",
|
|
237
|
+
"method": "delete",
|
|
238
|
+
"toolName": "delete-onedrive-file",
|
|
239
|
+
"scopes": ["Files.ReadWrite"]
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/content",
|
|
243
|
+
"method": "put",
|
|
244
|
+
"toolName": "upload-file-content",
|
|
245
|
+
"scopes": ["Files.ReadWrite"]
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/charts/add",
|
|
249
|
+
"method": "post",
|
|
250
|
+
"toolName": "create-excel-chart",
|
|
251
|
+
"isExcelOp": true,
|
|
252
|
+
"scopes": ["Files.ReadWrite"]
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range()/format",
|
|
256
|
+
"method": "patch",
|
|
257
|
+
"toolName": "format-excel-range",
|
|
258
|
+
"isExcelOp": true,
|
|
259
|
+
"scopes": ["Files.ReadWrite"]
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range()/sort",
|
|
263
|
+
"method": "patch",
|
|
264
|
+
"toolName": "sort-excel-range",
|
|
265
|
+
"isExcelOp": true,
|
|
266
|
+
"scopes": ["Files.ReadWrite"]
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range(address='{address}')",
|
|
270
|
+
"method": "get",
|
|
271
|
+
"toolName": "get-excel-range",
|
|
272
|
+
"isExcelOp": true,
|
|
273
|
+
"scopes": ["Files.Read"]
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets",
|
|
277
|
+
"method": "get",
|
|
278
|
+
"toolName": "list-excel-worksheets",
|
|
279
|
+
"isExcelOp": true,
|
|
280
|
+
"scopes": ["Files.Read"]
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"pathPattern": "/me/onenote/notebooks",
|
|
284
|
+
"method": "get",
|
|
285
|
+
"toolName": "list-onenote-notebooks",
|
|
286
|
+
"scopes": ["Notes.Read"]
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"pathPattern": "/me/onenote/notebooks/{notebook-id}/sections",
|
|
290
|
+
"method": "get",
|
|
291
|
+
"toolName": "list-onenote-notebook-sections",
|
|
292
|
+
"scopes": ["Notes.Read"]
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"pathPattern": "/me/onenote/sections/{onenoteSection-id}/pages",
|
|
296
|
+
"method": "get",
|
|
297
|
+
"toolName": "list-onenote-section-pages",
|
|
298
|
+
"scopes": ["Notes.Read"]
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"pathPattern": "/me/onenote/pages/{onenotePage-id}/content",
|
|
302
|
+
"method": "get",
|
|
303
|
+
"toolName": "get-onenote-page-content",
|
|
304
|
+
"scopes": ["Notes.Read"]
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
"pathPattern": "/me/onenote/pages",
|
|
308
|
+
"method": "post",
|
|
309
|
+
"toolName": "create-onenote-page",
|
|
310
|
+
"scopes": ["Notes.Create"],
|
|
311
|
+
"contentType": "text/html"
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"pathPattern": "/me/todo/lists",
|
|
315
|
+
"method": "get",
|
|
316
|
+
"toolName": "list-todo-task-lists",
|
|
317
|
+
"scopes": ["Tasks.Read"]
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks",
|
|
321
|
+
"method": "get",
|
|
322
|
+
"toolName": "list-todo-tasks",
|
|
323
|
+
"scopes": ["Tasks.Read"]
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
"pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}",
|
|
327
|
+
"method": "get",
|
|
328
|
+
"toolName": "get-todo-task",
|
|
329
|
+
"scopes": ["Tasks.Read"]
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks",
|
|
333
|
+
"method": "post",
|
|
334
|
+
"toolName": "create-todo-task",
|
|
335
|
+
"scopes": ["Tasks.ReadWrite"]
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
"pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}",
|
|
339
|
+
"method": "patch",
|
|
340
|
+
"toolName": "update-todo-task",
|
|
341
|
+
"scopes": ["Tasks.ReadWrite"]
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"pathPattern": "/me/todo/lists/{todoTaskList-id}/tasks/{todoTask-id}",
|
|
345
|
+
"method": "delete",
|
|
346
|
+
"toolName": "delete-todo-task",
|
|
347
|
+
"scopes": ["Tasks.ReadWrite"]
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"pathPattern": "/me/planner/tasks",
|
|
351
|
+
"method": "get",
|
|
352
|
+
"toolName": "list-planner-tasks",
|
|
353
|
+
"scopes": ["Tasks.Read"]
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"pathPattern": "/planner/plans/{plannerPlan-id}",
|
|
357
|
+
"method": "get",
|
|
358
|
+
"toolName": "get-planner-plan",
|
|
359
|
+
"scopes": ["Tasks.Read"]
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"pathPattern": "/planner/plans/{plannerPlan-id}/tasks",
|
|
363
|
+
"method": "get",
|
|
364
|
+
"toolName": "list-plan-tasks",
|
|
365
|
+
"scopes": ["Tasks.Read"]
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"pathPattern": "/planner/tasks/{plannerTask-id}",
|
|
369
|
+
"method": "get",
|
|
370
|
+
"toolName": "get-planner-task",
|
|
371
|
+
"scopes": ["Tasks.Read"]
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
"pathPattern": "/planner/tasks",
|
|
375
|
+
"method": "post",
|
|
376
|
+
"toolName": "create-planner-task",
|
|
377
|
+
"scopes": ["Tasks.ReadWrite"]
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"pathPattern": "/planner/tasks/{plannerTask-id}",
|
|
381
|
+
"method": "patch",
|
|
382
|
+
"toolName": "update-planner-task",
|
|
383
|
+
"scopes": ["Tasks.ReadWrite"]
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
"pathPattern": "/planner/tasks/{plannerTask-id}/details",
|
|
387
|
+
"method": "patch",
|
|
388
|
+
"toolName": "update-planner-task-details",
|
|
389
|
+
"scopes": ["Tasks.ReadWrite"]
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"pathPattern": "/me/contacts",
|
|
393
|
+
"method": "get",
|
|
394
|
+
"toolName": "list-outlook-contacts",
|
|
395
|
+
"scopes": ["Contacts.Read"]
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
"pathPattern": "/me/contacts/{contact-id}",
|
|
399
|
+
"method": "get",
|
|
400
|
+
"toolName": "get-outlook-contact",
|
|
401
|
+
"scopes": ["Contacts.Read"]
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
"pathPattern": "/me/contacts",
|
|
405
|
+
"method": "post",
|
|
406
|
+
"toolName": "create-outlook-contact",
|
|
407
|
+
"scopes": ["Contacts.ReadWrite"]
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
"pathPattern": "/me/contacts/{contact-id}",
|
|
411
|
+
"method": "patch",
|
|
412
|
+
"toolName": "update-outlook-contact",
|
|
413
|
+
"scopes": ["Contacts.ReadWrite"]
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
"pathPattern": "/me/contacts/{contact-id}",
|
|
417
|
+
"method": "delete",
|
|
418
|
+
"toolName": "delete-outlook-contact",
|
|
419
|
+
"scopes": ["Contacts.ReadWrite"]
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
"pathPattern": "/me",
|
|
423
|
+
"method": "get",
|
|
424
|
+
"toolName": "get-current-user",
|
|
425
|
+
"scopes": ["User.Read"]
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"pathPattern": "/me/chats",
|
|
429
|
+
"method": "get",
|
|
430
|
+
"toolName": "list-chats",
|
|
431
|
+
"workScopes": ["Chat.Read"]
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"pathPattern": "/chats/{chat-id}",
|
|
435
|
+
"method": "get",
|
|
436
|
+
"toolName": "get-chat",
|
|
437
|
+
"workScopes": ["Chat.Read"]
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
"pathPattern": "/chats/{chat-id}/messages",
|
|
441
|
+
"method": "get",
|
|
442
|
+
"toolName": "list-chat-messages",
|
|
443
|
+
"workScopes": ["ChatMessage.Read"]
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"pathPattern": "/chats/{chat-id}/messages/{chatMessage-id}",
|
|
447
|
+
"method": "get",
|
|
448
|
+
"toolName": "get-chat-message",
|
|
449
|
+
"workScopes": ["ChatMessage.Read"]
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
"pathPattern": "/chats/{chat-id}/messages",
|
|
453
|
+
"method": "post",
|
|
454
|
+
"toolName": "send-chat-message",
|
|
455
|
+
"workScopes": ["ChatMessage.Send"]
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
"pathPattern": "/me/joinedTeams",
|
|
459
|
+
"method": "get",
|
|
460
|
+
"toolName": "list-joined-teams",
|
|
461
|
+
"workScopes": ["Team.ReadBasic.All"]
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
"pathPattern": "/teams/{team-id}",
|
|
465
|
+
"method": "get",
|
|
466
|
+
"toolName": "get-team",
|
|
467
|
+
"workScopes": ["Team.ReadBasic.All"]
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
"pathPattern": "/teams/{team-id}/channels",
|
|
471
|
+
"method": "get",
|
|
472
|
+
"toolName": "list-team-channels",
|
|
473
|
+
"workScopes": ["Channel.ReadBasic.All"]
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
"pathPattern": "/teams/{team-id}/channels/{channel-id}",
|
|
477
|
+
"method": "get",
|
|
478
|
+
"toolName": "get-team-channel",
|
|
479
|
+
"workScopes": ["Channel.ReadBasic.All"]
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
"pathPattern": "/teams/{team-id}/channels/{channel-id}/messages",
|
|
483
|
+
"method": "get",
|
|
484
|
+
"toolName": "list-channel-messages",
|
|
485
|
+
"workScopes": ["ChannelMessage.Read.All"]
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
"pathPattern": "/teams/{team-id}/channels/{channel-id}/messages/{chatMessage-id}",
|
|
489
|
+
"method": "get",
|
|
490
|
+
"toolName": "get-channel-message",
|
|
491
|
+
"workScopes": ["ChannelMessage.Read.All"]
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"pathPattern": "/teams/{team-id}/channels/{channel-id}/messages",
|
|
495
|
+
"method": "post",
|
|
496
|
+
"toolName": "send-channel-message",
|
|
497
|
+
"workScopes": ["ChannelMessage.Send"]
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
"pathPattern": "/teams/{team-id}/members",
|
|
501
|
+
"method": "get",
|
|
502
|
+
"toolName": "list-team-members",
|
|
503
|
+
"workScopes": ["TeamMember.Read.All"]
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
"pathPattern": "/chats/{chat-id}/messages/{chatMessage-id}/replies",
|
|
507
|
+
"method": "get",
|
|
508
|
+
"toolName": "list-chat-message-replies",
|
|
509
|
+
"workScopes": ["ChatMessage.Read"]
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
"pathPattern": "/chats/{chat-id}/messages/{chatMessage-id}/replies",
|
|
513
|
+
"method": "post",
|
|
514
|
+
"toolName": "reply-to-chat-message",
|
|
515
|
+
"workScopes": ["ChatMessage.Send"]
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
"pathPattern": "/sites",
|
|
519
|
+
"method": "get",
|
|
520
|
+
"toolName": "search-sharepoint-sites",
|
|
521
|
+
"workScopes": ["Sites.Read.All"]
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
"pathPattern": "/sites/{site-id}",
|
|
525
|
+
"method": "get",
|
|
526
|
+
"toolName": "get-sharepoint-site",
|
|
527
|
+
"workScopes": ["Sites.Read.All"]
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
"pathPattern": "/sites/{site-id}/drives",
|
|
531
|
+
"method": "get",
|
|
532
|
+
"toolName": "list-sharepoint-site-drives",
|
|
533
|
+
"workScopes": ["Sites.Read.All"]
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
"pathPattern": "/sites/{site-id}/drives/{drive-id}",
|
|
537
|
+
"method": "get",
|
|
538
|
+
"toolName": "get-sharepoint-site-drive-by-id",
|
|
539
|
+
"workScopes": ["Sites.Read.All"]
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
"pathPattern": "/sites/{site-id}/items",
|
|
543
|
+
"method": "get",
|
|
544
|
+
"toolName": "list-sharepoint-site-items",
|
|
545
|
+
"workScopes": ["Sites.Read.All"]
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"pathPattern": "/sites/{site-id}/items/{baseItem-id}",
|
|
549
|
+
"method": "get",
|
|
550
|
+
"toolName": "get-sharepoint-site-item",
|
|
551
|
+
"workScopes": ["Sites.Read.All"]
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
"pathPattern": "/sites/{site-id}/lists",
|
|
555
|
+
"method": "get",
|
|
556
|
+
"toolName": "list-sharepoint-site-lists",
|
|
557
|
+
"workScopes": ["Sites.Read.All"]
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
"pathPattern": "/sites/{site-id}/lists/{list-id}",
|
|
561
|
+
"method": "get",
|
|
562
|
+
"toolName": "get-sharepoint-site-list",
|
|
563
|
+
"workScopes": ["Sites.Read.All"]
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
"pathPattern": "/sites/{site-id}/lists/{list-id}/items",
|
|
567
|
+
"method": "get",
|
|
568
|
+
"toolName": "list-sharepoint-site-list-items",
|
|
569
|
+
"workScopes": ["Sites.Read.All"]
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
"pathPattern": "/sites/{site-id}/lists/{list-id}/items/{listItem-id}",
|
|
573
|
+
"method": "get",
|
|
574
|
+
"toolName": "get-sharepoint-site-list-item",
|
|
575
|
+
"workScopes": ["Sites.Read.All"]
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
"pathPattern": "/sites/{site-id}/getByPath(path='{path}')",
|
|
579
|
+
"method": "get",
|
|
580
|
+
"toolName": "get-sharepoint-site-by-path",
|
|
581
|
+
"workScopes": ["Sites.Read.All"]
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
"pathPattern": "/sites/delta()",
|
|
585
|
+
"method": "get",
|
|
586
|
+
"toolName": "get-sharepoint-sites-delta",
|
|
587
|
+
"workScopes": ["Sites.Read.All"]
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
"pathPattern": "/search/query",
|
|
591
|
+
"method": "post",
|
|
592
|
+
"toolName": "search-query",
|
|
593
|
+
"scopes": ["Mail.Read", "Calendars.Read", "Files.Read.All", "People.Read"],
|
|
594
|
+
"workScopes": ["Sites.Read.All", "Chat.Read", "ChannelMessage.Read.All"]
|
|
595
|
+
}
|
|
596
|
+
]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# MS 365 OpenAPI Client Generation
|
|
2
|
+
|
|
3
|
+
This directory contains the generated TypeScript client for the Microsoft 365 API based on the OpenAPI specification.
|
|
4
|
+
|
|
5
|
+
## The Evolution
|
|
6
|
+
|
|
7
|
+
### Version 1: AI-Generated Mappings
|
|
8
|
+
|
|
9
|
+
Our initial approach used AI to map Microsoft 365 documentation and OpenAPI specifications directly into MCP tools with
|
|
10
|
+
Zod mappings. While conceptually appealing, this approach didn't work well in practice and created several problems.
|
|
11
|
+
|
|
12
|
+
### Version 2: Direct OpenAPI Spec Usage
|
|
13
|
+
|
|
14
|
+
We then moved to using the full MS 365 OpenAPI specification file directly. This improved reliability but created new
|
|
15
|
+
significant problems:
|
|
16
|
+
|
|
17
|
+
- The spec file was a whopping 45MB in size
|
|
18
|
+
- It had to be included in the npm package
|
|
19
|
+
- Startup time was painfully slow due to parsing the large spec file
|
|
20
|
+
|
|
21
|
+
### Version 3: Current Solution (Trimmed Spec + Generated Client)
|
|
22
|
+
|
|
23
|
+
We eventually settled on a combined approach:
|
|
24
|
+
|
|
25
|
+
- Trim the OpenAPI spec to only what we need
|
|
26
|
+
- Generate static TypeScript client code using [openapi-zod-client](https://github.com/astahmer/openapi-zod-client)
|
|
27
|
+
|
|
28
|
+
### Benefits
|
|
29
|
+
|
|
30
|
+
- **Dramatically faster startup time** - No need to parse a large spec file
|
|
31
|
+
- **Significantly smaller package size** - No more bundling a 45MB spec file
|
|
32
|
+
- **Type safety** - Full TypeScript types generated from the OpenAPI spec
|
|
33
|
+
- **Validation** - Zod schemas for request/response validation
|
|
34
|
+
|
|
35
|
+
### Current Limitations & Future Improvements
|
|
36
|
+
|
|
37
|
+
While this approach is a significant improvement, it's not perfect. The MCP server might still struggle to understand
|
|
38
|
+
the MS 365 endpoints correctly, and there's room for improvements in how the API is exposed and documented for AI
|
|
39
|
+
assistants. However, with the current foundation of generated TypeScript clients and proper type safety, these
|
|
40
|
+
improvements should now be much easier to implement and maintain.
|
|
41
|
+
|
|
42
|
+
## Regenerating the Client
|
|
43
|
+
|
|
44
|
+
To regenerate the client code (e.g., after API changes or to update the supported endpoints):
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
npm run bin/generate-graph-client.mjs
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
This command does the following:
|
|
51
|
+
|
|
52
|
+
1. Fetches/processes the OpenAPI spec
|
|
53
|
+
2. Generates the TypeScript client with Zod validation
|
|
54
|
+
3. Outputs the result to `client.ts` in this directory
|
|
55
|
+
|
|
56
|
+
No complex build scripts needed - the generation is handled by openapi-zod-client.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';
|
|
4
|
+
|
|
5
|
+
export type Parameter = {
|
|
6
|
+
name: string;
|
|
7
|
+
type: 'Query' | 'Path' | 'Body' | 'Header';
|
|
8
|
+
schema: z.ZodType<any>;
|
|
9
|
+
description?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type Endpoint = {
|
|
13
|
+
method: HttpMethod;
|
|
14
|
+
path: string;
|
|
15
|
+
alias: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
requestFormat: 'json';
|
|
18
|
+
parameters?: Parameter[];
|
|
19
|
+
response: z.ZodType<any>;
|
|
20
|
+
errors?: Array<{
|
|
21
|
+
status: number;
|
|
22
|
+
description?: string;
|
|
23
|
+
schema?: z.ZodType<any>;
|
|
24
|
+
}>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type Endpoints = Endpoint[];
|