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 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
- --setup-auth Set up MS365 API credentials
124
- --reset-auth Clear stored authentication tokens
125
- --multi-user Enable multi-user authentication mode
126
- --login Login to MS365
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
- Setup:
135
- 1. Run: npx ms365-mcp-server --setup-auth
136
- 2. Follow the instructions to set up Azure App Registration
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 Setup:
140
- The server supports two methods for providing MS365 API credentials:
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. Environment Variables (Recommended):
143
- - MS365_CLIENT_ID: Your Azure app client ID
144
- - MS365_CLIENT_SECRET: Your Azure app client secret
145
- - MS365_TENANT_ID: Your Azure tenant ID (or "common")
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
- 2. Credentials File:
150
- - Run --setup-auth for interactive setup
151
- - Saves credentials to ~/.ms365-mcp/credentials.json
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:44001/oauth2callback
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 --setup-auth # Set up authentication
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 { enhancedMS365Auth } from './utils/ms365-auth-enhanced.js';
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.1.19"
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 device code flow, status checking, and logout. RECOMMENDED for all auth operations.",
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", "device_code", "check_pending"],
882
- description: "Auth action: login (device code auth), status (check auth status), logout (clear tokens), device_code (get device code only), check_pending (check pending auth)",
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 enhancedMS365Auth.isAuthenticated() && !args?.force) {
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! Use force: true to re-authenticate.`
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
- // First, try to complete any existing pending authentication
959
- const existingResult = await enhancedMS365Auth.completeDeviceCodeAuth();
960
- if (existingResult) {
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: `šŸ” Microsoft 365 Device Code Authentication\n\nšŸ“± Visit: ${deviceCodeInfo.verificationUri}\nšŸ”‘ Enter this code: ${deviceCodeInfo.userCode}\n\nā³ After completing authentication in your browser, call this tool again to finish the process.\n\nšŸ’” This code will expire in 15 minutes.`
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 again or use CLI: node dist/index.js --login`
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 isAuthenticated = await enhancedMS365Auth.isAuthenticated();
999
- const currentUser = await enhancedMS365Auth.getCurrentUser();
1000
- const storageInfo = enhancedMS365Auth.getStorageInfo();
1001
- const tokenInfo = await enhancedMS365Auth.getTokenExpirationInfo();
1002
- let statusText = `šŸ“Š Microsoft 365 Authentication Status\n\nšŸ” Authentication: ${isAuthenticated ? 'āœ… Valid' : 'āŒ Not authenticated'}\nšŸ‘¤ Current User: ${currentUser || 'None'}\n`;
1003
- if (isAuthenticated) {
1004
- statusText += `\nā° Token expires in: ${tokenInfo.expiresInMinutes} minutes`;
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 accountKey = args?.accountKey;
1022
- const wasAuthenticated = await enhancedMS365Auth.isAuthenticated();
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 enhancedMS365Auth.getGraphClient();
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 enhancedMS365Auth.getGraphClient();
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 enhancedMS365Auth.getGraphClient();
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 enhancedMS365Auth.getGraphClient();
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 enhancedMS365Auth.getGraphClient();
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 enhancedMS365Auth.getGraphClient();
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 enhancedMS365Auth.getGraphClient();
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 enhancedMS365Auth.getGraphClient();
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 enhancedMS365Auth.getGraphClient();
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 enhancedMS365Auth.setupCredentials();
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 enhancedMS365Auth.resetAuth();
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 enhancedMS365Auth.authenticateWithDeviceCode();
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 enhancedMS365Auth.resetAuth();
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 isAuthenticated = await enhancedMS365Auth.isAuthenticated();
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: ${isAuthenticated ? 'āœ… Valid' : 'āŒ Not authenticated'}`);
2761
- console.log(`Current User: ${currentUser || 'None'}`);
2762
- console.log(`Storage method: ${storageInfo.method}`);
2763
- console.log(`Storage location: ${storageInfo.location}\n`);
2764
- process.exit(isAuthenticated ? 0 : 1);
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
- const storageInfo = enhancedMS365Auth.getStorageInfo();
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 enhanced auth module dynamically to avoid circular imports
54
- const { enhancedMS365Auth } = await import('./ms365-auth-enhanced.js');
55
- // Proactive token check - refresh if expiring within 5 minutes
56
- const tokenInfo = await enhancedMS365Auth.getTokenExpirationInfo();
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
  }