@softeria/ms-365-mcp-server 0.36.1 → 0.37.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 +19 -0
- package/dist/auth.js +41 -15
- package/logs/mcp-server.log +10 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -490,6 +490,25 @@ Environment variables:
|
|
|
490
490
|
- `MS365_MCP_TENANT_ID`: Custom tenant ID (defaults to 'common' for multi-tenant)
|
|
491
491
|
- `MS365_MCP_OAUTH_TOKEN`: Pre-existing OAuth token for Microsoft Graph API (BYOT method)
|
|
492
492
|
- `MS365_MCP_KEYVAULT_URL`: Azure Key Vault URL for secrets management (see Azure Key Vault section)
|
|
493
|
+
- `MS365_MCP_TOKEN_CACHE_PATH`: Custom file path for MSAL token cache (see Token Storage below)
|
|
494
|
+
- `MS365_MCP_SELECTED_ACCOUNT_PATH`: Custom file path for selected account metadata (see Token Storage below)
|
|
495
|
+
|
|
496
|
+
## Token Storage
|
|
497
|
+
|
|
498
|
+
Authentication tokens are stored using the OS credential store (via keytar) when available. If keytar is not installed or fails (common on headless Linux), the server falls back to file-based storage.
|
|
499
|
+
|
|
500
|
+
**Default fallback paths** are relative to the installed package directory. This means tokens can be lost when the package is reinstalled or updated via npm.
|
|
501
|
+
|
|
502
|
+
To persist tokens across updates, set custom paths outside the package directory:
|
|
503
|
+
|
|
504
|
+
```bash
|
|
505
|
+
export MS365_MCP_TOKEN_CACHE_PATH="$HOME/.config/ms365-mcp/.token-cache.json"
|
|
506
|
+
export MS365_MCP_SELECTED_ACCOUNT_PATH="$HOME/.config/ms365-mcp/.selected-account.json"
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
Parent directories are created automatically. Files are written with `0600` permissions.
|
|
510
|
+
|
|
511
|
+
> **Security note**: File-based token storage writes sensitive credentials to disk. Ensure the chosen directory has appropriate access controls. The OS credential store (keytar) is preferred when available.
|
|
493
512
|
|
|
494
513
|
## Azure Key Vault Integration
|
|
495
514
|
|
package/dist/auth.js
CHANGED
|
@@ -34,8 +34,20 @@ const SERVICE_NAME = "ms-365-mcp-server";
|
|
|
34
34
|
const TOKEN_CACHE_ACCOUNT = "msal-token-cache";
|
|
35
35
|
const SELECTED_ACCOUNT_KEY = "selected-account";
|
|
36
36
|
const FALLBACK_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
37
|
-
const
|
|
38
|
-
const
|
|
37
|
+
const DEFAULT_TOKEN_CACHE_PATH = path.join(FALLBACK_DIR, "..", ".token-cache.json");
|
|
38
|
+
const DEFAULT_SELECTED_ACCOUNT_PATH = path.join(FALLBACK_DIR, "..", ".selected-account.json");
|
|
39
|
+
function getTokenCachePath() {
|
|
40
|
+
const envPath = process.env.MS365_MCP_TOKEN_CACHE_PATH?.trim();
|
|
41
|
+
return envPath || DEFAULT_TOKEN_CACHE_PATH;
|
|
42
|
+
}
|
|
43
|
+
function getSelectedAccountPath() {
|
|
44
|
+
const envPath = process.env.MS365_MCP_SELECTED_ACCOUNT_PATH?.trim();
|
|
45
|
+
return envPath || DEFAULT_SELECTED_ACCOUNT_PATH;
|
|
46
|
+
}
|
|
47
|
+
function ensureParentDir(filePath) {
|
|
48
|
+
const dir = path.dirname(filePath);
|
|
49
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
50
|
+
}
|
|
39
51
|
function createMsalConfig(secrets) {
|
|
40
52
|
const cloudEndpoints = getCloudEndpoints(secrets.cloudType);
|
|
41
53
|
return {
|
|
@@ -128,8 +140,9 @@ class AuthManager {
|
|
|
128
140
|
`Keychain access failed, falling back to file storage: ${keytarError.message}`
|
|
129
141
|
);
|
|
130
142
|
}
|
|
131
|
-
|
|
132
|
-
|
|
143
|
+
const cachePath = getTokenCachePath();
|
|
144
|
+
if (!cacheData && existsSync(cachePath)) {
|
|
145
|
+
cacheData = readFileSync(cachePath, "utf8");
|
|
133
146
|
}
|
|
134
147
|
if (cacheData) {
|
|
135
148
|
this.msalApp.getTokenCache().deserialize(cacheData);
|
|
@@ -155,8 +168,9 @@ class AuthManager {
|
|
|
155
168
|
`Keychain access failed for selected account, falling back to file storage: ${keytarError.message}`
|
|
156
169
|
);
|
|
157
170
|
}
|
|
158
|
-
|
|
159
|
-
|
|
171
|
+
const accountPath = getSelectedAccountPath();
|
|
172
|
+
if (!selectedAccountData && existsSync(accountPath)) {
|
|
173
|
+
selectedAccountData = readFileSync(accountPath, "utf8");
|
|
160
174
|
}
|
|
161
175
|
if (selectedAccountData) {
|
|
162
176
|
const parsed = JSON.parse(selectedAccountData);
|
|
@@ -175,13 +189,17 @@ class AuthManager {
|
|
|
175
189
|
if (kt) {
|
|
176
190
|
await kt.setPassword(SERVICE_NAME, TOKEN_CACHE_ACCOUNT, cacheData);
|
|
177
191
|
} else {
|
|
178
|
-
|
|
192
|
+
const cachePath = getTokenCachePath();
|
|
193
|
+
ensureParentDir(cachePath);
|
|
194
|
+
fs.writeFileSync(cachePath, cacheData, { mode: 384 });
|
|
179
195
|
}
|
|
180
196
|
} catch (keytarError) {
|
|
181
197
|
logger.warn(
|
|
182
198
|
`Keychain save failed, falling back to file storage: ${keytarError.message}`
|
|
183
199
|
);
|
|
184
|
-
|
|
200
|
+
const cachePath = getTokenCachePath();
|
|
201
|
+
ensureParentDir(cachePath);
|
|
202
|
+
fs.writeFileSync(cachePath, cacheData, { mode: 384 });
|
|
185
203
|
}
|
|
186
204
|
} catch (error) {
|
|
187
205
|
logger.error(`Error saving token cache: ${error.message}`);
|
|
@@ -195,13 +213,17 @@ class AuthManager {
|
|
|
195
213
|
if (kt) {
|
|
196
214
|
await kt.setPassword(SERVICE_NAME, SELECTED_ACCOUNT_KEY, selectedAccountData);
|
|
197
215
|
} else {
|
|
198
|
-
|
|
216
|
+
const accountPath = getSelectedAccountPath();
|
|
217
|
+
ensureParentDir(accountPath);
|
|
218
|
+
fs.writeFileSync(accountPath, selectedAccountData, { mode: 384 });
|
|
199
219
|
}
|
|
200
220
|
} catch (keytarError) {
|
|
201
221
|
logger.warn(
|
|
202
222
|
`Keychain save failed for selected account, falling back to file storage: ${keytarError.message}`
|
|
203
223
|
);
|
|
204
|
-
|
|
224
|
+
const accountPath = getSelectedAccountPath();
|
|
225
|
+
ensureParentDir(accountPath);
|
|
226
|
+
fs.writeFileSync(accountPath, selectedAccountData, { mode: 384 });
|
|
205
227
|
}
|
|
206
228
|
} catch (error) {
|
|
207
229
|
logger.error(`Error saving selected account: ${error.message}`);
|
|
@@ -359,11 +381,13 @@ class AuthManager {
|
|
|
359
381
|
} catch (keytarError) {
|
|
360
382
|
logger.warn(`Keychain deletion failed: ${keytarError.message}`);
|
|
361
383
|
}
|
|
362
|
-
|
|
363
|
-
|
|
384
|
+
const cachePath = getTokenCachePath();
|
|
385
|
+
if (fs.existsSync(cachePath)) {
|
|
386
|
+
fs.unlinkSync(cachePath);
|
|
364
387
|
}
|
|
365
|
-
|
|
366
|
-
|
|
388
|
+
const accountPath = getSelectedAccountPath();
|
|
389
|
+
if (fs.existsSync(accountPath)) {
|
|
390
|
+
fs.unlinkSync(accountPath);
|
|
367
391
|
}
|
|
368
392
|
return true;
|
|
369
393
|
} catch (error) {
|
|
@@ -418,5 +442,7 @@ class AuthManager {
|
|
|
418
442
|
var auth_default = AuthManager;
|
|
419
443
|
export {
|
|
420
444
|
buildScopesFromEndpoints,
|
|
421
|
-
auth_default as default
|
|
445
|
+
auth_default as default,
|
|
446
|
+
getSelectedAccountPath,
|
|
447
|
+
getTokenCachePath
|
|
422
448
|
};
|
package/logs/mcp-server.log
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
2026-02-09 08:
|
|
2
|
-
2026-02-09 08:
|
|
3
|
-
2026-02-09 08:
|
|
4
|
-
2026-02-09 08:
|
|
5
|
-
2026-02-09 08:
|
|
6
|
-
2026-02-09 08:
|
|
7
|
-
2026-02-09 08:
|
|
8
|
-
2026-02-09 08:
|
|
9
|
-
2026-02-09 08:
|
|
10
|
-
2026-02-09 08:
|
|
1
|
+
2026-02-09 08:40:40 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
|
|
2
|
+
2026-02-09 08:40:40 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
|
|
3
|
+
2026-02-09 08:40:40 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me
|
|
4
|
+
2026-02-09 08:40:40 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me/messages
|
|
5
|
+
2026-02-09 08:40:40 INFO: [GRAPH CLIENT] Final URL being sent to Microsoft: https://graph.microsoft.com/v1.0/me/calendar
|
|
6
|
+
2026-02-09 08:40:40 INFO: Using environment variables for secrets
|
|
7
|
+
2026-02-09 08:40:40 INFO: Using environment variables for secrets
|
|
8
|
+
2026-02-09 08:40:40 INFO: Using environment variables for secrets
|
|
9
|
+
2026-02-09 08:40:40 INFO: Using environment variables for secrets
|
|
10
|
+
2026-02-09 08:40:40 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.37.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",
|