@softeria/ms-365-mcp-server 0.116.1 → 0.117.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
@@ -577,6 +577,8 @@ Environment variables:
577
577
  - `MS365_MCP_MAX_ITEMS=<n>`: Maximum number of items accumulated when `fetchAllPages: true` (positive integer, default `10000`). Pagination stops and the response is truncated once this many items are collected.
578
578
  - `MS365_MCP_ALLOW_PAGINATION=0|false|no`: Disable multi-page following entirely. When set, the `fetchAllPages` parameter is not advertised on tools, and any request that still passes it returns only the first page (default: pagination enabled).
579
579
  - `MS365_MCP_BODY_FORMAT=html`: Return email bodies as HTML instead of plain text (default: text)
580
+ - `MS365_MCP_RATE_LIMIT_DISABLED=true|1`: Disable per-IP rate limiting in HTTP mode (default: enabled — 30 req/min on `/authorize`, `/token`, `/register`; 120 req/min on `/mcp`)
581
+ - `MS365_MCP_TRUST_PROXY_HOPS=<n>`: Number of trusted reverse-proxy hops in HTTP mode (default `1`). Accurate per-IP rate limiting depends on this matching your deployment — set to the number of proxies in front of the server, `0` to use the raw socket peer IP, or a comma-separated subnet list
580
582
  - `MS365_MCP_CLOUD_TYPE=global|china`: Microsoft cloud environment (alternative to --cloud flag)
581
583
  - `LOG_LEVEL`: Set logging level (default: 'info')
582
584
  - `SILENT=true|1`: Disable console output
package/dist/server.js CHANGED
@@ -3,6 +3,8 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
3
3
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
4
  import { mcpAuthRouter } from "@modelcontextprotocol/sdk/server/auth/router.js";
5
5
  import express from "express";
6
+ import helmet from "helmet";
7
+ import rateLimit from "express-rate-limit";
6
8
  import logger, { enableConsoleLogging } from "./logger.js";
7
9
  import { registerAuthTools } from "./auth-tools.js";
8
10
  import { registerGraphTools, registerDiscoveryTools } from "./graph-tools.js";
@@ -167,7 +169,20 @@ class MicrosoftGraphServer {
167
169
  if (this.options.http) {
168
170
  const { host, port } = parseHttpOption(this.options.http);
169
171
  const app = express();
170
- app.set("trust proxy", true);
172
+ const trustProxyEnv = process.env.MS365_MCP_TRUST_PROXY_HOPS;
173
+ if (trustProxyEnv !== void 0 && trustProxyEnv !== "") {
174
+ const asNum = Number(trustProxyEnv);
175
+ app.set("trust proxy", Number.isFinite(asNum) ? asNum : trustProxyEnv);
176
+ } else {
177
+ app.set("trust proxy", 1);
178
+ }
179
+ app.use(
180
+ helmet({
181
+ contentSecurityPolicy: false,
182
+ crossOriginEmbedderPolicy: false,
183
+ hsts: { maxAge: 31536e3, includeSubDomains: true, preload: true }
184
+ })
185
+ );
171
186
  app.use(express.json());
172
187
  app.use(express.urlencoded({ extended: true }));
173
188
  const corsOrigin = process.env.MS365_MCP_CORS_ORIGIN || "http://localhost:3000";
@@ -184,6 +199,25 @@ class MicrosoftGraphServer {
184
199
  }
185
200
  next();
186
201
  });
202
+ const rateLimitDisabled = process.env.MS365_MCP_RATE_LIMIT_DISABLED === "true" || process.env.MS365_MCP_RATE_LIMIT_DISABLED === "1";
203
+ if (!rateLimitDisabled) {
204
+ const authLimiter = rateLimit({
205
+ windowMs: 6e4,
206
+ max: 30,
207
+ standardHeaders: "draft-7",
208
+ legacyHeaders: false
209
+ });
210
+ const mcpLimiter = rateLimit({
211
+ windowMs: 6e4,
212
+ max: 120,
213
+ standardHeaders: "draft-7",
214
+ legacyHeaders: false
215
+ });
216
+ app.use("/authorize", authLimiter);
217
+ app.use("/token", authLimiter);
218
+ app.use("/register", authLimiter);
219
+ app.use("/mcp", mcpLimiter);
220
+ }
187
221
  const oauthProvider = new MicrosoftOAuthProvider(this.authManager, this.secrets);
188
222
  const publicUrlRaw = this.options.publicUrl || process.env.MS365_MCP_PUBLIC_URL || this.options.baseUrl || process.env.MS365_MCP_BASE_URL || null;
189
223
  const publicBase = publicUrlRaw ? new URL(publicUrlRaw).href.replace(/\/$/, "") : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softeria/ms-365-mcp-server",
3
- "version": "0.116.1",
3
+ "version": "0.117.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",
@@ -39,6 +39,8 @@
39
39
  "commander": "^11.1.0",
40
40
  "dotenv": "^17.0.1",
41
41
  "express": "^5.2.1",
42
+ "express-rate-limit": "^7.5.1",
43
+ "helmet": "^8.1.0",
42
44
  "js-yaml": "^4.1.0",
43
45
  "open": "^11.0.0",
44
46
  "winston": "^3.17.0",