@softeria/ms-365-mcp-server 0.79.6 → 0.80.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/dist/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Command } from "commander";
1
+ import { Command, Option } from "commander";
2
2
  import { readFileSync } from "fs";
3
3
  import path from "path";
4
4
  import { fileURLToPath } from "url";
@@ -33,8 +33,13 @@ program.name("ms-365-mcp-server").description("Microsoft 365 MCP Server").versio
33
33
  "--auth-browser",
34
34
  "Use browser-based interactive OAuth flow instead of device code for stdio mode. Opens system browser with localhost callback for seamless sign-in."
35
35
  ).option(
36
- "--base-url <url>",
37
- "Public base URL for OAuth metadata when running behind a reverse proxy (e.g. https://mcp.example.com)"
36
+ "--public-url <url>",
37
+ "Public base URL (e.g. https://mcp.example.com) used in browser-facing OAuth redirects when running behind a reverse proxy. Server-to-server endpoints (token, register) stay on the request host."
38
+ ).addOption(
39
+ // DEPRECATED: kept only so existing deployments that set --base-url or
40
+ // MS365_MCP_BASE_URL do not crash at startup. Use --public-url /
41
+ // MS365_MCP_PUBLIC_URL instead. Hidden from --help; undocumented.
42
+ new Option("--base-url <url>", "deprecated: use --public-url").hideHelp()
38
43
  );
39
44
  function parseArgs() {
40
45
  program.parse();
package/dist/server.js CHANGED
@@ -147,14 +147,17 @@ class MicrosoftGraphServer {
147
147
  next();
148
148
  });
149
149
  const oauthProvider = new MicrosoftOAuthProvider(this.authManager, this.secrets);
150
+ const publicUrlRaw = this.options.publicUrl || process.env.MS365_MCP_PUBLIC_URL || this.options.baseUrl || process.env.MS365_MCP_BASE_URL || null;
151
+ const publicBase = publicUrlRaw ? new URL(publicUrlRaw).href.replace(/\/$/, "") : null;
150
152
  app.get("/.well-known/oauth-authorization-server", async (req, res) => {
151
153
  const protocol = req.secure ? "https" : "http";
152
- const url = new URL(`${protocol}://${req.get("host")}`);
154
+ const requestOrigin = `${protocol}://${req.get("host")}`;
155
+ const browserBase = publicBase ?? requestOrigin;
153
156
  const scopes = buildScopesFromEndpoints(this.options.orgMode, this.options.enabledTools);
154
157
  const metadata = {
155
- issuer: url.origin,
156
- authorization_endpoint: `${url.origin}/authorize`,
157
- token_endpoint: `${url.origin}/token`,
158
+ issuer: browserBase,
159
+ authorization_endpoint: `${browserBase}/authorize`,
160
+ token_endpoint: `${requestOrigin}/token`,
158
161
  response_types_supported: ["code"],
159
162
  response_modes_supported: ["query"],
160
163
  grant_types_supported: ["authorization_code", "refresh_token"],
@@ -163,20 +166,21 @@ class MicrosoftGraphServer {
163
166
  scopes_supported: scopes
164
167
  };
165
168
  if (this.options.enableDynamicRegistration) {
166
- metadata.registration_endpoint = `${url.origin}/register`;
169
+ metadata.registration_endpoint = `${requestOrigin}/register`;
167
170
  }
168
171
  res.json(metadata);
169
172
  });
170
173
  app.get("/.well-known/oauth-protected-resource", async (req, res) => {
171
174
  const protocol = req.secure ? "https" : "http";
172
- const url = new URL(`${protocol}://${req.get("host")}`);
175
+ const requestOrigin = `${protocol}://${req.get("host")}`;
176
+ const browserBase = publicBase ?? requestOrigin;
173
177
  const scopes = buildScopesFromEndpoints(this.options.orgMode, this.options.enabledTools);
174
178
  res.json({
175
- resource: `${url.origin}/mcp`,
176
- authorization_servers: [url.origin],
179
+ resource: `${requestOrigin}/mcp`,
180
+ authorization_servers: [browserBase],
177
181
  scopes_supported: scopes,
178
182
  bearer_methods_supported: ["header"],
179
- resource_documentation: `${url.origin}`
183
+ resource_documentation: browserBase
180
184
  });
181
185
  });
182
186
  if (this.options.enableDynamicRegistration) {
@@ -362,9 +366,7 @@ class MicrosoftGraphServer {
362
366
  app.use(
363
367
  mcpAuthRouter({
364
368
  provider: oauthProvider,
365
- issuerUrl: new URL(
366
- this.options.baseUrl || process.env.MS365_MCP_BASE_URL || `http://localhost:${port}`
367
- )
369
+ issuerUrl: new URL(publicBase ?? `http://localhost:${port}`)
368
370
  })
369
371
  );
370
372
  app.get(
@@ -42,7 +42,7 @@ For production, use Azure Key Vault instead of environment variables for secrets
42
42
  docker run -p 3000:3000 \
43
43
  -e MS365_MCP_KEYVAULT_URL=https://your-keyvault.vault.azure.net \
44
44
  -e MS365_MCP_ORG_MODE=true \
45
- -e MS365_MCP_BASE_URL=https://mcp.example.com \
45
+ -e MS365_MCP_PUBLIC_URL=https://mcp.example.com \
46
46
  ms-365-mcp-server \
47
47
  --http 3000 --org-mode
48
48
  ```
@@ -72,7 +72,7 @@ docker run -p 3000:3000 \
72
72
  --env-vars \
73
73
  "MS365_MCP_KEYVAULT_URL=https://your-keyvault.vault.azure.net" \
74
74
  "MS365_MCP_ORG_MODE=true" \
75
- "MS365_MCP_BASE_URL=https://mcp.example.com" \
75
+ "MS365_MCP_PUBLIC_URL=https://mcp.example.com" \
76
76
  --command "node" "dist/index.js" "--http" "3000" "--org-mode"
77
77
  ```
78
78
 
@@ -99,7 +99,7 @@ az webapp config appsettings set --name mcp-server --resource-group your-rg \
99
99
  --settings \
100
100
  MS365_MCP_KEYVAULT_URL="https://your-keyvault.vault.azure.net" \
101
101
  MS365_MCP_ORG_MODE="true" \
102
- MS365_MCP_BASE_URL="https://mcp-server.azurewebsites.net" \
102
+ MS365_MCP_PUBLIC_URL="https://mcp-server.azurewebsites.net" \
103
103
  WEBSITES_PORT="3000"
104
104
 
105
105
  az webapp config set --name mcp-server --resource-group your-rg \
@@ -130,17 +130,17 @@ When deploying for an organization, create a dedicated app registration instead
130
130
 
131
131
  ## Reverse Proxy / Custom Domain
132
132
 
133
- When running behind a reverse proxy or custom domain, set `MS365_MCP_BASE_URL` so OAuth discovery endpoints return the correct public URL:
133
+ When running behind a reverse proxy, set `MS365_MCP_PUBLIC_URL` so that the OAuth authorize URL handed back to the user's browser is resolvable from outside the server's network:
134
134
 
135
135
  ```bash
136
136
  # Via environment variable
137
- MS365_MCP_BASE_URL=https://mcp.example.com
137
+ MS365_MCP_PUBLIC_URL=https://mcp.example.com
138
138
 
139
139
  # Or via CLI flag
140
- --base-url https://mcp.example.com
140
+ --public-url https://mcp.example.com
141
141
  ```
142
142
 
143
- Without this, `/.well-known/oauth-authorization-server` would advertise `http://localhost:3000` as the authorization endpoint.
143
+ Only browser-facing fields (`issuer`, `authorization_endpoint`, `authorization_servers`) are pinned to this URL. Server-to-server endpoints (`token_endpoint`, `registration_endpoint`, `resource`) stay on the request origin, so clients that reach the server over an internal network (e.g. another container on the same Docker network) don't have to round-trip back through the public URL.
144
144
 
145
145
  ## Client Configuration
146
146
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softeria/ms-365-mcp-server",
3
- "version": "0.79.6",
3
+ "version": "0.80.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",