@softeria/ms-365-mcp-server 0.30.1 → 0.31.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/README.md +35 -0
- package/dist/cli.js +4 -1
- package/dist/graph-tools.js +3 -1
- package/dist/secrets.js +4 -3
- package/dist/server.js +30 -7
- package/glama.json +4 -0
- package/logs/mcp-server.log +5 -5
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -269,6 +269,40 @@ claude mcp add ms365-china -s user -- cmd /c "npx -y @softeria/ms-365-mcp-server
|
|
|
269
269
|
For other interfaces that support MCPs, please refer to their respective documentation for the correct
|
|
270
270
|
integration method.
|
|
271
271
|
|
|
272
|
+
### Open WebUI
|
|
273
|
+
|
|
274
|
+
Open WebUI supports MCP servers via HTTP transport with OAuth 2.1.
|
|
275
|
+
|
|
276
|
+
1. Start the server with HTTP mode and dynamic registration enabled:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
npx @softeria/ms-365-mcp-server --http --enable-dynamic-registration
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
2. In Open WebUI, go to **Admin Settings → Tools** (`/admin/settings/tools`) → **Add Connection**:
|
|
283
|
+
- **Type**: MCP Streamable HTTP
|
|
284
|
+
- **URL**: Your MCP server URL with `/mcp` path
|
|
285
|
+
- **Auth**: OAuth 2.1
|
|
286
|
+
|
|
287
|
+
3. Click **Register Client**.
|
|
288
|
+
|
|
289
|
+
> **Note**: The `--enable-dynamic-registration` is required for Open WebUI to work. If using a custom Azure Entra app, add your redirect URI under "Mobile and desktop applications" platform (not "Single-page application").
|
|
290
|
+
|
|
291
|
+
**Quick test setup** using the default Azure app (ID `ms-365` and `localhost:8080` are pre-configured):
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
docker run -d -p 8080:8080 \
|
|
295
|
+
-e WEBUI_AUTH=false \
|
|
296
|
+
-e OPENAI_API_KEY \
|
|
297
|
+
ghcr.io/open-webui/open-webui:main
|
|
298
|
+
|
|
299
|
+
npx @softeria/ms-365-mcp-server --http --enable-dynamic-registration
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Then add connection with URL `http://localhost:3000/mcp` and ID `ms-365`.
|
|
303
|
+
|
|
304
|
+

|
|
305
|
+
|
|
272
306
|
### Local Development
|
|
273
307
|
|
|
274
308
|
For local development or testing:
|
|
@@ -434,6 +468,7 @@ When running as an MCP server, the following options can be used:
|
|
|
434
468
|
--http [port] Use Streamable HTTP transport instead of stdio (optionally specify port, default: 3000)
|
|
435
469
|
Starts Express.js server with MCP endpoint at /mcp
|
|
436
470
|
--enable-auth-tools Enable login/logout tools when using HTTP mode (disabled by default in HTTP mode)
|
|
471
|
+
--enable-dynamic-registration Enable OAuth Dynamic Client Registration endpoint (required for Open WebUI)
|
|
437
472
|
--enabled-tools <pattern> Filter tools using regex pattern (e.g., "excel|contact" to enable Excel and Contact tools)
|
|
438
473
|
--preset <names> Use preset tool categories (comma-separated). See "Tool Presets" section above
|
|
439
474
|
--list-presets List all available presets and exit
|
package/dist/cli.js
CHANGED
|
@@ -23,7 +23,10 @@ program.name("ms-365-mcp-server").description("Microsoft 365 MCP Server").versio
|
|
|
23
23
|
).option("--list-presets", "List all available presets and exit").option(
|
|
24
24
|
"--org-mode",
|
|
25
25
|
"Enable organization/work mode from start (includes Teams, SharePoint, etc.)"
|
|
26
|
-
).option("--work-mode", "Alias for --org-mode").option("--force-work-scopes", "Backwards compatibility alias for --org-mode (deprecated)").option("--toon", "(experimental) Enable TOON output format for 30-60% token reduction").option("--discovery", "Enable runtime tool discovery and loading (experimental feature)").option("--cloud <type>", "Microsoft cloud environment: global (default) or china (21Vianet)")
|
|
26
|
+
).option("--work-mode", "Alias for --org-mode").option("--force-work-scopes", "Backwards compatibility alias for --org-mode (deprecated)").option("--toon", "(experimental) Enable TOON output format for 30-60% token reduction").option("--discovery", "Enable runtime tool discovery and loading (experimental feature)").option("--cloud <type>", "Microsoft cloud environment: global (default) or china (21Vianet)").option(
|
|
27
|
+
"--enable-dynamic-registration",
|
|
28
|
+
"Enable OAuth Dynamic Client Registration endpoint (required for some MCP clients like Open WebUI)"
|
|
29
|
+
);
|
|
27
30
|
function parseArgs() {
|
|
28
31
|
program.parse();
|
|
29
32
|
const options = program.opts();
|
package/dist/graph-tools.js
CHANGED
|
@@ -45,7 +45,9 @@ async function executeGraphTool(tool, config, graphClient, params) {
|
|
|
45
45
|
path2 = path2.replace(`{${paramName}}`, encodeURIComponent(paramValue)).replace(`:${paramName}`, encodeURIComponent(paramValue));
|
|
46
46
|
break;
|
|
47
47
|
case "Query":
|
|
48
|
-
|
|
48
|
+
if (paramValue !== "" && paramValue != null) {
|
|
49
|
+
queryParams[fixedParamName] = `${paramValue}`;
|
|
50
|
+
}
|
|
49
51
|
break;
|
|
50
52
|
case "Body":
|
|
51
53
|
if (paramDef.schema) {
|
package/dist/secrets.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import logger from "./logger.js";
|
|
2
|
-
import { parseCloudType } from "./cloud-config.js";
|
|
2
|
+
import { parseCloudType, getDefaultClientId } from "./cloud-config.js";
|
|
3
3
|
class EnvironmentSecretsProvider {
|
|
4
4
|
async getSecrets() {
|
|
5
|
+
const cloudType = parseCloudType(process.env.MS365_MCP_CLOUD_TYPE);
|
|
5
6
|
return {
|
|
6
|
-
clientId: process.env.MS365_MCP_CLIENT_ID ||
|
|
7
|
+
clientId: process.env.MS365_MCP_CLIENT_ID || getDefaultClientId(cloudType),
|
|
7
8
|
tenantId: process.env.MS365_MCP_TENANT_ID || "common",
|
|
8
9
|
clientSecret: process.env.MS365_MCP_CLIENT_SECRET,
|
|
9
|
-
cloudType
|
|
10
|
+
cloudType
|
|
10
11
|
};
|
|
11
12
|
}
|
|
12
13
|
}
|
package/dist/server.js
CHANGED
|
@@ -108,7 +108,7 @@ class MicrosoftGraphServer {
|
|
|
108
108
|
const protocol = req.secure ? "https" : "http";
|
|
109
109
|
const url = new URL(`${protocol}://${req.get("host")}`);
|
|
110
110
|
const scopes = buildScopesFromEndpoints(this.options.orgMode, this.options.enabledTools);
|
|
111
|
-
|
|
111
|
+
const metadata = {
|
|
112
112
|
issuer: url.origin,
|
|
113
113
|
authorization_endpoint: `${url.origin}/authorize`,
|
|
114
114
|
token_endpoint: `${url.origin}/token`,
|
|
@@ -118,7 +118,11 @@ class MicrosoftGraphServer {
|
|
|
118
118
|
token_endpoint_auth_methods_supported: ["none"],
|
|
119
119
|
code_challenge_methods_supported: ["S256"],
|
|
120
120
|
scopes_supported: scopes
|
|
121
|
-
}
|
|
121
|
+
};
|
|
122
|
+
if (this.options.enableDynamicRegistration) {
|
|
123
|
+
metadata.registration_endpoint = `${url.origin}/register`;
|
|
124
|
+
}
|
|
125
|
+
res.json(metadata);
|
|
122
126
|
});
|
|
123
127
|
app.get("/.well-known/oauth-protected-resource", async (req, res) => {
|
|
124
128
|
const protocol = req.secure ? "https" : "http";
|
|
@@ -132,6 +136,22 @@ class MicrosoftGraphServer {
|
|
|
132
136
|
resource_documentation: `${url.origin}`
|
|
133
137
|
});
|
|
134
138
|
});
|
|
139
|
+
if (this.options.enableDynamicRegistration) {
|
|
140
|
+
app.post("/register", async (req, res) => {
|
|
141
|
+
const body = req.body;
|
|
142
|
+
logger.info("Client registration request", { body });
|
|
143
|
+
const clientId = `mcp-client-${Date.now()}`;
|
|
144
|
+
res.status(201).json({
|
|
145
|
+
client_id: clientId,
|
|
146
|
+
client_id_issued_at: Math.floor(Date.now() / 1e3),
|
|
147
|
+
redirect_uris: body.redirect_uris || [],
|
|
148
|
+
grant_types: body.grant_types || ["authorization_code", "refresh_token"],
|
|
149
|
+
response_types: body.response_types || ["code"],
|
|
150
|
+
token_endpoint_auth_method: body.token_endpoint_auth_method || "none",
|
|
151
|
+
client_name: body.client_name || "MCP Client"
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
135
155
|
app.get("/authorize", async (req, res) => {
|
|
136
156
|
const url = new URL(req.url, `${req.protocol}://${req.get("host")}`);
|
|
137
157
|
const tenantId = this.secrets?.tenantId || "common";
|
|
@@ -193,11 +213,14 @@ class MicrosoftGraphServer {
|
|
|
193
213
|
const tenantId = this.secrets?.tenantId || "common";
|
|
194
214
|
const clientId = this.secrets.clientId;
|
|
195
215
|
const clientSecret = this.secrets?.clientSecret;
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
216
|
+
logger.info("Token endpoint: authorization_code exchange", {
|
|
217
|
+
redirect_uri: body.redirect_uri,
|
|
218
|
+
has_code: !!body.code,
|
|
219
|
+
has_code_verifier: !!body.code_verifier,
|
|
220
|
+
clientId,
|
|
221
|
+
tenantId,
|
|
222
|
+
hasClientSecret: !!clientSecret
|
|
223
|
+
});
|
|
201
224
|
const result = await exchangeCodeForToken(
|
|
202
225
|
body.code,
|
|
203
226
|
body.redirect_uri,
|
package/glama.json
ADDED
package/logs/mcp-server.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
2026-01-
|
|
2
|
-
2026-01-
|
|
3
|
-
2026-01-
|
|
4
|
-
2026-01-
|
|
5
|
-
2026-01-
|
|
1
|
+
2026-01-27 11:31:49 INFO: Using environment variables for secrets
|
|
2
|
+
2026-01-27 11:31:49 INFO: Using environment variables for secrets
|
|
3
|
+
2026-01-27 11:31:49 INFO: Using environment variables for secrets
|
|
4
|
+
2026-01-27 11:31:49 INFO: Using environment variables for secrets
|
|
5
|
+
2026-01-27 11:31:49 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.
|
|
3
|
+
"version": "0.31.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",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@semantic-release/exec": "^7.1.0",
|
|
54
54
|
"@semantic-release/git": "^10.0.1",
|
|
55
55
|
"@semantic-release/github": "^11.0.3",
|
|
56
|
-
"@semantic-release/npm": "^
|
|
56
|
+
"@semantic-release/npm": "^13.1.3",
|
|
57
57
|
"@types/express": "^5.0.3",
|
|
58
58
|
"@types/node": "^22.15.15",
|
|
59
59
|
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"globals": "^16.3.0",
|
|
64
64
|
"patch-package": "^8.0.1",
|
|
65
65
|
"prettier": "^3.5.3",
|
|
66
|
-
"semantic-release": "^
|
|
66
|
+
"semantic-release": "^25.0.2",
|
|
67
67
|
"tsup": "^8.5.0",
|
|
68
68
|
"tsx": "^4.19.4",
|
|
69
69
|
"typescript": "^5.8.3",
|