@softeria/ms-365-mcp-server 0.13.3 → 0.14.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 CHANGED
@@ -55,6 +55,9 @@ delete-outlook-contact</sub>
55
55
  **User Profile**
56
56
  <sub>get-current-user</sub>
57
57
 
58
+ **Search**
59
+ <sub>search-query</sub>
60
+
58
61
  ### Organization Account Tools (Requires --org-mode flag)
59
62
 
60
63
  **Teams & Chats**
@@ -17,7 +17,7 @@ export function generateMcpTools(openApiSpec, outputDir) {
17
17
 
18
18
  const clientFilePath = path.join(outputDir, 'client.ts');
19
19
  execSync(
20
- `npx -y openapi-zod-client ${openapiTrimmedFile} -o ${clientFilePath} --with-description --strict-objects --additional-props-default-value=false`,
20
+ `npx -y openapi-zod-client "${openapiTrimmedFile}" -o "${clientFilePath}" --with-description --strict-objects --additional-props-default-value=false`,
21
21
  {
22
22
  stdio: 'inherit',
23
23
  }
@@ -26,6 +26,18 @@ export function createAndSaveSimplifiedOpenAPI(endpointsFile, openapiFile, opena
26
26
  if (!operation.description && operation.summary) {
27
27
  operation.description = operation.summary;
28
28
  }
29
+ if (operation.parameters) {
30
+ operation.parameters = operation.parameters.map((param) => {
31
+ if (param.$ref && param.$ref.startsWith('#/components/parameters/')) {
32
+ const paramName = param.$ref.replace('#/components/parameters/', '');
33
+ const resolvedParam = openApiSpec.components?.parameters?.[paramName];
34
+ if (resolvedParam) {
35
+ return { ...resolvedParam };
36
+ }
37
+ }
38
+ return param;
39
+ });
40
+ }
29
41
  } else {
30
42
  delete value[method];
31
43
  }
package/dist/auth.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { PublicClientApplication } from "@azure/msal-node";
2
2
  import keytar from "keytar";
3
3
  import logger from "./logger.js";
4
- import { existsSync, readFileSync } from "fs";
4
+ import fs, { existsSync, readFileSync } from "fs";
5
5
  import { fileURLToPath } from "url";
6
6
  import path from "path";
7
7
  const __filename = fileURLToPath(import.meta.url);
@@ -34,12 +34,15 @@ const SCOPE_HIERARCHY = {
34
34
  function buildScopesFromEndpoints(includeWorkAccountScopes = false) {
35
35
  const scopesSet = /* @__PURE__ */ new Set();
36
36
  endpoints.default.forEach((endpoint) => {
37
- if (endpoint.requiresWorkAccount && !includeWorkAccountScopes) {
37
+ if (!includeWorkAccountScopes && !endpoint.scopes && endpoint.workScopes) {
38
38
  return;
39
39
  }
40
40
  if (endpoint.scopes && Array.isArray(endpoint.scopes)) {
41
41
  endpoint.scopes.forEach((scope) => scopesSet.add(scope));
42
42
  }
43
+ if (includeWorkAccountScopes && endpoint.workScopes && Array.isArray(endpoint.workScopes)) {
44
+ endpoint.workScopes.forEach((scope) => scopesSet.add(scope));
45
+ }
43
46
  });
44
47
  Object.entries(SCOPE_HIERARCHY).forEach(([higherScope, lowerScopes]) => {
45
48
  if (lowerScopes.every((scope) => scopesSet.has(scope))) {
@@ -300,27 +303,6 @@ class AuthManager {
300
303
  throw error;
301
304
  }
302
305
  }
303
- async hasWorkAccountPermissions() {
304
- try {
305
- const currentAccount = await this.getCurrentAccount();
306
- if (!currentAccount) {
307
- return false;
308
- }
309
- const workScopes = endpoints.default.filter((e) => e.requiresWorkAccount).flatMap((e) => e.scopes || []);
310
- try {
311
- await this.msalApp.acquireTokenSilent({
312
- scopes: workScopes.slice(0, 1),
313
- account: currentAccount
314
- });
315
- return true;
316
- } catch {
317
- return false;
318
- }
319
- } catch (error) {
320
- logger.error(`Error checking work account permissions: ${error.message}`);
321
- return false;
322
- }
323
- }
324
306
  // Multi-account support methods
325
307
  async listAccounts() {
326
308
  return await this.msalApp.getTokenCache().getAllAccounts();
@@ -339,24 +321,6 @@ class AuthManager {
339
321
  logger.info(`Selected account: ${account.username} (${accountId})`);
340
322
  return true;
341
323
  }
342
- async getTokenForAccount(accountId) {
343
- const accounts = await this.listAccounts();
344
- const account = accounts.find((acc) => acc.homeAccountId === accountId);
345
- if (!account) {
346
- throw new Error(`Account with ID ${accountId} not found`);
347
- }
348
- const silentRequest = {
349
- account,
350
- scopes: this.scopes
351
- };
352
- try {
353
- const response = await this.msalApp.acquireTokenSilent(silentRequest);
354
- return response.accessToken;
355
- } catch (error) {
356
- logger.error(`Failed to get token for account ${accountId}: ${error.message}`);
357
- throw error;
358
- }
359
- }
360
324
  async removeAccount(accountId) {
361
325
  const accounts = await this.listAccounts();
362
326
  const account = accounts.find((acc) => acc.homeAccountId === accountId);
@@ -382,10 +346,6 @@ class AuthManager {
382
346
  getSelectedAccountId() {
383
347
  return this.selectedAccountId;
384
348
  }
385
- requiresWorkAccountScope(toolName) {
386
- const endpoint = endpoints.default.find((e) => e.toolName === toolName);
387
- return endpoint?.requiresWorkAccount === true;
388
- }
389
349
  }
390
350
  var auth_default = AuthManager;
391
351
  export {
@@ -314,189 +314,169 @@
314
314
  "pathPattern": "/me/chats",
315
315
  "method": "get",
316
316
  "toolName": "list-chats",
317
- "scopes": ["Chat.Read"],
318
- "requiresWorkAccount": true
317
+ "workScopes": ["Chat.Read"]
319
318
  },
320
319
  {
321
320
  "pathPattern": "/chats/{chat-id}",
322
321
  "method": "get",
323
322
  "toolName": "get-chat",
324
- "scopes": ["Chat.Read"],
325
- "requiresWorkAccount": true
323
+ "workScopes": ["Chat.Read"]
326
324
  },
327
325
  {
328
326
  "pathPattern": "/chats/{chat-id}/messages",
329
327
  "method": "get",
330
328
  "toolName": "list-chat-messages",
331
- "scopes": ["ChatMessage.Read"],
332
- "requiresWorkAccount": true
329
+ "workScopes": ["ChatMessage.Read"]
333
330
  },
334
331
  {
335
332
  "pathPattern": "/chats/{chat-id}/messages/{chatMessage-id}",
336
333
  "method": "get",
337
334
  "toolName": "get-chat-message",
338
- "scopes": ["ChatMessage.Read"],
339
- "requiresWorkAccount": true
335
+ "workScopes": ["ChatMessage.Read"]
340
336
  },
341
337
  {
342
338
  "pathPattern": "/chats/{chat-id}/messages",
343
339
  "method": "post",
344
340
  "toolName": "send-chat-message",
345
- "scopes": ["ChatMessage.Send"],
346
- "requiresWorkAccount": true
341
+ "workScopes": ["ChatMessage.Send"]
347
342
  },
348
343
  {
349
344
  "pathPattern": "/me/joinedTeams",
350
345
  "method": "get",
351
346
  "toolName": "list-joined-teams",
352
- "scopes": ["Team.ReadBasic.All"],
353
- "requiresWorkAccount": true
347
+ "workScopes": ["Team.ReadBasic.All"]
354
348
  },
355
349
  {
356
350
  "pathPattern": "/teams/{team-id}",
357
351
  "method": "get",
358
352
  "toolName": "get-team",
359
- "scopes": ["Team.ReadBasic.All"],
360
- "requiresWorkAccount": true
353
+ "workScopes": ["Team.ReadBasic.All"]
361
354
  },
362
355
  {
363
356
  "pathPattern": "/teams/{team-id}/channels",
364
357
  "method": "get",
365
358
  "toolName": "list-team-channels",
366
- "scopes": ["Channel.ReadBasic.All"],
367
- "requiresWorkAccount": true
359
+ "workScopes": ["Channel.ReadBasic.All"]
368
360
  },
369
361
  {
370
362
  "pathPattern": "/teams/{team-id}/channels/{channel-id}",
371
363
  "method": "get",
372
364
  "toolName": "get-team-channel",
373
- "scopes": ["Channel.ReadBasic.All"],
374
- "requiresWorkAccount": true
365
+ "workScopes": ["Channel.ReadBasic.All"]
375
366
  },
376
367
  {
377
368
  "pathPattern": "/teams/{team-id}/channels/{channel-id}/messages",
378
369
  "method": "get",
379
370
  "toolName": "list-channel-messages",
380
- "scopes": ["ChannelMessage.Read.All"],
381
- "requiresWorkAccount": true
371
+ "workScopes": ["ChannelMessage.Read.All"]
382
372
  },
383
373
  {
384
374
  "pathPattern": "/teams/{team-id}/channels/{channel-id}/messages/{chatMessage-id}",
385
375
  "method": "get",
386
376
  "toolName": "get-channel-message",
387
- "scopes": ["ChannelMessage.Read.All"],
388
- "requiresWorkAccount": true
377
+ "workScopes": ["ChannelMessage.Read.All"]
389
378
  },
390
379
  {
391
380
  "pathPattern": "/teams/{team-id}/channels/{channel-id}/messages",
392
381
  "method": "post",
393
382
  "toolName": "send-channel-message",
394
- "scopes": ["ChannelMessage.Send"],
395
- "requiresWorkAccount": true
383
+ "workScopes": ["ChannelMessage.Send"]
396
384
  },
397
385
  {
398
386
  "pathPattern": "/teams/{team-id}/members",
399
387
  "method": "get",
400
388
  "toolName": "list-team-members",
401
- "scopes": ["TeamMember.Read.All"],
402
- "requiresWorkAccount": true
389
+ "workScopes": ["TeamMember.Read.All"]
403
390
  },
404
391
  {
405
392
  "pathPattern": "/chats/{chat-id}/messages/{chatMessage-id}/replies",
406
393
  "method": "get",
407
394
  "toolName": "list-chat-message-replies",
408
- "scopes": ["ChatMessage.Read"],
409
- "requiresWorkAccount": true
395
+ "workScopes": ["ChatMessage.Read"]
410
396
  },
411
397
  {
412
398
  "pathPattern": "/chats/{chat-id}/messages/{chatMessage-id}/replies",
413
399
  "method": "post",
414
400
  "toolName": "reply-to-chat-message",
415
- "scopes": ["ChatMessage.Send"],
416
- "requiresWorkAccount": true
401
+ "workScopes": ["ChatMessage.Send"]
417
402
  },
418
403
  {
419
404
  "pathPattern": "/sites",
420
405
  "method": "get",
421
406
  "toolName": "search-sharepoint-sites",
422
- "scopes": ["Sites.Read.All"],
423
- "requiresWorkAccount": true
407
+ "workScopes": ["Sites.Read.All"]
424
408
  },
425
409
  {
426
410
  "pathPattern": "/sites/{site-id}",
427
411
  "method": "get",
428
412
  "toolName": "get-sharepoint-site",
429
- "scopes": ["Sites.Read.All"],
430
- "requiresWorkAccount": true
413
+ "workScopes": ["Sites.Read.All"]
431
414
  },
432
415
  {
433
416
  "pathPattern": "/sites/{site-id}/drives",
434
417
  "method": "get",
435
418
  "toolName": "list-sharepoint-site-drives",
436
- "scopes": ["Sites.Read.All"],
437
- "requiresWorkAccount": true
419
+ "workScopes": ["Sites.Read.All"]
438
420
  },
439
421
  {
440
422
  "pathPattern": "/sites/{site-id}/drives/{drive-id}",
441
423
  "method": "get",
442
424
  "toolName": "get-sharepoint-site-drive-by-id",
443
- "scopes": ["Sites.Read.All"],
444
- "requiresWorkAccount": true
425
+ "workScopes": ["Sites.Read.All"]
445
426
  },
446
427
  {
447
428
  "pathPattern": "/sites/{site-id}/items",
448
429
  "method": "get",
449
430
  "toolName": "list-sharepoint-site-items",
450
- "scopes": ["Sites.Read.All"],
451
- "requiresWorkAccount": true
431
+ "workScopes": ["Sites.Read.All"]
452
432
  },
453
433
  {
454
434
  "pathPattern": "/sites/{site-id}/items/{baseItem-id}",
455
435
  "method": "get",
456
436
  "toolName": "get-sharepoint-site-item",
457
- "scopes": ["Sites.Read.All"],
458
- "requiresWorkAccount": true
437
+ "workScopes": ["Sites.Read.All"]
459
438
  },
460
439
  {
461
440
  "pathPattern": "/sites/{site-id}/lists",
462
441
  "method": "get",
463
442
  "toolName": "list-sharepoint-site-lists",
464
- "scopes": ["Sites.Read.All"],
465
- "requiresWorkAccount": true
443
+ "workScopes": ["Sites.Read.All"]
466
444
  },
467
445
  {
468
446
  "pathPattern": "/sites/{site-id}/lists/{list-id}",
469
447
  "method": "get",
470
448
  "toolName": "get-sharepoint-site-list",
471
- "scopes": ["Sites.Read.All"],
472
- "requiresWorkAccount": true
449
+ "workScopes": ["Sites.Read.All"]
473
450
  },
474
451
  {
475
452
  "pathPattern": "/sites/{site-id}/lists/{list-id}/items",
476
453
  "method": "get",
477
454
  "toolName": "list-sharepoint-site-list-items",
478
- "scopes": ["Sites.Read.All"],
479
- "requiresWorkAccount": true
455
+ "workScopes": ["Sites.Read.All"]
480
456
  },
481
457
  {
482
458
  "pathPattern": "/sites/{site-id}/lists/{list-id}/items/{listItem-id}",
483
459
  "method": "get",
484
460
  "toolName": "get-sharepoint-site-list-item",
485
- "scopes": ["Sites.Read.All"],
486
- "requiresWorkAccount": true
461
+ "workScopes": ["Sites.Read.All"]
487
462
  },
488
463
  {
489
464
  "pathPattern": "/sites/{site-id}/getByPath(path='{path}')",
490
465
  "method": "get",
491
466
  "toolName": "get-sharepoint-site-by-path",
492
- "scopes": ["Sites.Read.All"],
493
- "requiresWorkAccount": true
467
+ "workScopes": ["Sites.Read.All"]
494
468
  },
495
469
  {
496
470
  "pathPattern": "/sites/delta()",
497
471
  "method": "get",
498
472
  "toolName": "get-sharepoint-sites-delta",
499
- "scopes": ["Sites.Read.All"],
500
- "requiresWorkAccount": true
473
+ "workScopes": ["Sites.Read.All"]
474
+ },
475
+ {
476
+ "pathPattern": "/search/query",
477
+ "method": "post",
478
+ "toolName": "search-query",
479
+ "scopes": ["Mail.Read", "Calendars.Read", "Files.Read.All", "People.Read"],
480
+ "workScopes": ["Sites.Read.All", "Chat.Read", "ChannelMessage.Read.All"]
501
481
  }
502
482
  ]