@softeria/ms-365-mcp-server 0.120.1 → 0.122.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
@@ -150,6 +150,18 @@ Scope coverage is hierarchy-aware: for example, `Mail.ReadWrite` covers tools th
150
150
 
151
151
  In HTTP mode, OAuth discovery advertises the effective filtered permissions so clients request the same consent surface. On-Behalf-Of mode (`--obo`) still advertises `api://<clientId>/access_as_user` for protected-resource metadata; `--allowed-scopes` does not override OBO.
152
152
 
153
+ ### Requesting extra scopes
154
+
155
+ `--allowed-scopes` only ever _narrows_ the token request. To request a Graph scope that no bundled tool needs — for example to drive an endpoint via `graph-batch` — use `--extra-scopes` (or `MS365_MCP_EXTRA_SCOPES`). These scopes are appended verbatim to the token request, on top of the tool-derived scopes.
156
+
157
+ ```bash
158
+ npx @softeria/ms-365-mcp-server \
159
+ --org-mode \
160
+ --extra-scopes 'CopilotPackages.ReadWrite.All'
161
+ ```
162
+
163
+ This is for use with your own Azure app registration (`MS365_MCP_CLIENT_ID` / `MS365_MCP_CLIENT_SECRET`): the default Softeria app only declares a lean, fixed permission set, so request additional scopes against an app you control (your tenant admin consents to them there). CLI value takes precedence over the env var; an empty value fails at startup.
164
+
153
165
  ## Organization/Work Mode
154
166
 
155
167
  To access work/school features (Teams, SharePoint, etc.), enable organization mode using any of these flags:
@@ -542,6 +554,7 @@ The following options can be used when running ms-365-mcp-server directly from t
542
554
  --force-work-scopes Backwards compatibility alias for --org-mode (deprecated)
543
555
  --cloud <type> Microsoft cloud environment: global (default) or china (21Vianet)
544
556
  --allowed-scopes <scopes> Limit exposed tools to Graph scopes covered by this allowlist
557
+ --extra-scopes <scopes> Append additional Graph scopes to the token request (for use with your own app registration + graph-batch)
545
558
  --expected-username <username> Require local MSAL auth to use this account username
546
559
  --expected-home-account-id <id> Require local MSAL auth to use this exact homeAccountId
547
560
  ```
package/dist/auth.js CHANGED
@@ -218,7 +218,12 @@ function buildAllowedScopeDiagnostics(options = {}) {
218
218
  };
219
219
  }
220
220
  function resolveAuthScopes(options = {}) {
221
- return buildAllowedScopeDiagnostics(options).effectivePermissions;
221
+ const toolScopes = buildAllowedScopeDiagnostics(options).effectivePermissions;
222
+ const extraScopes = parseAllowedScopes(options.extraScopes);
223
+ if (!extraScopes || extraScopes.length === 0) {
224
+ return toolScopes;
225
+ }
226
+ return Array.from(/* @__PURE__ */ new Set([...toolScopes, ...extraScopes]));
222
227
  }
223
228
  function buildScopeDiagnostics(toolScopes, allowedScopesInput) {
224
229
  const toolPermissions = [...toolScopes].sort((a, b) => a.localeCompare(b));
package/dist/cli.js CHANGED
@@ -26,6 +26,9 @@ program.name("ms-365-mcp-server").description("Microsoft 365 MCP Server").versio
26
26
  ).option(
27
27
  "--allowed-scopes <scopes>",
28
28
  "Limit exposed tools to Graph scopes covered by this whitespace-separated allowlist"
29
+ ).option(
30
+ "--extra-scopes <scopes>",
31
+ "Append additional Graph scopes (whitespace-separated) to the token request, beyond those derived from enabled tools. Use with your own app registration (MS365_MCP_CLIENT_ID/SECRET) to request scopes the default app does not declare, then call the endpoints via graph-batch."
29
32
  ).option(
30
33
  "--preset <names>",
31
34
  "Use preset tool categories (comma-separated). Available: mail, calendar, files, personal, work, excel, contacts, tasks, onenote, search, users, all"
@@ -97,6 +100,15 @@ function parseArgs() {
97
100
  );
98
101
  process.exit(1);
99
102
  }
103
+ if (options.extraScopes === void 0 && process.env.MS365_MCP_EXTRA_SCOPES !== void 0) {
104
+ options.extraScopes = process.env.MS365_MCP_EXTRA_SCOPES;
105
+ }
106
+ if (options.extraScopes !== void 0 && options.extraScopes.trim() === "") {
107
+ console.error(
108
+ "Error: --extra-scopes / MS365_MCP_EXTRA_SCOPES was provided but is empty. Provide one or more whitespace-separated scopes, or omit it."
109
+ );
110
+ process.exit(1);
111
+ }
100
112
  if (options.expectedUsername === void 0 && process.env.MS365_MCP_EXPECTED_USERNAME !== void 0) {
101
113
  options.expectedUsername = process.env.MS365_MCP_EXPECTED_USERNAME;
102
114
  }
@@ -944,6 +944,27 @@
944
944
  "presets": ["onenote", "work"],
945
945
  "workScopes": ["Notes.Read"]
946
946
  },
947
+ {
948
+ "pathPattern": "/sites/{site-id}/onenote/notebooks/{notebook-id}/sectionGroups",
949
+ "method": "get",
950
+ "toolName": "list-sharepoint-site-onenote-notebook-section-groups",
951
+ "presets": ["onenote", "work"],
952
+ "workScopes": ["Notes.Read"]
953
+ },
954
+ {
955
+ "pathPattern": "/sites/{site-id}/onenote/sectionGroups/{sectionGroup-id}/sections",
956
+ "method": "get",
957
+ "toolName": "list-sharepoint-site-onenote-section-group-sections",
958
+ "presets": ["onenote", "work"],
959
+ "workScopes": ["Notes.Read"]
960
+ },
961
+ {
962
+ "pathPattern": "/sites/{site-id}/onenote/sectionGroups/{sectionGroup-id}/sectionGroups",
963
+ "method": "get",
964
+ "toolName": "list-sharepoint-site-onenote-section-group-section-groups",
965
+ "presets": ["onenote", "work"],
966
+ "workScopes": ["Notes.Read"]
967
+ },
947
968
  {
948
969
  "pathPattern": "/sites/{site-id}/onenote/pages/{onenotePage-id}/content",
949
970
  "method": "get",
@@ -13290,6 +13290,56 @@ To list them, include system in your $select statement.`,
13290
13290
  ],
13291
13291
  response: z.void()
13292
13292
  },
13293
+ {
13294
+ method: "get",
13295
+ path: "/sites/:siteId/onenote/notebooks/:notebookId/sectionGroups",
13296
+ alias: "list-sharepoint-site-onenote-notebook-section-groups",
13297
+ description: `The section groups in the notebook. Read-only. Nullable.`,
13298
+ requestFormat: "json",
13299
+ parameters: [
13300
+ {
13301
+ name: "$top",
13302
+ type: "Query",
13303
+ schema: z.number().int().gte(0).describe("Show only the first n items").optional()
13304
+ },
13305
+ {
13306
+ name: "$skip",
13307
+ type: "Query",
13308
+ schema: z.number().int().gte(0).describe("Skip the first n items").optional()
13309
+ },
13310
+ {
13311
+ name: "$search",
13312
+ type: "Query",
13313
+ schema: z.string().describe("Search items by search phrases").optional()
13314
+ },
13315
+ {
13316
+ name: "$filter",
13317
+ type: "Query",
13318
+ schema: z.string().describe("Filter items by property values").optional()
13319
+ },
13320
+ {
13321
+ name: "$count",
13322
+ type: "Query",
13323
+ schema: z.boolean().describe("Include count of items").optional()
13324
+ },
13325
+ {
13326
+ name: "$orderby",
13327
+ type: "Query",
13328
+ schema: z.array(z.string()).describe("Order items by property values").optional()
13329
+ },
13330
+ {
13331
+ name: "$select",
13332
+ type: "Query",
13333
+ schema: z.array(z.string()).describe("Select properties to be returned").optional()
13334
+ },
13335
+ {
13336
+ name: "$expand",
13337
+ type: "Query",
13338
+ schema: z.array(z.string()).describe("Expand related entities").optional()
13339
+ }
13340
+ ],
13341
+ response: z.void()
13342
+ },
13293
13343
  {
13294
13344
  method: "get",
13295
13345
  path: "/sites/:siteId/onenote/notebooks/:notebookId/sections",
@@ -13348,6 +13398,106 @@ To list them, include system in your $select statement.`,
13348
13398
  requestFormat: "json",
13349
13399
  response: z.void()
13350
13400
  },
13401
+ {
13402
+ method: "get",
13403
+ path: "/sites/:siteId/onenote/sectionGroups/:sectionGroupId/sectionGroups",
13404
+ alias: "list-sharepoint-site-onenote-section-group-section-groups",
13405
+ description: `The section groups in the section. Read-only. Nullable.`,
13406
+ requestFormat: "json",
13407
+ parameters: [
13408
+ {
13409
+ name: "$top",
13410
+ type: "Query",
13411
+ schema: z.number().int().gte(0).describe("Show only the first n items").optional()
13412
+ },
13413
+ {
13414
+ name: "$skip",
13415
+ type: "Query",
13416
+ schema: z.number().int().gte(0).describe("Skip the first n items").optional()
13417
+ },
13418
+ {
13419
+ name: "$search",
13420
+ type: "Query",
13421
+ schema: z.string().describe("Search items by search phrases").optional()
13422
+ },
13423
+ {
13424
+ name: "$filter",
13425
+ type: "Query",
13426
+ schema: z.string().describe("Filter items by property values").optional()
13427
+ },
13428
+ {
13429
+ name: "$count",
13430
+ type: "Query",
13431
+ schema: z.boolean().describe("Include count of items").optional()
13432
+ },
13433
+ {
13434
+ name: "$orderby",
13435
+ type: "Query",
13436
+ schema: z.array(z.string()).describe("Order items by property values").optional()
13437
+ },
13438
+ {
13439
+ name: "$select",
13440
+ type: "Query",
13441
+ schema: z.array(z.string()).describe("Select properties to be returned").optional()
13442
+ },
13443
+ {
13444
+ name: "$expand",
13445
+ type: "Query",
13446
+ schema: z.array(z.string()).describe("Expand related entities").optional()
13447
+ }
13448
+ ],
13449
+ response: z.void()
13450
+ },
13451
+ {
13452
+ method: "get",
13453
+ path: "/sites/:siteId/onenote/sectionGroups/:sectionGroupId/sections",
13454
+ alias: "list-sharepoint-site-onenote-section-group-sections",
13455
+ description: `The sections in the section group. Read-only. Nullable.`,
13456
+ requestFormat: "json",
13457
+ parameters: [
13458
+ {
13459
+ name: "$top",
13460
+ type: "Query",
13461
+ schema: z.number().int().gte(0).describe("Show only the first n items").optional()
13462
+ },
13463
+ {
13464
+ name: "$skip",
13465
+ type: "Query",
13466
+ schema: z.number().int().gte(0).describe("Skip the first n items").optional()
13467
+ },
13468
+ {
13469
+ name: "$search",
13470
+ type: "Query",
13471
+ schema: z.string().describe("Search items by search phrases").optional()
13472
+ },
13473
+ {
13474
+ name: "$filter",
13475
+ type: "Query",
13476
+ schema: z.string().describe("Filter items by property values").optional()
13477
+ },
13478
+ {
13479
+ name: "$count",
13480
+ type: "Query",
13481
+ schema: z.boolean().describe("Include count of items").optional()
13482
+ },
13483
+ {
13484
+ name: "$orderby",
13485
+ type: "Query",
13486
+ schema: z.array(z.string()).describe("Order items by property values").optional()
13487
+ },
13488
+ {
13489
+ name: "$select",
13490
+ type: "Query",
13491
+ schema: z.array(z.string()).describe("Select properties to be returned").optional()
13492
+ },
13493
+ {
13494
+ name: "$expand",
13495
+ type: "Query",
13496
+ schema: z.array(z.string()).describe("Expand related entities").optional()
13497
+ }
13498
+ ],
13499
+ response: z.void()
13500
+ },
13351
13501
  {
13352
13502
  method: "get",
13353
13503
  path: "/sites/:siteId/onenote/sections/:onenoteSectionId/pages",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softeria/ms-365-mcp-server",
3
- "version": "0.120.1",
3
+ "version": "0.122.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",
@@ -944,6 +944,27 @@
944
944
  "presets": ["onenote", "work"],
945
945
  "workScopes": ["Notes.Read"]
946
946
  },
947
+ {
948
+ "pathPattern": "/sites/{site-id}/onenote/notebooks/{notebook-id}/sectionGroups",
949
+ "method": "get",
950
+ "toolName": "list-sharepoint-site-onenote-notebook-section-groups",
951
+ "presets": ["onenote", "work"],
952
+ "workScopes": ["Notes.Read"]
953
+ },
954
+ {
955
+ "pathPattern": "/sites/{site-id}/onenote/sectionGroups/{sectionGroup-id}/sections",
956
+ "method": "get",
957
+ "toolName": "list-sharepoint-site-onenote-section-group-sections",
958
+ "presets": ["onenote", "work"],
959
+ "workScopes": ["Notes.Read"]
960
+ },
961
+ {
962
+ "pathPattern": "/sites/{site-id}/onenote/sectionGroups/{sectionGroup-id}/sectionGroups",
963
+ "method": "get",
964
+ "toolName": "list-sharepoint-site-onenote-section-group-section-groups",
965
+ "presets": ["onenote", "work"],
966
+ "workScopes": ["Notes.Read"]
967
+ },
947
968
  {
948
969
  "pathPattern": "/sites/{site-id}/onenote/pages/{onenotePage-id}/content",
949
970
  "method": "get",