@softeria/ms-365-mcp-server 0.28.2 → 0.28.3
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/.env.example +22 -2
- package/README.md +68 -0
- package/dist/auth.js +19 -7
- package/dist/graph-client.js +5 -4
- package/dist/index.js +1 -1
- package/dist/oauth-provider.js +3 -3
- package/dist/secrets.js +61 -0
- package/dist/server.js +19 -41
- package/logs/error.log +0 -0
- package/logs/mcp-server.log +5 -0
- package/package.json +4 -1
package/.env.example
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# Your Azure AD App Registration Client ID
|
|
5
5
|
MS365_MCP_CLIENT_ID=your-azure-ad-app-client-id-here
|
|
6
6
|
|
|
7
|
-
# Your Azure AD App Registration Client Secret
|
|
7
|
+
# Your Azure AD App Registration Client Secret (optional, for confidential clients)
|
|
8
8
|
MS365_MCP_CLIENT_SECRET=your-azure-ad-app-client-secret-here
|
|
9
9
|
|
|
10
10
|
# Tenant ID - use "common" for multi-tenant or your specific tenant ID
|
|
@@ -21,4 +21,24 @@ MS365_MCP_TENANT_ID=common
|
|
|
21
21
|
# 5. Copy the Client ID from Overview page
|
|
22
22
|
# 6. Go to Certificates & secrets → New client secret → Copy the secret value
|
|
23
23
|
# 7. Replace the values above with your actual credentials
|
|
24
|
-
# 8. Rename this file to .env
|
|
24
|
+
# 8. Rename this file to .env
|
|
25
|
+
|
|
26
|
+
# -------------------------------------------------------------------
|
|
27
|
+
# Azure Key Vault Integration (Optional)
|
|
28
|
+
# -------------------------------------------------------------------
|
|
29
|
+
# When set, secrets are fetched from Azure Key Vault instead of environment variables.
|
|
30
|
+
# This is useful for production deployments, especially with Azure Container Apps.
|
|
31
|
+
#
|
|
32
|
+
# MS365_MCP_KEYVAULT_URL=https://your-keyvault-name.vault.azure.net
|
|
33
|
+
#
|
|
34
|
+
# Key Vault secret names (store these in your Key Vault):
|
|
35
|
+
# - ms365-mcp-client-id (required)
|
|
36
|
+
# - ms365-mcp-tenant-id (optional, defaults to "common")
|
|
37
|
+
# - ms365-mcp-client-secret (optional)
|
|
38
|
+
#
|
|
39
|
+
# Authentication uses DefaultAzureCredential, which supports:
|
|
40
|
+
# - Managed Identity (recommended for Azure Container Apps)
|
|
41
|
+
# - Azure CLI credentials (for local development)
|
|
42
|
+
# - Environment variables (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
|
|
43
|
+
#
|
|
44
|
+
# See README.md for detailed Azure Key Vault setup instructions.
|
package/README.md
CHANGED
|
@@ -395,6 +395,74 @@ Environment variables:
|
|
|
395
395
|
- `MS365_MCP_CLIENT_ID`: Custom Azure app client ID (defaults to built-in app)
|
|
396
396
|
- `MS365_MCP_TENANT_ID`: Custom tenant ID (defaults to 'common' for multi-tenant)
|
|
397
397
|
- `MS365_MCP_OAUTH_TOKEN`: Pre-existing OAuth token for Microsoft Graph API (BYOT method)
|
|
398
|
+
- `MS365_MCP_KEYVAULT_URL`: Azure Key Vault URL for secrets management (see Azure Key Vault section)
|
|
399
|
+
|
|
400
|
+
## Azure Key Vault Integration
|
|
401
|
+
|
|
402
|
+
For production deployments, you can store secrets in Azure Key Vault instead of environment variables. This is particularly useful for Azure Container Apps with managed identity.
|
|
403
|
+
|
|
404
|
+
### Setup
|
|
405
|
+
|
|
406
|
+
1. **Create a Key Vault** (if you don't have one):
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
az keyvault create --name your-keyvault-name --resource-group your-rg --location eastus
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
2. **Add secrets to Key Vault**:
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
az keyvault secret set --vault-name your-keyvault-name --name ms365-mcp-client-id --value "your-client-id"
|
|
416
|
+
az keyvault secret set --vault-name your-keyvault-name --name ms365-mcp-tenant-id --value "your-tenant-id"
|
|
417
|
+
# Optional: if using confidential client flow
|
|
418
|
+
az keyvault secret set --vault-name your-keyvault-name --name ms365-mcp-client-secret --value "your-secret"
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
3. **Grant access to Key Vault**:
|
|
422
|
+
|
|
423
|
+
For Azure Container Apps with managed identity:
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# Get the managed identity principal ID
|
|
427
|
+
PRINCIPAL_ID=$(az containerapp show --name your-app --resource-group your-rg --query identity.principalId -o tsv)
|
|
428
|
+
|
|
429
|
+
# Grant access to Key Vault secrets
|
|
430
|
+
az keyvault set-policy --name your-keyvault-name --object-id $PRINCIPAL_ID --secret-permissions get list
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
For local development with Azure CLI:
|
|
434
|
+
|
|
435
|
+
```bash
|
|
436
|
+
# Your Azure CLI identity already has access if you have appropriate RBAC roles
|
|
437
|
+
az login
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
4. **Configure the server**:
|
|
441
|
+
```bash
|
|
442
|
+
MS365_MCP_KEYVAULT_URL=https://your-keyvault-name.vault.azure.net npx @softeria/ms-365-mcp-server
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Secret Name Mapping
|
|
446
|
+
|
|
447
|
+
| Key Vault Secret Name | Environment Variable | Required |
|
|
448
|
+
| ----------------------- | ----------------------- | ------------------------- |
|
|
449
|
+
| ms365-mcp-client-id | MS365_MCP_CLIENT_ID | Yes |
|
|
450
|
+
| ms365-mcp-tenant-id | MS365_MCP_TENANT_ID | No (defaults to 'common') |
|
|
451
|
+
| ms365-mcp-client-secret | MS365_MCP_CLIENT_SECRET | No |
|
|
452
|
+
|
|
453
|
+
### Authentication
|
|
454
|
+
|
|
455
|
+
The Key Vault integration uses `DefaultAzureCredential` from the Azure Identity SDK, which automatically tries multiple authentication methods in order:
|
|
456
|
+
|
|
457
|
+
1. Environment variables (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
|
|
458
|
+
2. Managed Identity (recommended for Azure Container Apps)
|
|
459
|
+
3. Azure CLI credentials (for local development)
|
|
460
|
+
4. Visual Studio Code credentials
|
|
461
|
+
5. Azure PowerShell credentials
|
|
462
|
+
|
|
463
|
+
### Optional Dependencies
|
|
464
|
+
|
|
465
|
+
The Azure Key Vault packages (`@azure/identity` and `@azure/keyvault-secrets`) are optional dependencies. They are only loaded when `MS365_MCP_KEYVAULT_URL` is configured. If you don't use Key Vault, these packages are not required.
|
|
398
466
|
|
|
399
467
|
## Contributing
|
|
400
468
|
|
package/dist/auth.js
CHANGED
|
@@ -3,6 +3,7 @@ import logger from "./logger.js";
|
|
|
3
3
|
import fs, { existsSync, readFileSync } from "fs";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import path from "path";
|
|
6
|
+
import { getSecrets } from "./secrets.js";
|
|
6
7
|
let keytar = null;
|
|
7
8
|
async function getKeytar() {
|
|
8
9
|
if (keytar === void 0) {
|
|
@@ -34,12 +35,14 @@ const SELECTED_ACCOUNT_KEY = "selected-account";
|
|
|
34
35
|
const FALLBACK_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
35
36
|
const FALLBACK_PATH = path.join(FALLBACK_DIR, "..", ".token-cache.json");
|
|
36
37
|
const SELECTED_ACCOUNT_PATH = path.join(FALLBACK_DIR, "..", ".selected-account.json");
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
38
|
+
function createMsalConfig(secrets) {
|
|
39
|
+
return {
|
|
40
|
+
auth: {
|
|
41
|
+
clientId: secrets.clientId || "084a3e9f-a9f4-43f7-89f9-d229cf97853e",
|
|
42
|
+
authority: `https://login.microsoftonline.com/${secrets.tenantId || "common"}`
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
43
46
|
const SCOPE_HIERARCHY = {
|
|
44
47
|
"Mail.ReadWrite": ["Mail.Read"],
|
|
45
48
|
"Calendars.ReadWrite": ["Calendars.Read"],
|
|
@@ -87,7 +90,7 @@ function buildScopesFromEndpoints(includeWorkAccountScopes = false, enabledTools
|
|
|
87
90
|
return scopes;
|
|
88
91
|
}
|
|
89
92
|
class AuthManager {
|
|
90
|
-
constructor(config
|
|
93
|
+
constructor(config, scopes = buildScopesFromEndpoints()) {
|
|
91
94
|
logger.info(`And scopes are ${scopes.join(", ")}`, scopes);
|
|
92
95
|
this.config = config;
|
|
93
96
|
this.scopes = scopes;
|
|
@@ -99,6 +102,15 @@ class AuthManager {
|
|
|
99
102
|
this.oauthToken = oauthTokenFromEnv ?? null;
|
|
100
103
|
this.isOAuthMode = oauthTokenFromEnv != null;
|
|
101
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Creates an AuthManager instance with secrets loaded from the configured provider.
|
|
107
|
+
* Uses Key Vault if MS365_MCP_KEYVAULT_URL is set, otherwise environment variables.
|
|
108
|
+
*/
|
|
109
|
+
static async create(scopes = buildScopesFromEndpoints()) {
|
|
110
|
+
const secrets = await getSecrets();
|
|
111
|
+
const config = createMsalConfig(secrets);
|
|
112
|
+
return new AuthManager(config, scopes);
|
|
113
|
+
}
|
|
102
114
|
async loadTokenCache() {
|
|
103
115
|
try {
|
|
104
116
|
let cacheData;
|
package/dist/graph-client.js
CHANGED
|
@@ -2,11 +2,12 @@ import logger from "./logger.js";
|
|
|
2
2
|
import { refreshAccessToken } from "./lib/microsoft-auth.js";
|
|
3
3
|
import { encode as toonEncode } from "@toon-format/toon";
|
|
4
4
|
class GraphClient {
|
|
5
|
-
constructor(authManager, outputFormat = "json") {
|
|
5
|
+
constructor(authManager, secrets, outputFormat = "json") {
|
|
6
6
|
this.accessToken = null;
|
|
7
7
|
this.refreshToken = null;
|
|
8
8
|
this.outputFormat = "json";
|
|
9
9
|
this.authManager = authManager;
|
|
10
|
+
this.secrets = secrets;
|
|
10
11
|
this.outputFormat = outputFormat;
|
|
11
12
|
}
|
|
12
13
|
setOAuthTokens(accessToken, refreshToken) {
|
|
@@ -72,9 +73,9 @@ class GraphClient {
|
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
async refreshAccessToken(refreshToken) {
|
|
75
|
-
const tenantId =
|
|
76
|
-
const clientId =
|
|
77
|
-
const clientSecret =
|
|
76
|
+
const tenantId = this.secrets.tenantId || "common";
|
|
77
|
+
const clientId = this.secrets.clientId;
|
|
78
|
+
const clientSecret = this.secrets.clientSecret;
|
|
78
79
|
if (clientSecret) {
|
|
79
80
|
logger.info("GraphClient: Refreshing token with confidential client");
|
|
80
81
|
} else {
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ async function main() {
|
|
|
13
13
|
logger.info("Organization mode enabled - including work account scopes");
|
|
14
14
|
}
|
|
15
15
|
const scopes = buildScopesFromEndpoints(includeWorkScopes, args.enabledTools);
|
|
16
|
-
const authManager =
|
|
16
|
+
const authManager = await AuthManager.create(scopes);
|
|
17
17
|
await authManager.loadTokenCache();
|
|
18
18
|
if (args.login) {
|
|
19
19
|
await authManager.acquireTokenByDeviceCode();
|
package/dist/oauth-provider.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ProxyOAuthServerProvider } from "@modelcontextprotocol/sdk/server/auth/providers/proxyProvider.js";
|
|
2
2
|
import logger from "./logger.js";
|
|
3
3
|
class MicrosoftOAuthProvider extends ProxyOAuthServerProvider {
|
|
4
|
-
constructor(authManager) {
|
|
5
|
-
const tenantId =
|
|
6
|
-
const clientId =
|
|
4
|
+
constructor(authManager, secrets) {
|
|
5
|
+
const tenantId = secrets.tenantId || "common";
|
|
6
|
+
const clientId = secrets.clientId;
|
|
7
7
|
super({
|
|
8
8
|
endpoints: {
|
|
9
9
|
authorizationUrl: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`,
|
package/dist/secrets.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import logger from "./logger.js";
|
|
2
|
+
class EnvironmentSecretsProvider {
|
|
3
|
+
async getSecrets() {
|
|
4
|
+
return {
|
|
5
|
+
clientId: process.env.MS365_MCP_CLIENT_ID || "",
|
|
6
|
+
tenantId: process.env.MS365_MCP_TENANT_ID || "common",
|
|
7
|
+
clientSecret: process.env.MS365_MCP_CLIENT_SECRET
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
class KeyVaultSecretsProvider {
|
|
12
|
+
constructor(vaultUrl) {
|
|
13
|
+
this.vaultUrl = vaultUrl;
|
|
14
|
+
}
|
|
15
|
+
async getSecrets() {
|
|
16
|
+
const { DefaultAzureCredential } = await import("@azure/identity");
|
|
17
|
+
const { SecretClient } = await import("@azure/keyvault-secrets");
|
|
18
|
+
const credential = new DefaultAzureCredential();
|
|
19
|
+
const client = new SecretClient(this.vaultUrl, credential);
|
|
20
|
+
logger.info(`Fetching secrets from Key Vault: ${this.vaultUrl}`);
|
|
21
|
+
const [clientIdSecret, tenantIdSecret, clientSecretResult] = await Promise.all([
|
|
22
|
+
client.getSecret("ms365-mcp-client-id"),
|
|
23
|
+
client.getSecret("ms365-mcp-tenant-id").catch(() => null),
|
|
24
|
+
client.getSecret("ms365-mcp-client-secret").catch(() => null)
|
|
25
|
+
]);
|
|
26
|
+
if (!clientIdSecret.value) {
|
|
27
|
+
throw new Error("Required secret ms365-mcp-client-id not found in Key Vault");
|
|
28
|
+
}
|
|
29
|
+
logger.info("Successfully retrieved secrets from Key Vault");
|
|
30
|
+
return {
|
|
31
|
+
clientId: clientIdSecret.value,
|
|
32
|
+
tenantId: tenantIdSecret?.value || "common",
|
|
33
|
+
clientSecret: clientSecretResult?.value
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function createSecretsProvider() {
|
|
38
|
+
const vaultUrl = process.env.MS365_MCP_KEYVAULT_URL;
|
|
39
|
+
if (vaultUrl) {
|
|
40
|
+
logger.info("Key Vault URL configured, using Azure Key Vault for secrets");
|
|
41
|
+
return new KeyVaultSecretsProvider(vaultUrl);
|
|
42
|
+
}
|
|
43
|
+
logger.info("Using environment variables for secrets");
|
|
44
|
+
return new EnvironmentSecretsProvider();
|
|
45
|
+
}
|
|
46
|
+
let cachedSecrets = null;
|
|
47
|
+
async function getSecrets() {
|
|
48
|
+
if (cachedSecrets) {
|
|
49
|
+
return cachedSecrets;
|
|
50
|
+
}
|
|
51
|
+
const provider = createSecretsProvider();
|
|
52
|
+
cachedSecrets = await provider.getSecrets();
|
|
53
|
+
return cachedSecrets;
|
|
54
|
+
}
|
|
55
|
+
function clearSecretsCache() {
|
|
56
|
+
cachedSecrets = null;
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
clearSecretsCache,
|
|
60
|
+
getSecrets
|
|
61
|
+
};
|
package/dist/server.js
CHANGED
|
@@ -3,7 +3,6 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
3
3
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
4
4
|
import { mcpAuthRouter } from "@modelcontextprotocol/sdk/server/auth/router.js";
|
|
5
5
|
import express from "express";
|
|
6
|
-
import crypto from "crypto";
|
|
7
6
|
import logger, { enableConsoleLogging } from "./logger.js";
|
|
8
7
|
import { registerAuthTools } from "./auth-tools.js";
|
|
9
8
|
import { registerGraphTools, registerDiscoveryTools } from "./graph-tools.js";
|
|
@@ -15,7 +14,7 @@ import {
|
|
|
15
14
|
microsoftBearerTokenAuthMiddleware,
|
|
16
15
|
refreshAccessToken
|
|
17
16
|
} from "./lib/microsoft-auth.js";
|
|
18
|
-
|
|
17
|
+
import { getSecrets } from "./secrets.js";
|
|
19
18
|
function parseHttpOption(httpOption) {
|
|
20
19
|
if (typeof httpOption === "boolean") {
|
|
21
20
|
return { host: void 0, port: 3e3 };
|
|
@@ -34,11 +33,14 @@ class MicrosoftGraphServer {
|
|
|
34
33
|
constructor(authManager, options = {}) {
|
|
35
34
|
this.authManager = authManager;
|
|
36
35
|
this.options = options;
|
|
37
|
-
|
|
38
|
-
this.graphClient = new GraphClient(authManager, outputFormat);
|
|
36
|
+
this.graphClient = null;
|
|
39
37
|
this.server = null;
|
|
38
|
+
this.secrets = null;
|
|
40
39
|
}
|
|
41
40
|
async initialize(version) {
|
|
41
|
+
this.secrets = await getSecrets();
|
|
42
|
+
const outputFormat = this.options.toon ? "toon" : "json";
|
|
43
|
+
this.graphClient = new GraphClient(this.authManager, this.secrets, outputFormat);
|
|
42
44
|
this.server = new McpServer({
|
|
43
45
|
name: "Microsoft365MCP",
|
|
44
46
|
version
|
|
@@ -70,10 +72,10 @@ class MicrosoftGraphServer {
|
|
|
70
72
|
enableConsoleLogging();
|
|
71
73
|
}
|
|
72
74
|
logger.info("Microsoft 365 MCP Server starting...");
|
|
73
|
-
logger.info("
|
|
74
|
-
CLIENT_ID:
|
|
75
|
-
CLIENT_SECRET:
|
|
76
|
-
TENANT_ID:
|
|
75
|
+
logger.info("Secrets Check:", {
|
|
76
|
+
CLIENT_ID: this.secrets?.clientId ? `${this.secrets.clientId.substring(0, 8)}...` : "NOT SET",
|
|
77
|
+
CLIENT_SECRET: this.secrets?.clientSecret ? "SET" : "NOT SET",
|
|
78
|
+
TENANT_ID: this.secrets?.tenantId || "NOT SET",
|
|
77
79
|
NODE_ENV: process.env.NODE_ENV || "NOT SET"
|
|
78
80
|
});
|
|
79
81
|
if (this.options.readOnly) {
|
|
@@ -99,7 +101,7 @@ class MicrosoftGraphServer {
|
|
|
99
101
|
}
|
|
100
102
|
next();
|
|
101
103
|
});
|
|
102
|
-
const oauthProvider = new MicrosoftOAuthProvider(this.authManager);
|
|
104
|
+
const oauthProvider = new MicrosoftOAuthProvider(this.authManager, this.secrets);
|
|
103
105
|
app.get("/.well-known/oauth-authorization-server", async (req, res) => {
|
|
104
106
|
const protocol = req.secure ? "https" : "http";
|
|
105
107
|
const url = new URL(`${protocol}://${req.get("host")}`);
|
|
@@ -108,7 +110,6 @@ class MicrosoftGraphServer {
|
|
|
108
110
|
issuer: url.origin,
|
|
109
111
|
authorization_endpoint: `${url.origin}/authorize`,
|
|
110
112
|
token_endpoint: `${url.origin}/token`,
|
|
111
|
-
registration_endpoint: `${url.origin}/register`,
|
|
112
113
|
response_types_supported: ["code"],
|
|
113
114
|
response_modes_supported: ["query"],
|
|
114
115
|
grant_types_supported: ["authorization_code", "refresh_token"],
|
|
@@ -129,33 +130,10 @@ class MicrosoftGraphServer {
|
|
|
129
130
|
resource_documentation: `${url.origin}`
|
|
130
131
|
});
|
|
131
132
|
});
|
|
132
|
-
app.post("/register", async (req, res) => {
|
|
133
|
-
const body = req.body;
|
|
134
|
-
const clientId = crypto.randomUUID();
|
|
135
|
-
registeredClients.set(clientId, {
|
|
136
|
-
client_id: clientId,
|
|
137
|
-
client_name: body.client_name || "MCP Client",
|
|
138
|
-
redirect_uris: body.redirect_uris || [],
|
|
139
|
-
grant_types: body.grant_types || ["authorization_code", "refresh_token"],
|
|
140
|
-
response_types: body.response_types || ["code"],
|
|
141
|
-
scope: body.scope,
|
|
142
|
-
token_endpoint_auth_method: "none",
|
|
143
|
-
created_at: Date.now()
|
|
144
|
-
});
|
|
145
|
-
res.status(201).json({
|
|
146
|
-
client_id: clientId,
|
|
147
|
-
client_name: body.client_name || "MCP Client",
|
|
148
|
-
redirect_uris: body.redirect_uris || [],
|
|
149
|
-
grant_types: body.grant_types || ["authorization_code", "refresh_token"],
|
|
150
|
-
response_types: body.response_types || ["code"],
|
|
151
|
-
scope: body.scope,
|
|
152
|
-
token_endpoint_auth_method: "none"
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
133
|
app.get("/authorize", async (req, res) => {
|
|
156
134
|
const url = new URL(req.url, `${req.protocol}://${req.get("host")}`);
|
|
157
|
-
const tenantId =
|
|
158
|
-
const clientId =
|
|
135
|
+
const tenantId = this.secrets?.tenantId || "common";
|
|
136
|
+
const clientId = this.secrets.clientId;
|
|
159
137
|
const microsoftAuthUrl = new URL(
|
|
160
138
|
`https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`
|
|
161
139
|
);
|
|
@@ -209,9 +187,9 @@ class MicrosoftGraphServer {
|
|
|
209
187
|
return;
|
|
210
188
|
}
|
|
211
189
|
if (body.grant_type === "authorization_code") {
|
|
212
|
-
const tenantId =
|
|
213
|
-
const clientId =
|
|
214
|
-
const clientSecret =
|
|
190
|
+
const tenantId = this.secrets?.tenantId || "common";
|
|
191
|
+
const clientId = this.secrets.clientId;
|
|
192
|
+
const clientSecret = this.secrets?.clientSecret;
|
|
215
193
|
if (clientSecret) {
|
|
216
194
|
logger.info("Token endpoint: Using confidential client with client_secret");
|
|
217
195
|
} else {
|
|
@@ -227,9 +205,9 @@ class MicrosoftGraphServer {
|
|
|
227
205
|
);
|
|
228
206
|
res.json(result);
|
|
229
207
|
} else if (body.grant_type === "refresh_token") {
|
|
230
|
-
const tenantId =
|
|
231
|
-
const clientId =
|
|
232
|
-
const clientSecret =
|
|
208
|
+
const tenantId = this.secrets?.tenantId || "common";
|
|
209
|
+
const clientId = this.secrets.clientId;
|
|
210
|
+
const clientSecret = this.secrets?.clientSecret;
|
|
233
211
|
if (clientSecret) {
|
|
234
212
|
logger.info("Refresh endpoint: Using confidential client with client_secret");
|
|
235
213
|
} else {
|
package/logs/error.log
ADDED
|
File without changes
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
2025-12-23 08:30:22 INFO: Using environment variables for secrets
|
|
2
|
+
2025-12-23 08:30:22 INFO: Using environment variables for secrets
|
|
3
|
+
2025-12-23 08:30:22 INFO: Using environment variables for secrets
|
|
4
|
+
2025-12-23 08:30:22 INFO: Using environment variables for secrets
|
|
5
|
+
2025-12-23 08:30:22 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.28.
|
|
3
|
+
"version": "0.28.3",
|
|
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",
|
|
@@ -44,6 +44,8 @@
|
|
|
44
44
|
"zod": "^3.24.2"
|
|
45
45
|
},
|
|
46
46
|
"optionalDependencies": {
|
|
47
|
+
"@azure/identity": "^4.5.0",
|
|
48
|
+
"@azure/keyvault-secrets": "^4.9.0",
|
|
47
49
|
"keytar": "^7.9.0"
|
|
48
50
|
},
|
|
49
51
|
"devDependencies": {
|
|
@@ -56,6 +58,7 @@
|
|
|
56
58
|
"@types/node": "^22.15.15",
|
|
57
59
|
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
|
58
60
|
"@typescript-eslint/parser": "^8.38.0",
|
|
61
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
59
62
|
"eslint": "^9.31.0",
|
|
60
63
|
"globals": "^16.3.0",
|
|
61
64
|
"patch-package": "^8.0.1",
|