@softeria/ms-365-mcp-server 0.127.0 → 0.128.1
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/endpoints.json +1 -0
- package/dist/graph-client.js +2 -0
- package/dist/graph-tools.js +15 -5
- package/dist/lib/microsoft-auth.js +17 -4
- package/dist/lib/tool-schema.js +2 -2
- package/dist/server.js +9 -6
- package/package.json +1 -1
- package/src/endpoints.json +1 -0
package/dist/endpoints.json
CHANGED
|
@@ -359,6 +359,7 @@
|
|
|
359
359
|
"toolName": "create-calendar-event",
|
|
360
360
|
"presets": ["calendar", "outlook", "personal"],
|
|
361
361
|
"scopes": ["Calendars.ReadWrite"],
|
|
362
|
+
"descriptionOverride": "Create (schedule) a new calendar event — a meeting or appointment — on the user's calendar. Set subject, start/end times, time zone, location, body, and attendees; supports online meetings and recurrence.",
|
|
362
363
|
"llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients."
|
|
363
364
|
},
|
|
364
365
|
{
|
package/dist/graph-client.js
CHANGED
package/dist/graph-tools.js
CHANGED
|
@@ -170,7 +170,10 @@ const UTILITY_TOOLS = [
|
|
|
170
170
|
if (authManager && !authManager.isOAuthModeEnabled() && !getRequestTokens()) {
|
|
171
171
|
accountAccessToken = await authManager.getTokenForAccount(accountParam);
|
|
172
172
|
}
|
|
173
|
-
return await graphClient.graphRequest(target, {
|
|
173
|
+
return await graphClient.graphRequest(target, {
|
|
174
|
+
accessToken: accountAccessToken,
|
|
175
|
+
rawResponse: true
|
|
176
|
+
});
|
|
174
177
|
} catch (error) {
|
|
175
178
|
return {
|
|
176
179
|
content: [{ type: "text", text: JSON.stringify({ error: error.message }) }],
|
|
@@ -823,7 +826,7 @@ function registerGraphTools(server, graphClient, readOnly = false, enabledToolsP
|
|
|
823
826
|
).optional();
|
|
824
827
|
}
|
|
825
828
|
let toolDescription = withApiVersionPrefix(
|
|
826
|
-
tool.description || `Execute ${tool.method.toUpperCase()} request to ${tool.path}`,
|
|
829
|
+
(endpointConfig?.descriptionOverride ?? tool.description) || `Execute ${tool.method.toUpperCase()} request to ${tool.path}`,
|
|
827
830
|
endpointConfig
|
|
828
831
|
);
|
|
829
832
|
if (endpointConfig?.llmTip) {
|
|
@@ -920,7 +923,10 @@ function buildDiscoverySearchIndex(toolsRegistry, utilityTools = []) {
|
|
|
920
923
|
const nt = tokenize(name);
|
|
921
924
|
nameTokens.set(name, new Set(nt));
|
|
922
925
|
const pathTokens = tokenize(tool.path);
|
|
923
|
-
const descTokens = tokenize(tool.description).slice(
|
|
926
|
+
const descTokens = tokenize(config?.descriptionOverride ?? tool.description).slice(
|
|
927
|
+
0,
|
|
928
|
+
DESC_CAP_TOKENS
|
|
929
|
+
);
|
|
924
930
|
const tipTokens = tokenize(config?.llmTip).slice(0, TIP_EXCERPT_TOKENS);
|
|
925
931
|
const tokens = [
|
|
926
932
|
...nt,
|
|
@@ -1032,7 +1038,7 @@ function registerDiscoveryTools(server, graphClient, readOnly = false, orgMode =
|
|
|
1032
1038
|
method: tool.method.toUpperCase(),
|
|
1033
1039
|
path: tool.path,
|
|
1034
1040
|
description: withApiVersionPrefix(
|
|
1035
|
-
tool.description || `${tool.method.toUpperCase()} ${tool.path}`,
|
|
1041
|
+
(config?.descriptionOverride ?? tool.description) || `${tool.method.toUpperCase()} ${tool.path}`,
|
|
1036
1042
|
config
|
|
1037
1043
|
),
|
|
1038
1044
|
...config?.llmTip ? { llmTip: config.llmTip } : {}
|
|
@@ -1111,7 +1117,11 @@ function registerDiscoveryTools(server, graphClient, readOnly = false, orgMode =
|
|
|
1111
1117
|
async ({ tool_name }) => {
|
|
1112
1118
|
const entry = toolsRegistry.get(tool_name);
|
|
1113
1119
|
if (entry) {
|
|
1114
|
-
const schema = describeToolSchema(
|
|
1120
|
+
const schema = describeToolSchema(
|
|
1121
|
+
entry.tool,
|
|
1122
|
+
entry.config?.llmTip,
|
|
1123
|
+
entry.config?.descriptionOverride
|
|
1124
|
+
);
|
|
1115
1125
|
return {
|
|
1116
1126
|
content: [{ type: "text", text: JSON.stringify(schema, null, 2) }]
|
|
1117
1127
|
};
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import logger from "../logger.js";
|
|
2
2
|
import { getCloudEndpoints } from "../cloud-config.js";
|
|
3
|
-
function
|
|
3
|
+
function buildResourceMetadataUrl(req, publicUrl) {
|
|
4
|
+
if (publicUrl) {
|
|
5
|
+
const parsed = new URL(publicUrl);
|
|
6
|
+
const path = parsed.pathname.replace(/\/$/, "");
|
|
7
|
+
return `${parsed.origin}/.well-known/oauth-protected-resource${path}`;
|
|
8
|
+
}
|
|
4
9
|
const protocol = req.secure ? "https" : "http";
|
|
5
10
|
const origin = `${protocol}://${req.get("host")}`;
|
|
6
|
-
|
|
11
|
+
return `${origin}/.well-known/oauth-protected-resource`;
|
|
12
|
+
}
|
|
13
|
+
function buildWwwAuthenticate(req, error, description, publicUrl) {
|
|
14
|
+
const resourceMetadata = buildResourceMetadataUrl(req, publicUrl);
|
|
7
15
|
return `Bearer resource_metadata="${resourceMetadata}", error="${error}", error_description="${description}"`;
|
|
8
16
|
}
|
|
9
17
|
function isJwtExpired(token) {
|
|
@@ -46,7 +54,12 @@ const microsoftBearerTokenAuthMiddleware = (opts = {}) => (req, res, next) => {
|
|
|
46
54
|
}
|
|
47
55
|
res.status(401).set(
|
|
48
56
|
"WWW-Authenticate",
|
|
49
|
-
buildWwwAuthenticate(
|
|
57
|
+
buildWwwAuthenticate(
|
|
58
|
+
req,
|
|
59
|
+
"invalid_token",
|
|
60
|
+
"Missing or malformed Authorization header",
|
|
61
|
+
opts.publicUrl
|
|
62
|
+
)
|
|
50
63
|
).json({
|
|
51
64
|
error: "invalid_token",
|
|
52
65
|
error_description: "Missing or malformed Authorization header"
|
|
@@ -57,7 +70,7 @@ const microsoftBearerTokenAuthMiddleware = (opts = {}) => (req, res, next) => {
|
|
|
57
70
|
if (isJwtExpired(accessToken)) {
|
|
58
71
|
res.status(401).set(
|
|
59
72
|
"WWW-Authenticate",
|
|
60
|
-
buildWwwAuthenticate(req, "invalid_token", "The access token has expired")
|
|
73
|
+
buildWwwAuthenticate(req, "invalid_token", "The access token has expired", opts.publicUrl)
|
|
61
74
|
).json({ error: "invalid_token", error_description: "The access token has expired" });
|
|
62
75
|
return;
|
|
63
76
|
}
|
package/dist/lib/tool-schema.js
CHANGED
|
@@ -7,7 +7,7 @@ function unwrapOptional(schema) {
|
|
|
7
7
|
}
|
|
8
8
|
return { inner: schema, optional: false };
|
|
9
9
|
}
|
|
10
|
-
function describeToolSchema(tool, llmTip) {
|
|
10
|
+
function describeToolSchema(tool, llmTip, descriptionOverride) {
|
|
11
11
|
const params = (tool.parameters ?? []).map((p) => {
|
|
12
12
|
const { inner, optional } = unwrapOptional(p.schema);
|
|
13
13
|
const isPath = p.type === "Path";
|
|
@@ -25,7 +25,7 @@ function describeToolSchema(tool, llmTip) {
|
|
|
25
25
|
name: tool.alias,
|
|
26
26
|
method: tool.method.toUpperCase(),
|
|
27
27
|
path: tool.path,
|
|
28
|
-
description: tool.description ?? "",
|
|
28
|
+
description: descriptionOverride ?? tool.description ?? "",
|
|
29
29
|
...llmTip ? { llmTip } : {},
|
|
30
30
|
parameters: params
|
|
31
31
|
};
|
package/dist/server.js
CHANGED
|
@@ -229,7 +229,7 @@ class MicrosoftGraphServer {
|
|
|
229
229
|
const metadata = {
|
|
230
230
|
issuer: browserBase,
|
|
231
231
|
authorization_endpoint: `${browserBase}/authorize`,
|
|
232
|
-
token_endpoint: `${
|
|
232
|
+
token_endpoint: `${browserBase}/token`,
|
|
233
233
|
response_types_supported: ["code"],
|
|
234
234
|
response_modes_supported: ["query"],
|
|
235
235
|
grant_types_supported: ["authorization_code", "refresh_token"],
|
|
@@ -238,23 +238,25 @@ class MicrosoftGraphServer {
|
|
|
238
238
|
scopes_supported: scopes
|
|
239
239
|
};
|
|
240
240
|
if (this.options.enableDynamicRegistration) {
|
|
241
|
-
metadata.registration_endpoint = `${
|
|
241
|
+
metadata.registration_endpoint = `${browserBase}/register`;
|
|
242
242
|
}
|
|
243
243
|
res.json(metadata);
|
|
244
244
|
});
|
|
245
|
-
|
|
245
|
+
const protectedResourcesHandler = async (req, res) => {
|
|
246
246
|
const protocol = req.secure ? "https" : "http";
|
|
247
247
|
const requestOrigin = `${protocol}://${req.get("host")}`;
|
|
248
248
|
const browserBase = publicBase ?? requestOrigin;
|
|
249
249
|
const scopes = this.options.obo ? [`${this.secrets.clientId}/access_as_user`] : resolveAuthScopes(this.options);
|
|
250
250
|
res.json({
|
|
251
|
-
resource: `${
|
|
251
|
+
resource: `${browserBase}/mcp`,
|
|
252
252
|
authorization_servers: [browserBase],
|
|
253
253
|
scopes_supported: scopes,
|
|
254
254
|
bearer_methods_supported: ["header"],
|
|
255
255
|
resource_documentation: browserBase
|
|
256
256
|
});
|
|
257
|
-
}
|
|
257
|
+
};
|
|
258
|
+
app.get("/.well-known/oauth-protected-resource", protectedResourcesHandler);
|
|
259
|
+
app.get("/.well-known/oauth-protected-resource/*path", protectedResourcesHandler);
|
|
258
260
|
if (this.options.enableDynamicRegistration) {
|
|
259
261
|
app.post("/register", async (req, res) => {
|
|
260
262
|
const body = req.body;
|
|
@@ -470,7 +472,8 @@ class MicrosoftGraphServer {
|
|
|
470
472
|
);
|
|
471
473
|
const mcpAuth = microsoftBearerTokenAuthMiddleware({
|
|
472
474
|
trustProxyAuth: this.options.trustProxyAuth,
|
|
473
|
-
allowUnauthenticatedDiscovery: this.options.allowUnauthenticatedDiscovery
|
|
475
|
+
allowUnauthenticatedDiscovery: this.options.allowUnauthenticatedDiscovery,
|
|
476
|
+
publicUrl: publicBase
|
|
474
477
|
});
|
|
475
478
|
app.get(
|
|
476
479
|
"/mcp",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softeria/ms-365-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.128.1",
|
|
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",
|
package/src/endpoints.json
CHANGED
|
@@ -359,6 +359,7 @@
|
|
|
359
359
|
"toolName": "create-calendar-event",
|
|
360
360
|
"presets": ["calendar", "outlook", "personal"],
|
|
361
361
|
"scopes": ["Calendars.ReadWrite"],
|
|
362
|
+
"descriptionOverride": "Create (schedule) a new calendar event — a meeting or appointment — on the user's calendar. Set subject, start/end times, time zone, location, body, and attendees; supports online meetings and recurrence.",
|
|
362
363
|
"llmTip": "CRITICAL: Do not try to guess the email address of the recipients. Use the list-users tool to find the email address of the recipients."
|
|
363
364
|
},
|
|
364
365
|
{
|