@softeria/ms-365-mcp-server 0.82.0 → 0.83.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/graph-client.js +2 -30
- package/dist/lib/microsoft-auth.js +32 -6
- package/dist/server.js +2 -14
- package/package.json +1 -1
package/dist/graph-client.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import logger from "./logger.js";
|
|
2
|
-
import { refreshAccessToken } from "./lib/microsoft-auth.js";
|
|
3
2
|
import { encode as toonEncode } from "@toon-format/toon";
|
|
4
3
|
import { getCloudEndpoints } from "./cloud-config.js";
|
|
5
4
|
import { getRequestTokens } from "./request-context.js";
|
|
@@ -33,18 +32,12 @@ class GraphClient {
|
|
|
33
32
|
}
|
|
34
33
|
async makeRequest(endpoint, options = {}) {
|
|
35
34
|
const contextTokens = getRequestTokens();
|
|
36
|
-
|
|
37
|
-
const refreshToken = options.refreshToken ?? contextTokens?.refreshToken;
|
|
35
|
+
const accessToken = options.accessToken ?? contextTokens?.accessToken ?? await this.authManager.getToken();
|
|
38
36
|
if (!accessToken) {
|
|
39
37
|
throw new Error("No access token available");
|
|
40
38
|
}
|
|
41
39
|
try {
|
|
42
|
-
|
|
43
|
-
if (response.status === 401 && refreshToken) {
|
|
44
|
-
const newTokens = await this.refreshAccessToken(refreshToken);
|
|
45
|
-
accessToken = newTokens.accessToken;
|
|
46
|
-
response = await this.performRequest(endpoint, accessToken, options);
|
|
47
|
-
}
|
|
40
|
+
const response = await this.performRequest(endpoint, accessToken, options);
|
|
48
41
|
if (response.status === 403) {
|
|
49
42
|
const errorText = await response.text();
|
|
50
43
|
if (errorText.includes("scope") || errorText.includes("permission")) {
|
|
@@ -100,27 +93,6 @@ class GraphClient {
|
|
|
100
93
|
throw error;
|
|
101
94
|
}
|
|
102
95
|
}
|
|
103
|
-
async refreshAccessToken(refreshToken) {
|
|
104
|
-
const tenantId = this.secrets.tenantId || "common";
|
|
105
|
-
const clientId = this.secrets.clientId;
|
|
106
|
-
const clientSecret = this.secrets.clientSecret;
|
|
107
|
-
if (clientSecret) {
|
|
108
|
-
logger.info("GraphClient: Refreshing token with confidential client");
|
|
109
|
-
} else {
|
|
110
|
-
logger.info("GraphClient: Refreshing token with public client");
|
|
111
|
-
}
|
|
112
|
-
const response = await refreshAccessToken(
|
|
113
|
-
refreshToken,
|
|
114
|
-
clientId,
|
|
115
|
-
clientSecret,
|
|
116
|
-
tenantId,
|
|
117
|
-
this.secrets.cloudType
|
|
118
|
-
);
|
|
119
|
-
return {
|
|
120
|
-
accessToken: response.access_token,
|
|
121
|
-
refreshToken: response.refresh_token
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
96
|
async performRequest(endpoint, accessToken, options) {
|
|
125
97
|
const cloudEndpoints = getCloudEndpoints(this.secrets.cloudType);
|
|
126
98
|
const url = `${cloudEndpoints.graphApi}/v1.0${endpoint}`;
|
|
@@ -1,17 +1,43 @@
|
|
|
1
1
|
import logger from "../logger.js";
|
|
2
2
|
import { getCloudEndpoints } from "../cloud-config.js";
|
|
3
|
+
function buildWwwAuthenticate(req, error, description) {
|
|
4
|
+
const protocol = req.secure ? "https" : "http";
|
|
5
|
+
const origin = `${protocol}://${req.get("host")}`;
|
|
6
|
+
const resourceMetadata = `${origin}/.well-known/oauth-protected-resource`;
|
|
7
|
+
return `Bearer resource_metadata="${resourceMetadata}", error="${error}", error_description="${description}"`;
|
|
8
|
+
}
|
|
9
|
+
function isJwtExpired(token) {
|
|
10
|
+
const parts = token.split(".");
|
|
11
|
+
if (parts.length !== 3) return false;
|
|
12
|
+
try {
|
|
13
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
|
|
14
|
+
if (typeof payload.exp !== "number") return false;
|
|
15
|
+
return payload.exp * 1e3 < Date.now();
|
|
16
|
+
} catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
3
20
|
const microsoftBearerTokenAuthMiddleware = (req, res, next) => {
|
|
4
21
|
const authHeader = req.headers.authorization;
|
|
5
22
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
6
|
-
res.status(401).
|
|
23
|
+
res.status(401).set(
|
|
24
|
+
"WWW-Authenticate",
|
|
25
|
+
buildWwwAuthenticate(req, "invalid_token", "Missing or malformed Authorization header")
|
|
26
|
+
).json({
|
|
27
|
+
error: "invalid_token",
|
|
28
|
+
error_description: "Missing or malformed Authorization header"
|
|
29
|
+
});
|
|
7
30
|
return;
|
|
8
31
|
}
|
|
9
32
|
const accessToken = authHeader.substring(7);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
33
|
+
if (isJwtExpired(accessToken)) {
|
|
34
|
+
res.status(401).set(
|
|
35
|
+
"WWW-Authenticate",
|
|
36
|
+
buildWwwAuthenticate(req, "invalid_token", "The access token has expired")
|
|
37
|
+
).json({ error: "invalid_token", error_description: "The access token has expired" });
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
req.microsoftAuth = { accessToken };
|
|
15
41
|
next();
|
|
16
42
|
};
|
|
17
43
|
async function exchangeCodeForToken(code, redirectUri, clientId, clientSecret, tenantId = "common", codeVerifier, cloudType = "global") {
|
package/dist/server.js
CHANGED
|
@@ -388,13 +388,7 @@ class MicrosoftGraphServer {
|
|
|
388
388
|
};
|
|
389
389
|
try {
|
|
390
390
|
if (req.microsoftAuth) {
|
|
391
|
-
await requestContext.run(
|
|
392
|
-
{
|
|
393
|
-
accessToken: req.microsoftAuth.accessToken,
|
|
394
|
-
refreshToken: req.microsoftAuth.refreshToken
|
|
395
|
-
},
|
|
396
|
-
handler
|
|
397
|
-
);
|
|
391
|
+
await requestContext.run({ accessToken: req.microsoftAuth.accessToken }, handler);
|
|
398
392
|
} else {
|
|
399
393
|
await handler();
|
|
400
394
|
}
|
|
@@ -432,13 +426,7 @@ class MicrosoftGraphServer {
|
|
|
432
426
|
};
|
|
433
427
|
try {
|
|
434
428
|
if (req.microsoftAuth) {
|
|
435
|
-
await requestContext.run(
|
|
436
|
-
{
|
|
437
|
-
accessToken: req.microsoftAuth.accessToken,
|
|
438
|
-
refreshToken: req.microsoftAuth.refreshToken
|
|
439
|
-
},
|
|
440
|
-
handler
|
|
441
|
-
);
|
|
429
|
+
await requestContext.run({ accessToken: req.microsoftAuth.accessToken }, handler);
|
|
442
430
|
} else {
|
|
443
431
|
await handler();
|
|
444
432
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softeria/ms-365-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.83.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",
|