@softeria/ms-365-mcp-server 0.63.1 → 0.63.2
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/server.js +48 -3
- package/logs/mcp-server.log +10 -10
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { getSecrets } from "./secrets.js";
|
|
18
18
|
import { getCloudEndpoints } from "./cloud-config.js";
|
|
19
19
|
import { requestContext } from "./request-context.js";
|
|
20
|
+
import crypto from "node:crypto";
|
|
20
21
|
function parseHttpOption(httpOption) {
|
|
21
22
|
if (typeof httpOption === "boolean") {
|
|
22
23
|
return { host: void 0, port: 3e3 };
|
|
@@ -36,6 +37,8 @@ class MicrosoftGraphServer {
|
|
|
36
37
|
this.version = "0.0.0";
|
|
37
38
|
this.multiAccount = false;
|
|
38
39
|
this.accountNames = [];
|
|
40
|
+
// Two-leg PKCE: stores client's code_challenge and server's code_verifier, keyed by OAuth state
|
|
41
|
+
this.pkceStore = /* @__PURE__ */ new Map();
|
|
39
42
|
this.authManager = authManager;
|
|
40
43
|
this.options = options;
|
|
41
44
|
this.graphClient = null;
|
|
@@ -189,14 +192,15 @@ class MicrosoftGraphServer {
|
|
|
189
192
|
const microsoftAuthUrl = new URL(
|
|
190
193
|
`${cloudEndpoints.authority}/${tenantId}/oauth2/v2.0/authorize`
|
|
191
194
|
);
|
|
195
|
+
const clientCodeChallenge = url.searchParams.get("code_challenge");
|
|
196
|
+
const clientCodeChallengeMethod = url.searchParams.get("code_challenge_method");
|
|
197
|
+
const state = url.searchParams.get("state");
|
|
192
198
|
const allowedParams = [
|
|
193
199
|
"response_type",
|
|
194
200
|
"redirect_uri",
|
|
195
201
|
"scope",
|
|
196
202
|
"state",
|
|
197
203
|
"response_mode",
|
|
198
|
-
"code_challenge",
|
|
199
|
-
"code_challenge_method",
|
|
200
204
|
"prompt",
|
|
201
205
|
"login_hint",
|
|
202
206
|
"domain_hint"
|
|
@@ -207,6 +211,32 @@ class MicrosoftGraphServer {
|
|
|
207
211
|
microsoftAuthUrl.searchParams.set(param, value);
|
|
208
212
|
}
|
|
209
213
|
});
|
|
214
|
+
if (clientCodeChallenge && state) {
|
|
215
|
+
const serverCodeVerifier = crypto.randomBytes(32).toString("base64url");
|
|
216
|
+
const serverCodeChallenge = crypto.createHash("sha256").update(serverCodeVerifier).digest("base64url");
|
|
217
|
+
this.pkceStore.set(state, {
|
|
218
|
+
clientCodeChallenge,
|
|
219
|
+
clientCodeChallengeMethod: clientCodeChallengeMethod || "S256",
|
|
220
|
+
serverCodeVerifier,
|
|
221
|
+
createdAt: Date.now()
|
|
222
|
+
});
|
|
223
|
+
const now = Date.now();
|
|
224
|
+
for (const [key, value] of this.pkceStore) {
|
|
225
|
+
if (now - value.createdAt > 10 * 60 * 1e3) {
|
|
226
|
+
this.pkceStore.delete(key);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
microsoftAuthUrl.searchParams.set("code_challenge", serverCodeChallenge);
|
|
230
|
+
microsoftAuthUrl.searchParams.set("code_challenge_method", "S256");
|
|
231
|
+
logger.info("Two-leg PKCE: stored client challenge, generated server challenge", {
|
|
232
|
+
state: state.substring(0, 8) + "..."
|
|
233
|
+
});
|
|
234
|
+
} else if (clientCodeChallenge) {
|
|
235
|
+
microsoftAuthUrl.searchParams.set("code_challenge", clientCodeChallenge);
|
|
236
|
+
if (clientCodeChallengeMethod) {
|
|
237
|
+
microsoftAuthUrl.searchParams.set("code_challenge_method", clientCodeChallengeMethod);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
210
240
|
microsoftAuthUrl.searchParams.set("client_id", clientId);
|
|
211
241
|
if (!microsoftAuthUrl.searchParams.get("scope")) {
|
|
212
242
|
microsoftAuthUrl.searchParams.set("scope", "User.Read Files.Read Mail.Read");
|
|
@@ -250,13 +280,28 @@ class MicrosoftGraphServer {
|
|
|
250
280
|
tenantId,
|
|
251
281
|
hasClientSecret: !!clientSecret
|
|
252
282
|
});
|
|
283
|
+
let serverCodeVerifier;
|
|
284
|
+
if (body.code_verifier) {
|
|
285
|
+
const clientVerifier = body.code_verifier;
|
|
286
|
+
const clientChallengeComputed = crypto.createHash("sha256").update(clientVerifier).digest("base64url");
|
|
287
|
+
for (const [state, pkceData] of this.pkceStore) {
|
|
288
|
+
if (pkceData.clientCodeChallenge === clientChallengeComputed) {
|
|
289
|
+
serverCodeVerifier = pkceData.serverCodeVerifier;
|
|
290
|
+
this.pkceStore.delete(state);
|
|
291
|
+
logger.info("Two-leg PKCE: matched client verifier, using server verifier", {
|
|
292
|
+
state: state.substring(0, 8) + "..."
|
|
293
|
+
});
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
253
298
|
const result = await exchangeCodeForToken(
|
|
254
299
|
body.code,
|
|
255
300
|
body.redirect_uri,
|
|
256
301
|
clientId,
|
|
257
302
|
clientSecret,
|
|
258
303
|
tenantId,
|
|
259
|
-
body.code_verifier,
|
|
304
|
+
serverCodeVerifier || body.code_verifier,
|
|
260
305
|
this.secrets.cloudType
|
|
261
306
|
);
|
|
262
307
|
res.json(result);
|
package/logs/mcp-server.log
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
2026-04-05 08:
|
|
2
|
-
2026-04-05 08:
|
|
3
|
-
2026-04-05 08:
|
|
4
|
-
2026-04-05 08:
|
|
5
|
-
2026-04-05 08:
|
|
6
|
-
2026-04-05 08:
|
|
7
|
-
2026-04-05 08:
|
|
8
|
-
2026-04-05 08:
|
|
9
|
-
2026-04-05 08:
|
|
10
|
-
2026-04-05 08:
|
|
1
|
+
2026-04-05 08:47:40 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
|
|
2
|
+
2026-04-05 08:47:40 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
|
|
3
|
+
2026-04-05 08:47:40 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
|
|
4
|
+
2026-04-05 08:47:40 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me/messages
|
|
5
|
+
2026-04-05 08:47:40 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me/calendar
|
|
6
|
+
2026-04-05 08:47:42 INFO: Using environment variables for secrets
|
|
7
|
+
2026-04-05 08:47:42 INFO: Using environment variables for secrets
|
|
8
|
+
2026-04-05 08:47:42 INFO: Using environment variables for secrets
|
|
9
|
+
2026-04-05 08:47:42 INFO: Using environment variables for secrets
|
|
10
|
+
2026-04-05 08:47:42 INFO: Using environment variables for secrets
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softeria/ms-365-mcp-server",
|
|
3
|
-
"version": "0.63.
|
|
3
|
+
"version": "0.63.2",
|
|
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",
|