@softeria/ms-365-mcp-server 0.161.2 → 0.161.4
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 +10 -3
- package/dist/cli.js +4 -2
- package/dist/graph-tools.js +26 -0
- package/dist/tool-categories.js +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -633,7 +633,7 @@ npx @softeria/ms-365-mcp-server --list-presets # See all available presets
|
|
|
633
633
|
|
|
634
634
|
Available presets: `mail`, `calendar`, `files`, `personal`, `work`, `excel`, `contacts`, `tasks`, `onenote`, `search`, `users`, `outlook`, `onedrive`, `teams`, `teams-write`, `all`
|
|
635
635
|
|
|
636
|
-
Each endpoint in `endpoints.json` declares which presets it belongs to via a `presets` array, so every preset is an exact tool-name allow-list that never over-matches across apps (e.g. `mail` does not include shared-mailbox tools; those are in `work`). The universal binary reader `download-bytes` is included in every preset except `teams-write`, so whatever an app returns (a file, an attachment, a photo, a recording) can always be fetched; `get-download-url` (a pre-authenticated URL for drive/SharePoint files) rides with the drive-backed presets
|
|
636
|
+
Each endpoint in `endpoints.json` declares which presets it belongs to via a `presets` array, so every preset is an exact tool-name allow-list that never over-matches across apps (e.g. `mail` does not include shared-mailbox tools; those are in `work`). The universal binary reader `download-bytes` is included in every preset except `teams-write`, so whatever an app returns (a file, an attachment, a photo, a recording) can always be fetched; `get-download-url` (a pre-authenticated URL for drive/SharePoint files) rides with the drive-backed presets, and joins every other preset (bar `teams-write`) when HTTP mode runs with `--enable-attachment-urls`. So a preset that can find a file can always read its bytes.
|
|
637
637
|
|
|
638
638
|
The `outlook`, `onedrive` and `teams` presets are app-scoped: they expose exactly one Microsoft app. Use these for "expose exactly one app" deployments:
|
|
639
639
|
|
|
@@ -699,7 +699,8 @@ When running as an MCP server, the following options can be used:
|
|
|
699
699
|
--trust-proxy-auth
|
|
700
700
|
--enable-auth-tools Enable login/logout tools when using HTTP mode (disabled by default in HTTP mode)
|
|
701
701
|
--enable-attachment-urls Let get-download-url mint a server-served URL for byte resources Graph
|
|
702
|
-
exposes no pre-authenticated URL for (see "Server-Minted Attachment URLs")
|
|
702
|
+
exposes no pre-authenticated URL for (see "Server-Minted Attachment URLs").
|
|
703
|
+
Also adds get-download-url to any --preset that lacks it (except teams-write)
|
|
703
704
|
--attachment-port <port> Serve /attachment on its own listener on this port instead of on the
|
|
704
705
|
MCP app, so a fetcher that can read attachments cannot also reach /mcp
|
|
705
706
|
(requires --enable-attachment-urls; see "Splitting the attachment listener")
|
|
@@ -761,7 +762,13 @@ agent's context. A 73 KB, 3-page PDF costs about 24,500 tokens that way, and the
|
|
|
761
762
|
cannot parse them anyway.
|
|
762
763
|
|
|
763
764
|
`--enable-attachment-urls` (HTTP mode, off by default) closes that gap. When Graph has no
|
|
764
|
-
URL of its own, `get-download-url` mints one this server serves
|
|
765
|
+
URL of its own, `get-download-url` mints one this server serves. With it on,
|
|
766
|
+
`get-download-url` is registered under every `--preset` (except the send-only `teams-write`),
|
|
767
|
+
so a `--preset mail` agent that lists an attachment can mint a URL for it. A minted URL only
|
|
768
|
+
works if the preset's scopes cover the resource: a contacts, tasks or excel preset has no Mail
|
|
769
|
+
scopes, so a URL minted for a mail attachment fails when fetched.
|
|
770
|
+
|
|
771
|
+
The minted URL looks like:
|
|
765
772
|
|
|
766
773
|
```
|
|
767
774
|
GET /attachment?t=<ticket>&dgk=<key-id>&dgx=<expiry>&dgs=<signature>
|
package/dist/cli.js
CHANGED
|
@@ -29,7 +29,7 @@ program.name("ms-365-mcp-server").description("Microsoft 365 MCP Server").versio
|
|
|
29
29
|
"Enable login/logout tools when using HTTP mode (disabled by default in HTTP mode)"
|
|
30
30
|
).option(
|
|
31
31
|
"--enable-attachment-urls",
|
|
32
|
-
"HTTP mode only. Let get-download-url mint a short-TTL, single-use URL served by this server for Graph byte resources that expose no pre-authenticated URL of their own (mail and event attachments, meeting recordings, other $value endpoints). Requires MS365_MCP_ATTACHMENT_URL_BASE and MS365_MCP_ATTACHMENT_URL_KEY (or _KEY_FILE)"
|
|
32
|
+
"HTTP mode only. Let get-download-url mint a short-TTL, single-use URL served by this server for Graph byte resources that expose no pre-authenticated URL of their own (mail and event attachments, meeting recordings, other $value endpoints). Also adds get-download-url to any --preset that lacks it (except teams-write). Requires MS365_MCP_ATTACHMENT_URL_BASE and MS365_MCP_ATTACHMENT_URL_KEY (or _KEY_FILE)"
|
|
33
33
|
).option(
|
|
34
34
|
"--attachment-port <port>",
|
|
35
35
|
"HTTP mode only. Serve the attachment download route on its own listener on this port instead of on the MCP app, so a caller that can fetch attachments cannot also reach /mcp. Requires --enable-attachment-urls, and MS365_MCP_ATTACHMENT_URL_BASE must name this port. A separate port only isolates the two surfaces if they also bind separate interfaces \u2014 see --attachment-host. Equivalent env var: MS365_MCP_ATTACHMENT_PORT."
|
|
@@ -106,7 +106,9 @@ function parseArgs() {
|
|
|
106
106
|
if (options.preset) {
|
|
107
107
|
const presetNames = options.preset.split(",").map((p) => p.trim());
|
|
108
108
|
try {
|
|
109
|
-
options.enabledTools = getCombinedPresetPattern(presetNames
|
|
109
|
+
options.enabledTools = getCombinedPresetPattern(presetNames, {
|
|
110
|
+
attachmentUrls: Boolean(options.http && options.enableAttachmentUrls)
|
|
111
|
+
});
|
|
110
112
|
const requiresOrgMode = presetNames.some((preset) => presetRequiresOrgMode(preset));
|
|
111
113
|
if (requiresOrgMode && !options.orgMode) {
|
|
112
114
|
console.warn(
|
package/dist/graph-tools.js
CHANGED
|
@@ -1036,6 +1036,19 @@ const UTILITY_TOOLS = [
|
|
|
1036
1036
|
}
|
|
1037
1037
|
const pathPart = target.replace(/\/+$/, "");
|
|
1038
1038
|
if (/^(\/me|\/users\/[^/]+)\/messages\/[^/]+\/attachments\//.test(pathPart) || /^(\/me|\/users\/[^/]+)\/events\/[^/]+\/attachments\//.test(pathPart) || /^\/groups\/[^/]+\/messages\/[^/]+\/attachments\//.test(pathPart) || /^\/groups\/[^/]+\/events\/[^/]+\/attachments\//.test(pathPart)) {
|
|
1039
|
+
if (getAttachmentMinting() && !pathPart.endsWith("/$value")) {
|
|
1040
|
+
return {
|
|
1041
|
+
content: [
|
|
1042
|
+
{
|
|
1043
|
+
type: "text",
|
|
1044
|
+
text: JSON.stringify({
|
|
1045
|
+
error: "Only the /$value byte endpoint can be minted a download URL: end target with /$value, e.g. /me/messages/{message-id}/attachments/{attachment-id}/$value. The attachment resource itself returns JSON with base64 contentBytes."
|
|
1046
|
+
})
|
|
1047
|
+
}
|
|
1048
|
+
],
|
|
1049
|
+
isError: true
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1039
1052
|
const minted = await mintDownloadUrl(pathPart, accountParam, authManager);
|
|
1040
1053
|
if (minted) return minted;
|
|
1041
1054
|
return {
|
|
@@ -1053,6 +1066,19 @@ const UTILITY_TOOLS = [
|
|
|
1053
1066
|
if (/^(\/me|\/users\/[^/]+)\/onlineMeetings\/[^/]+\/recordings\/[^/]+(?:\/content)?$/.test(
|
|
1054
1067
|
pathPart
|
|
1055
1068
|
) || /^\/communications\/calls\/[^/]+\/recordings\/[^/]+(?:\/content)?$/.test(pathPart)) {
|
|
1069
|
+
if (getAttachmentMinting() && !pathPart.endsWith("/content")) {
|
|
1070
|
+
return {
|
|
1071
|
+
content: [
|
|
1072
|
+
{
|
|
1073
|
+
type: "text",
|
|
1074
|
+
text: JSON.stringify({
|
|
1075
|
+
error: "Only the /content byte endpoint can be minted a download URL: end target with /content, e.g. /me/onlineMeetings/{meeting-id}/recordings/{recording-id}/content."
|
|
1076
|
+
})
|
|
1077
|
+
}
|
|
1078
|
+
],
|
|
1079
|
+
isError: true
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1056
1082
|
const minted = await mintDownloadUrl(pathPart, accountParam, authManager);
|
|
1057
1083
|
if (minted) return minted;
|
|
1058
1084
|
return {
|
package/dist/tool-categories.js
CHANGED
|
@@ -101,7 +101,7 @@ const TOOL_CATEGORIES = {
|
|
|
101
101
|
description: "All available tools"
|
|
102
102
|
}
|
|
103
103
|
};
|
|
104
|
-
function getCombinedPresetPattern(presets) {
|
|
104
|
+
function getCombinedPresetPattern(presets, { attachmentUrls = false } = {}) {
|
|
105
105
|
const patterns = presets.map((preset) => {
|
|
106
106
|
const category = TOOL_CATEGORIES[preset];
|
|
107
107
|
if (!category) {
|
|
@@ -111,6 +111,9 @@ function getCombinedPresetPattern(presets) {
|
|
|
111
111
|
}
|
|
112
112
|
return category.pattern.source;
|
|
113
113
|
});
|
|
114
|
+
if (attachmentUrls && presets.some((p) => !PRESET_META[p]?.omitUniversalUtilities) && !patterns.some((p) => new RegExp(p).test("get-download-url"))) {
|
|
115
|
+
patterns.push("^get-download-url$");
|
|
116
|
+
}
|
|
114
117
|
return patterns.join("|");
|
|
115
118
|
}
|
|
116
119
|
function listPresets() {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softeria/ms-365-mcp-server",
|
|
3
3
|
"mcpName": "io.github.Softeria/ms-365-mcp-server",
|
|
4
|
-
"version": "0.161.
|
|
4
|
+
"version": "0.161.4",
|
|
5
5
|
"description": " A Model Context Protocol (MCP) server for interacting with Microsoft 365 and Office services through the Graph API",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|