ms365-mcp-server 1.1.23 ā 2.0.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/bin/cli.js +81 -31
- package/dist/index.js +59 -102
- package/dist/utils/ms365-operations.js +4 -9
- package/dist/utils/outlook-auth.js +614 -0
- package/dist/utils/outlook-credential-store.js +195 -0
- package/package.json +9 -5
package/bin/cli.js
CHANGED
|
@@ -64,6 +64,10 @@ let login = false;
|
|
|
64
64
|
let logout = false;
|
|
65
65
|
let verifyLogin = false;
|
|
66
66
|
let serverUrl = process.env.SERVER_URL || 'http://localhost:55000';
|
|
67
|
+
let clientId = process.env.OUTLOOK_CLIENT_ID || '';
|
|
68
|
+
let tenantId = process.env.OUTLOOK_TENANT_ID || '';
|
|
69
|
+
let clientSecret = process.env.OUTLOOK_CLIENT_SECRET || '';
|
|
70
|
+
let redirectUri = process.env.OUTLOOK_REDIRECT_URI || '';
|
|
67
71
|
|
|
68
72
|
// Detect if we're running under an MCP context (Claude/SIYA/ChatGPT/etc.)
|
|
69
73
|
const isMcpContext =
|
|
@@ -113,6 +117,38 @@ for (let i = 0; i < args.length; i++) {
|
|
|
113
117
|
console.error('Error: --server-url requires a value');
|
|
114
118
|
process.exit(1);
|
|
115
119
|
}
|
|
120
|
+
} else if (arg === '--client-id') {
|
|
121
|
+
if (i + 1 < args.length) {
|
|
122
|
+
clientId = args[++i];
|
|
123
|
+
writeDebug(`Client ID set`);
|
|
124
|
+
} else {
|
|
125
|
+
console.error('Error: --client-id requires a value');
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
} else if (arg === '--tenant-id') {
|
|
129
|
+
if (i + 1 < args.length) {
|
|
130
|
+
tenantId = args[++i];
|
|
131
|
+
writeDebug(`Tenant ID set`);
|
|
132
|
+
} else {
|
|
133
|
+
console.error('Error: --tenant-id requires a value');
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
} else if (arg === '--client-secret') {
|
|
137
|
+
if (i + 1 < args.length) {
|
|
138
|
+
clientSecret = args[++i];
|
|
139
|
+
writeDebug(`Client secret set`);
|
|
140
|
+
} else {
|
|
141
|
+
console.error('Error: --client-secret requires a value');
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
} else if (arg === '--redirect-uri') {
|
|
145
|
+
if (i + 1 < args.length) {
|
|
146
|
+
redirectUri = args[++i];
|
|
147
|
+
writeDebug(`Redirect URI set to: ${redirectUri}`);
|
|
148
|
+
} else {
|
|
149
|
+
console.error('Error: --redirect-uri requires a value');
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
116
152
|
} else if (arg === '--help' || arg === '-h') {
|
|
117
153
|
console.log(`
|
|
118
154
|
MS365 MCP Server - Microsoft 365 Integration for Claude/SIYA Desktop
|
|
@@ -120,41 +156,47 @@ MS365 MCP Server - Microsoft 365 Integration for Claude/SIYA Desktop
|
|
|
120
156
|
Usage: npx ms365-mcp-server [options]
|
|
121
157
|
|
|
122
158
|
Options:
|
|
123
|
-
--
|
|
124
|
-
--
|
|
125
|
-
--
|
|
126
|
-
--
|
|
159
|
+
--client-id ID Azure App Client ID
|
|
160
|
+
--tenant-id ID Azure Tenant ID (or "common")
|
|
161
|
+
--client-secret SECRET Azure App Client Secret (optional)
|
|
162
|
+
--redirect-uri URI OAuth redirect URI (optional)
|
|
163
|
+
--login Login to MS365 (opens browser for OAuth)
|
|
127
164
|
--logout Logout from MS365
|
|
128
165
|
--verify-login Verify login to MS365
|
|
129
166
|
--server-url URL Set the server URL (default: http://localhost:55000)
|
|
167
|
+
--setup-auth Interactive credential setup
|
|
168
|
+
--reset-auth Clear stored authentication tokens
|
|
169
|
+
--multi-user Enable multi-user authentication mode
|
|
130
170
|
--debug Enable debug output
|
|
131
171
|
--non-interactive, -n Run in non-interactive mode (no prompt)
|
|
132
172
|
--help, -h Show this help message
|
|
133
173
|
|
|
134
|
-
|
|
135
|
-
1. Run: npx ms365-mcp-server --
|
|
136
|
-
2.
|
|
174
|
+
Quick Start:
|
|
175
|
+
1. Run: npx ms365-mcp-server --login
|
|
176
|
+
2. Complete authentication in browser
|
|
137
177
|
3. Run: npx ms365-mcp-server to start the server
|
|
138
178
|
|
|
139
|
-
Authentication
|
|
140
|
-
The server
|
|
179
|
+
Authentication (OAuth2 Redirect Flow):
|
|
180
|
+
The server uses OAuth2 redirect flow with a local callback server.
|
|
181
|
+
No Azure app registration required - uses built-in Microsoft credentials!
|
|
141
182
|
|
|
142
|
-
1.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
- MS365_REDIRECT_URI: OAuth redirect URI (optional)
|
|
147
|
-
- SERVER_URL: Server URL for attachments (optional)
|
|
183
|
+
1. Run --login to open browser for authentication
|
|
184
|
+
2. Sign in with your Microsoft account
|
|
185
|
+
3. Authorization redirects back to local server (port 44005)
|
|
186
|
+
4. Tokens saved to ~/.outlook-mcp/
|
|
148
187
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
188
|
+
Environment Variables (Optional - for custom Azure app):
|
|
189
|
+
- OUTLOOK_CLIENT_ID: Your Azure app client ID
|
|
190
|
+
- OUTLOOK_TENANT_ID: Your Azure tenant ID (or "common")
|
|
191
|
+
- OUTLOOK_CLIENT_SECRET: Your Azure app client secret (optional)
|
|
192
|
+
- OUTLOOK_REDIRECT_URI: OAuth redirect URI (optional)
|
|
193
|
+
- SERVER_URL: Server URL for attachments (optional)
|
|
152
194
|
|
|
153
|
-
Azure App Registration:
|
|
195
|
+
Custom Azure App Registration (Optional):
|
|
154
196
|
1. Go to https://portal.azure.com
|
|
155
197
|
2. Navigate to Azure Active Directory > App registrations
|
|
156
198
|
3. Click "New registration"
|
|
157
|
-
4. Set redirect URI to: http://localhost:
|
|
199
|
+
4. Set redirect URI to: http://localhost:44005/oauth2callback
|
|
158
200
|
5. Grant required API permissions for Microsoft Graph:
|
|
159
201
|
- Mail.ReadWrite
|
|
160
202
|
- Mail.Send
|
|
@@ -162,14 +204,12 @@ Azure App Registration:
|
|
|
162
204
|
- Contacts.Read
|
|
163
205
|
- User.Read
|
|
164
206
|
|
|
165
|
-
Note: Device code flow (--login) doesn't require Azure app registration!
|
|
166
|
-
|
|
167
207
|
Examples:
|
|
168
|
-
npx ms365-mcp-server --
|
|
208
|
+
npx ms365-mcp-server --login # Login (opens browser)
|
|
169
209
|
npx ms365-mcp-server # Start the server
|
|
210
|
+
npx ms365-mcp-server --verify-login # Check auth status
|
|
211
|
+
npx ms365-mcp-server --logout # Clear auth tokens
|
|
170
212
|
npx ms365-mcp-server --multi-user # Start in multi-user mode
|
|
171
|
-
npx ms365-mcp-server --reset-auth # Clear auth tokens
|
|
172
|
-
npx ms365-mcp-server --server-url https://your-domain.com # Set custom server URL
|
|
173
213
|
`);
|
|
174
214
|
process.exit(0);
|
|
175
215
|
}
|
|
@@ -219,15 +259,25 @@ function startServerWithPath(serverPath) {
|
|
|
219
259
|
|
|
220
260
|
writeDebug(`Server arguments: ${serverArgs.join(' ')}`);
|
|
221
261
|
|
|
262
|
+
// Build environment with credentials
|
|
263
|
+
const serverEnv = {
|
|
264
|
+
...process.env,
|
|
265
|
+
NODE_PATH: process.env.NODE_PATH || '',
|
|
266
|
+
SERVER_URL: serverUrl
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// Add credentials to environment if provided via CLI
|
|
270
|
+
if (clientId) serverEnv.OUTLOOK_CLIENT_ID = clientId;
|
|
271
|
+
if (tenantId) serverEnv.OUTLOOK_TENANT_ID = tenantId;
|
|
272
|
+
if (clientSecret) serverEnv.OUTLOOK_CLIENT_SECRET = clientSecret;
|
|
273
|
+
if (redirectUri) serverEnv.OUTLOOK_REDIRECT_URI = redirectUri;
|
|
274
|
+
|
|
275
|
+
writeDebug(`Starting server with credentials: clientId=${clientId ? 'set' : 'not set'}, tenantId=${tenantId ? 'set' : 'not set'}, clientSecret=${clientSecret ? 'set' : 'not set'}`);
|
|
276
|
+
|
|
222
277
|
// Start the server process
|
|
223
278
|
const serverProcess = spawn(process.execPath, [serverPath, ...serverArgs], {
|
|
224
279
|
stdio: 'inherit',
|
|
225
|
-
env:
|
|
226
|
-
...process.env,
|
|
227
|
-
// Ensure environment variables are passed through
|
|
228
|
-
NODE_PATH: process.env.NODE_PATH || '',
|
|
229
|
-
SERVER_URL: serverUrl
|
|
230
|
-
}
|
|
280
|
+
env: serverEnv
|
|
231
281
|
});
|
|
232
282
|
|
|
233
283
|
// Handle server process events
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSche
|
|
|
14
14
|
import { logger } from './utils/api.js';
|
|
15
15
|
import { MS365Operations } from './utils/ms365-operations.js';
|
|
16
16
|
import { multiUserMS365Auth } from './utils/multi-user-auth.js';
|
|
17
|
-
import {
|
|
17
|
+
import { outlookAuth } from './utils/outlook-auth.js';
|
|
18
18
|
import { IntelligenceEngine } from './utils/intelligence-engine.js';
|
|
19
19
|
import { ProactiveIntelligence } from './utils/proactive-intelligence.js';
|
|
20
20
|
import { DocumentWorkflow } from './utils/document-workflow.js';
|
|
@@ -83,7 +83,7 @@ function parseArgs() {
|
|
|
83
83
|
}
|
|
84
84
|
const server = new Server({
|
|
85
85
|
name: "ms365-mcp-server",
|
|
86
|
-
version: "1.
|
|
86
|
+
version: "1.0.0"
|
|
87
87
|
}, {
|
|
88
88
|
capabilities: {
|
|
89
89
|
resources: {
|
|
@@ -872,25 +872,20 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
872
872
|
const authTools = [
|
|
873
873
|
{
|
|
874
874
|
name: "authenticate",
|
|
875
|
-
description: "UNIFIED AUTHENTICATION: Handle all Microsoft 365 authentication needs. Supports
|
|
875
|
+
description: "UNIFIED AUTHENTICATION: Handle all Microsoft 365 authentication needs via OAuth2 redirect flow. Supports login (opens browser), status checking, and logout.",
|
|
876
876
|
inputSchema: {
|
|
877
877
|
type: "object",
|
|
878
878
|
properties: {
|
|
879
879
|
action: {
|
|
880
880
|
type: "string",
|
|
881
|
-
enum: ["login", "status", "logout"
|
|
882
|
-
description: "Auth action: login (
|
|
881
|
+
enum: ["login", "status", "logout"],
|
|
882
|
+
description: "Auth action: login (OAuth redirect auth - opens browser), status (check auth status), logout (clear tokens)",
|
|
883
883
|
default: "login"
|
|
884
884
|
},
|
|
885
885
|
force: {
|
|
886
886
|
type: "boolean",
|
|
887
887
|
description: "Force new authentication even if already authenticated (for login action)",
|
|
888
888
|
default: false
|
|
889
|
-
},
|
|
890
|
-
accountKey: {
|
|
891
|
-
type: "string",
|
|
892
|
-
description: "Account key for logout action (default: current user)",
|
|
893
|
-
default: "default-user"
|
|
894
889
|
}
|
|
895
890
|
}
|
|
896
891
|
}
|
|
@@ -945,69 +940,62 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
945
940
|
case "login":
|
|
946
941
|
try {
|
|
947
942
|
// Check if already authenticated
|
|
948
|
-
if (await
|
|
943
|
+
if (await outlookAuth.isAuthenticated() && !processedArgs?.force) {
|
|
944
|
+
const user = await outlookAuth.getCurrentUser();
|
|
949
945
|
return {
|
|
950
946
|
content: [
|
|
951
947
|
{
|
|
952
948
|
type: "text",
|
|
953
|
-
text: `ā
Already authenticated with Microsoft 365
|
|
949
|
+
text: `ā
Already authenticated with Microsoft 365!\n\nš¤ User: ${user || 'authenticated-user'}\n\nš” Use force: true to re-authenticate.`
|
|
954
950
|
}
|
|
955
951
|
]
|
|
956
952
|
};
|
|
957
953
|
}
|
|
958
|
-
//
|
|
959
|
-
const
|
|
960
|
-
|
|
961
|
-
const currentUser = await enhancedMS365Auth.getCurrentUser();
|
|
962
|
-
return {
|
|
963
|
-
content: [
|
|
964
|
-
{
|
|
965
|
-
type: "text",
|
|
966
|
-
text: `ā
Device code authentication completed successfully!\n\nš¤ User: ${currentUser || 'authenticated-user'}\nš Status: Valid\n\nš You can now use all Microsoft 365 email features!`
|
|
967
|
-
}
|
|
968
|
-
]
|
|
969
|
-
};
|
|
970
|
-
}
|
|
971
|
-
// Check if there's already a pending device code
|
|
972
|
-
let deviceCodeInfo = await enhancedMS365Auth.getPendingDeviceCodeInfo();
|
|
973
|
-
if (!deviceCodeInfo || args?.force) {
|
|
974
|
-
// No pending code or force new one, start fresh
|
|
975
|
-
deviceCodeInfo = await enhancedMS365Auth.startDeviceCodeAuth();
|
|
976
|
-
}
|
|
977
|
-
// Return device code information immediately (MCP pattern)
|
|
954
|
+
// Start OAuth redirect flow
|
|
955
|
+
const authResult = await outlookAuth.authenticate();
|
|
956
|
+
const currentUser = await outlookAuth.getCurrentUser();
|
|
978
957
|
return {
|
|
979
958
|
content: [
|
|
980
959
|
{
|
|
981
960
|
type: "text",
|
|
982
|
-
text:
|
|
961
|
+
text: `ā
Authentication successful!\n\nš¤ User: ${currentUser || 'authenticated-user'}\nš Status: Valid\n\nš You can now use all Microsoft 365 email features!`
|
|
983
962
|
}
|
|
984
963
|
]
|
|
985
964
|
};
|
|
986
965
|
}
|
|
987
966
|
catch (error) {
|
|
967
|
+
// Check if this is an auth required error with URL (MCP context)
|
|
968
|
+
if (error.code === 'AUTH_REQUIRED' && error.authUrl) {
|
|
969
|
+
return {
|
|
970
|
+
content: [
|
|
971
|
+
{
|
|
972
|
+
type: "text",
|
|
973
|
+
text: `š Microsoft 365 Authentication Required\n\nš± Please authenticate using the CLI:\n\nms365-mcp-server --login\n\nOr visit this URL:\n${error.authUrl}`
|
|
974
|
+
}
|
|
975
|
+
]
|
|
976
|
+
};
|
|
977
|
+
}
|
|
988
978
|
return {
|
|
989
979
|
content: [
|
|
990
980
|
{
|
|
991
981
|
type: "text",
|
|
992
|
-
text: `ā Authentication failed: ${error.message}\n\nš” Try
|
|
982
|
+
text: `ā Authentication failed: ${error.message}\n\nš” Try using CLI: ms365-mcp-server --login`
|
|
993
983
|
}
|
|
994
984
|
]
|
|
995
985
|
};
|
|
996
986
|
}
|
|
997
987
|
case "status":
|
|
998
|
-
const
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
statusText += `\n
|
|
1005
|
-
if (tokenInfo.needsRefresh) {
|
|
1006
|
-
statusText += `\nā ļø Token will be refreshed automatically on next operation`;
|
|
1007
|
-
}
|
|
988
|
+
const authStatus = await outlookAuth.getAuthenticationStatus();
|
|
989
|
+
let statusText = `š Microsoft 365 Authentication Status\n\n`;
|
|
990
|
+
statusText += `š Authentication: ${authStatus.authenticated ? 'ā
Valid' : 'ā Not authenticated'}\n`;
|
|
991
|
+
statusText += `š¤ Current User: ${authStatus.username || 'None'}\n`;
|
|
992
|
+
if (authStatus.authenticated) {
|
|
993
|
+
statusText += `\nā° Token expires: ${authStatus.expiresAt}`;
|
|
994
|
+
statusText += `\nā±ļø Expires in: ${authStatus.expiresIn} minutes`;
|
|
1008
995
|
}
|
|
1009
996
|
else {
|
|
1010
997
|
statusText += `\nš” Use "authenticate" with action: login to sign in`;
|
|
998
|
+
statusText += `\n Or run: ms365-mcp-server --login`;
|
|
1011
999
|
}
|
|
1012
1000
|
return {
|
|
1013
1001
|
content: [
|
|
@@ -1018,9 +1006,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1018
1006
|
]
|
|
1019
1007
|
};
|
|
1020
1008
|
case "logout":
|
|
1021
|
-
const
|
|
1022
|
-
|
|
1023
|
-
await enhancedMS365Auth.resetAuth();
|
|
1009
|
+
const wasAuthenticated = await outlookAuth.isAuthenticated();
|
|
1010
|
+
await outlookAuth.logout();
|
|
1024
1011
|
return {
|
|
1025
1012
|
content: [
|
|
1026
1013
|
{
|
|
@@ -1031,38 +1018,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1031
1018
|
}
|
|
1032
1019
|
]
|
|
1033
1020
|
};
|
|
1034
|
-
case "device_code":
|
|
1035
|
-
const deviceCodeInfo = await enhancedMS365Auth.getDeviceCodeInfo();
|
|
1036
|
-
return {
|
|
1037
|
-
content: [
|
|
1038
|
-
{
|
|
1039
|
-
type: "text",
|
|
1040
|
-
text: `š Microsoft 365 Device Code Authentication\n\nš± Visit: ${deviceCodeInfo.verificationUri}\nš Enter code: ${deviceCodeInfo.userCode}\n\nā³ This code will expire in 15 minutes.`
|
|
1041
|
-
}
|
|
1042
|
-
]
|
|
1043
|
-
};
|
|
1044
|
-
case "check_pending":
|
|
1045
|
-
const pendingDeviceCodeState = await enhancedMS365Auth.getPendingDeviceCodeInfo();
|
|
1046
|
-
if (pendingDeviceCodeState) {
|
|
1047
|
-
return {
|
|
1048
|
-
content: [
|
|
1049
|
-
{
|
|
1050
|
-
type: "text",
|
|
1051
|
-
text: `ā³ Pending Device Code Authentication\n\nš± Visit: ${pendingDeviceCodeState.verificationUri}\nš Enter this code: ${pendingDeviceCodeState.userCode}\n\nš” Use "authenticate" with action: login to finish authentication after entering the code.`
|
|
1052
|
-
}
|
|
1053
|
-
]
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
return {
|
|
1057
|
-
content: [
|
|
1058
|
-
{
|
|
1059
|
-
type: "text",
|
|
1060
|
-
text: "ā¹ļø No pending device code authentication found. Use 'authenticate' with action: login to start a new authentication process."
|
|
1061
|
-
}
|
|
1062
|
-
]
|
|
1063
|
-
};
|
|
1064
1021
|
default:
|
|
1065
|
-
throw new Error(`Unknown authentication action: ${action}`);
|
|
1022
|
+
throw new Error(`Unknown authentication action: ${action}. Valid actions: login, status, logout`);
|
|
1066
1023
|
}
|
|
1067
1024
|
// ============ UNIFIED EMAIL MANAGEMENT TOOL ============
|
|
1068
1025
|
case "manage_email":
|
|
@@ -1077,7 +1034,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1077
1034
|
ms365Ops.setGraphClient(graphClient);
|
|
1078
1035
|
}
|
|
1079
1036
|
else {
|
|
1080
|
-
const graphClient = await
|
|
1037
|
+
const graphClient = await outlookAuth.getGraphClient();
|
|
1081
1038
|
ms365Ops.setGraphClient(graphClient);
|
|
1082
1039
|
}
|
|
1083
1040
|
const emailAction = processedArgs?.action;
|
|
@@ -1505,7 +1462,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1505
1462
|
ms365Ops.setGraphClient(graphClient);
|
|
1506
1463
|
}
|
|
1507
1464
|
else {
|
|
1508
|
-
const graphClient = await
|
|
1465
|
+
const graphClient = await outlookAuth.getGraphClient();
|
|
1509
1466
|
ms365Ops.setGraphClient(graphClient);
|
|
1510
1467
|
}
|
|
1511
1468
|
const contactAction = args?.action || 'list';
|
|
@@ -1548,7 +1505,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1548
1505
|
ms365Ops.setGraphClient(graphClient);
|
|
1549
1506
|
}
|
|
1550
1507
|
else {
|
|
1551
|
-
const graphClient = await
|
|
1508
|
+
const graphClient = await outlookAuth.getGraphClient();
|
|
1552
1509
|
ms365Ops.setGraphClient(graphClient);
|
|
1553
1510
|
}
|
|
1554
1511
|
// Validate and normalize email input
|
|
@@ -1611,7 +1568,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1611
1568
|
ms365Ops.setGraphClient(graphClient);
|
|
1612
1569
|
}
|
|
1613
1570
|
else {
|
|
1614
|
-
const graphClient = await
|
|
1571
|
+
const graphClient = await outlookAuth.getGraphClient();
|
|
1615
1572
|
ms365Ops.setGraphClient(graphClient);
|
|
1616
1573
|
}
|
|
1617
1574
|
if (!processedArgs?.messageId) {
|
|
@@ -1684,7 +1641,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1684
1641
|
ms365Ops.setGraphClient(graphClient);
|
|
1685
1642
|
}
|
|
1686
1643
|
else {
|
|
1687
|
-
const graphClient = await
|
|
1644
|
+
const graphClient = await outlookAuth.getGraphClient();
|
|
1688
1645
|
ms365Ops.setGraphClient(graphClient);
|
|
1689
1646
|
}
|
|
1690
1647
|
let folders;
|
|
@@ -1765,7 +1722,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1765
1722
|
ms365Ops.setGraphClient(graphClient);
|
|
1766
1723
|
}
|
|
1767
1724
|
else {
|
|
1768
|
-
const graphClient = await
|
|
1725
|
+
const graphClient = await outlookAuth.getGraphClient();
|
|
1769
1726
|
ms365Ops.setGraphClient(graphClient);
|
|
1770
1727
|
}
|
|
1771
1728
|
const batchAction = args?.action;
|
|
@@ -1866,7 +1823,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1866
1823
|
ms365Ops.setGraphClient(graphClient);
|
|
1867
1824
|
}
|
|
1868
1825
|
else {
|
|
1869
|
-
const graphClient = await
|
|
1826
|
+
const graphClient = await outlookAuth.getGraphClient();
|
|
1870
1827
|
ms365Ops.setGraphClient(graphClient);
|
|
1871
1828
|
}
|
|
1872
1829
|
const aiAction = args?.action;
|
|
@@ -2099,7 +2056,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2099
2056
|
ms365Ops.setGraphClient(graphClient);
|
|
2100
2057
|
}
|
|
2101
2058
|
else {
|
|
2102
|
-
const graphClient = await
|
|
2059
|
+
const graphClient = await outlookAuth.getGraphClient();
|
|
2103
2060
|
ms365Ops.setGraphClient(graphClient);
|
|
2104
2061
|
}
|
|
2105
2062
|
const testAction = args?.action;
|
|
@@ -2267,7 +2224,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2267
2224
|
ms365Ops.setGraphClient(graphClient);
|
|
2268
2225
|
}
|
|
2269
2226
|
else {
|
|
2270
|
-
const graphClient = await
|
|
2227
|
+
const graphClient = await outlookAuth.getGraphClient();
|
|
2271
2228
|
ms365Ops.setGraphClient(graphClient);
|
|
2272
2229
|
}
|
|
2273
2230
|
const pipelineAction = args?.action;
|
|
@@ -2709,7 +2666,7 @@ async function main() {
|
|
|
2709
2666
|
ms365Config = parseArgs();
|
|
2710
2667
|
if (ms365Config.setupAuth) {
|
|
2711
2668
|
try {
|
|
2712
|
-
await
|
|
2669
|
+
await outlookAuth.setupCredentials();
|
|
2713
2670
|
process.exit(0);
|
|
2714
2671
|
}
|
|
2715
2672
|
catch (error) {
|
|
@@ -2719,7 +2676,7 @@ async function main() {
|
|
|
2719
2676
|
}
|
|
2720
2677
|
if (ms365Config.resetAuth) {
|
|
2721
2678
|
try {
|
|
2722
|
-
await
|
|
2679
|
+
await outlookAuth.resetAuth();
|
|
2723
2680
|
console.log('ā
Authentication data cleared successfully');
|
|
2724
2681
|
process.exit(0);
|
|
2725
2682
|
}
|
|
@@ -2730,8 +2687,8 @@ async function main() {
|
|
|
2730
2687
|
}
|
|
2731
2688
|
if (ms365Config.login) {
|
|
2732
2689
|
try {
|
|
2733
|
-
console.log('š Starting Microsoft 365 authentication...\n');
|
|
2734
|
-
await
|
|
2690
|
+
console.log('š Starting Microsoft 365 OAuth authentication...\n');
|
|
2691
|
+
await outlookAuth.authenticate();
|
|
2735
2692
|
console.log('ā
Login successful! You can now use MS365 MCP server.\n');
|
|
2736
2693
|
process.exit(0);
|
|
2737
2694
|
}
|
|
@@ -2742,7 +2699,7 @@ async function main() {
|
|
|
2742
2699
|
}
|
|
2743
2700
|
if (ms365Config.logout) {
|
|
2744
2701
|
try {
|
|
2745
|
-
await
|
|
2702
|
+
await outlookAuth.logout();
|
|
2746
2703
|
console.log('ā
Logged out successfully');
|
|
2747
2704
|
process.exit(0);
|
|
2748
2705
|
}
|
|
@@ -2753,15 +2710,16 @@ async function main() {
|
|
|
2753
2710
|
}
|
|
2754
2711
|
if (ms365Config.verifyLogin) {
|
|
2755
2712
|
try {
|
|
2756
|
-
const
|
|
2757
|
-
const currentUser = await enhancedMS365Auth.getCurrentUser();
|
|
2758
|
-
const storageInfo = enhancedMS365Auth.getStorageInfo();
|
|
2713
|
+
const authStatus = await outlookAuth.getAuthenticationStatus();
|
|
2759
2714
|
console.log('\nš MS365 Authentication Status\n');
|
|
2760
|
-
console.log(`Authentication: ${
|
|
2761
|
-
console.log(`Current User: ${
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2715
|
+
console.log(`Authentication: ${authStatus.authenticated ? 'ā
Valid' : 'ā Not authenticated'}`);
|
|
2716
|
+
console.log(`Current User: ${authStatus.username || 'None'}`);
|
|
2717
|
+
if (authStatus.authenticated) {
|
|
2718
|
+
console.log(`Token expires: ${authStatus.expiresAt}`);
|
|
2719
|
+
console.log(`Expires in: ${authStatus.expiresIn} minutes`);
|
|
2720
|
+
}
|
|
2721
|
+
console.log(`Storage: ~/.ms365-mcp/\n`);
|
|
2722
|
+
process.exit(authStatus.authenticated ? 0 : 1);
|
|
2765
2723
|
}
|
|
2766
2724
|
catch (error) {
|
|
2767
2725
|
console.error('ā Verification failed:', error);
|
|
@@ -2773,8 +2731,7 @@ async function main() {
|
|
|
2773
2731
|
logger.log('Multi-user mode enabled');
|
|
2774
2732
|
}
|
|
2775
2733
|
// Display storage information
|
|
2776
|
-
|
|
2777
|
-
logger.log(`Credential storage: ${storageInfo.method} at ${storageInfo.location}`);
|
|
2734
|
+
logger.log('Credential storage: ~/.ms365-mcp/');
|
|
2778
2735
|
const transport = new StdioServerTransport();
|
|
2779
2736
|
await server.connect(transport);
|
|
2780
2737
|
logger.log('MS365 MCP Server running on stdio');
|
|
@@ -50,15 +50,10 @@ export class MS365Operations {
|
|
|
50
50
|
*/
|
|
51
51
|
async getGraphClient() {
|
|
52
52
|
if (!this.graphClient) {
|
|
53
|
-
// Import the
|
|
54
|
-
const {
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
if (tokenInfo.expiresInMinutes < 5) {
|
|
58
|
-
logger.log(`Token expires in ${tokenInfo.expiresInMinutes} minutes, refreshing proactively...`);
|
|
59
|
-
await enhancedMS365Auth.refreshTokenIfNeeded();
|
|
60
|
-
}
|
|
61
|
-
this.graphClient = await enhancedMS365Auth.getGraphClient();
|
|
53
|
+
// Import the outlook auth module dynamically to avoid circular imports
|
|
54
|
+
const { outlookAuth } = await import('./outlook-auth.js');
|
|
55
|
+
// Get graph client (handles token refresh automatically)
|
|
56
|
+
this.graphClient = await outlookAuth.getGraphClient();
|
|
62
57
|
}
|
|
63
58
|
return this.graphClient;
|
|
64
59
|
}
|