@softeria/ms-365-mcp-server 0.107.1 → 0.108.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.
@@ -620,7 +620,7 @@
620
620
  "isExcelOp": true,
621
621
  "scopes": ["Files.ReadWrite"],
622
622
  "skipEncoding": ["address"],
623
- "llmTip": "Apply font/fill/borders/alignment/wrapText/columnWidth/rowHeight to a specific range. Required path param 'address' (e.g. 'A1:E5' or 'Sheet1!A1:E5'). Body: { font: {bold,color,size,italic,name,underline}, fill: {color}, borders: [{sideIndex,style,color,weight}], horizontalAlignment, verticalAlignment, wrapText, columnWidth, rowHeight }."
623
+ "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 }. Note: font, fill, and borders are sub-resources on rangeFormat — set them via /format/font, /format/fill, and /format/borders/{sideIndex} respectively, not on this endpoint."
624
624
  },
625
625
  {
626
626
  "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range()/sort",
@@ -704,7 +704,7 @@
704
704
  "method": "get",
705
705
  "toolName": "get-excel-used-range",
706
706
  "isExcelOp": true,
707
- "scopes": ["Files.Read"],
707
+ "scopes": ["Files.ReadWrite"],
708
708
  "llmTip": "Get the smallest range that encompasses any cells with values or formatting on the worksheet. Returns address, values, formulas, numberFormat, rowCount, columnCount. Use this to discover the populated bounds of a sheet before reading or appending — avoids guessing how far data extends. Optional $select to trim the response."
709
709
  },
710
710
  {
package/dist/server.js CHANGED
@@ -170,7 +170,11 @@ class MicrosoftGraphServer {
170
170
  const protocol = req.secure ? "https" : "http";
171
171
  const requestOrigin = `${protocol}://${req.get("host")}`;
172
172
  const browserBase = publicBase ?? requestOrigin;
173
- const scopes = buildScopesFromEndpoints(this.options.orgMode, this.options.enabledTools);
173
+ const scopes = buildScopesFromEndpoints(
174
+ this.options.orgMode,
175
+ this.options.enabledTools,
176
+ this.options.readOnly
177
+ );
174
178
  const metadata = {
175
179
  issuer: browserBase,
176
180
  authorization_endpoint: `${browserBase}/authorize`,
@@ -191,7 +195,11 @@ class MicrosoftGraphServer {
191
195
  const protocol = req.secure ? "https" : "http";
192
196
  const requestOrigin = `${protocol}://${req.get("host")}`;
193
197
  const browserBase = publicBase ?? requestOrigin;
194
- const scopes = this.options.obo ? [`api://${this.secrets.clientId}/access_as_user`] : buildScopesFromEndpoints(this.options.orgMode, this.options.enabledTools);
198
+ const scopes = this.options.obo ? [`api://${this.secrets.clientId}/access_as_user`] : buildScopesFromEndpoints(
199
+ this.options.orgMode,
200
+ this.options.enabledTools,
201
+ this.options.readOnly
202
+ );
195
203
  res.json({
196
204
  resource: `${requestOrigin}/mcp`,
197
205
  authorization_servers: [browserBase],
@@ -296,19 +304,14 @@ class MicrosoftGraphServer {
296
304
  }
297
305
  }
298
306
  microsoftAuthUrl.searchParams.set("client_id", clientId);
299
- if (!microsoftAuthUrl.searchParams.get("scope")) {
300
- microsoftAuthUrl.searchParams.set(
301
- "scope",
302
- "User.Read Files.Read Mail.Read offline_access"
303
- );
304
- } else {
305
- const scopeValue = microsoftAuthUrl.searchParams.get("scope");
306
- const scopeList = scopeValue.split(/\s+/).filter(Boolean);
307
- if (!scopeList.includes("offline_access")) {
308
- scopeList.push("offline_access");
309
- microsoftAuthUrl.searchParams.set("scope", scopeList.join(" "));
310
- }
311
- }
307
+ const clientScope = microsoftAuthUrl.searchParams.get("scope");
308
+ const baseScopes = clientScope ? clientScope.split(/\s+/).filter(Boolean) : buildScopesFromEndpoints(
309
+ this.options.orgMode,
310
+ this.options.enabledTools,
311
+ this.options.readOnly
312
+ );
313
+ const scopeSet = /* @__PURE__ */ new Set([...baseScopes, "User.Read", "offline_access"]);
314
+ microsoftAuthUrl.searchParams.set("scope", Array.from(scopeSet).join(" "));
312
315
  res.redirect(microsoftAuthUrl.toString());
313
316
  });
314
317
  app.post("/token", async (req, res) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softeria/ms-365-mcp-server",
3
- "version": "0.107.1",
3
+ "version": "0.108.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",
@@ -620,7 +620,7 @@
620
620
  "isExcelOp": true,
621
621
  "scopes": ["Files.ReadWrite"],
622
622
  "skipEncoding": ["address"],
623
- "llmTip": "Apply font/fill/borders/alignment/wrapText/columnWidth/rowHeight to a specific range. Required path param 'address' (e.g. 'A1:E5' or 'Sheet1!A1:E5'). Body: { font: {bold,color,size,italic,name,underline}, fill: {color}, borders: [{sideIndex,style,color,weight}], horizontalAlignment, verticalAlignment, wrapText, columnWidth, rowHeight }."
623
+ "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 }. Note: font, fill, and borders are sub-resources on rangeFormat — set them via /format/font, /format/fill, and /format/borders/{sideIndex} respectively, not on this endpoint."
624
624
  },
625
625
  {
626
626
  "pathPattern": "/drives/{drive-id}/items/{driveItem-id}/workbook/worksheets/{workbookWorksheet-id}/range()/sort",
@@ -704,7 +704,7 @@
704
704
  "method": "get",
705
705
  "toolName": "get-excel-used-range",
706
706
  "isExcelOp": true,
707
- "scopes": ["Files.Read"],
707
+ "scopes": ["Files.ReadWrite"],
708
708
  "llmTip": "Get the smallest range that encompasses any cells with values or formatting on the worksheet. Returns address, values, formulas, numberFormat, rowCount, columnCount. Use this to discover the populated bounds of a sheet before reading or appending — avoids guessing how far data extends. Optional $select to trim the response."
709
709
  },
710
710
  {