ms365-mcp-server 1.1.5 → 1.1.7

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 CHANGED
@@ -38,6 +38,9 @@ ms365-mcp-server --login
38
38
 
39
39
  # Start the server
40
40
  ms365-mcp-server
41
+
42
+ # Start with custom server URL
43
+ ms365-mcp-server --server-url https://your-domain.com
41
44
  ```
42
45
 
43
46
  **Option B: Run with npx (no installation needed)**
@@ -47,6 +50,9 @@ npx ms365-mcp-server --login
47
50
 
48
51
  # Start the server
49
52
  npx ms365-mcp-server
53
+
54
+ # Start with custom server URL
55
+ npx ms365-mcp-server --server-url https://your-domain.com
50
56
  ```
51
57
 
52
58
  ### 2. SIYA Desktop Integration
@@ -57,7 +63,7 @@ npx ms365-mcp-server
57
63
  "mcpServers": {
58
64
  "ms365": {
59
65
  "command": "ms365-mcp-server",
60
- "args": []
66
+ "args": ["--server-url", "https://your-domain.com"]
61
67
  }
62
68
  }
63
69
  }
@@ -69,7 +75,7 @@ npx ms365-mcp-server
69
75
  "mcpServers": {
70
76
  "ms365": {
71
77
  "command": "npx",
72
- "args": ["ms365-mcp-server"]
78
+ "args": ["ms365-mcp-server", "--server-url", "https://your-domain.com"]
73
79
  }
74
80
  }
75
81
  }
@@ -84,6 +90,16 @@ Chat with SIYA and ask it to help with your emails! The tools are designed for n
84
90
  ```bash
85
91
  # One-command authentication
86
92
  ms365-mcp-server --login
93
+
94
+ # Authentication with custom server URL
95
+ ms365-mcp-server --login --server-url https://your-domain.com
96
+ ```
97
+
98
+ ### Environment Variables
99
+ ```bash
100
+ # Set server URL via environment variable
101
+ export SERVER_URL=https://your-domain.com
102
+ ms365-mcp-server
87
103
  ```
88
104
 
89
105
  ### MCP Tool Authentication
@@ -381,4 +397,34 @@ Contributions welcome! Please submit issues and pull requests.
381
397
 
382
398
  **Built with 🔒 Security and ❤️ for the AI community**
383
399
 
384
- *Production-ready Microsoft 365 integration for SIYA Desktop and MCP applications*
400
+ *Production-ready Microsoft 365 integration for SIYA Desktop and MCP applications*
401
+
402
+ ## 🔧 Configuration Options
403
+
404
+ ### Server Configuration
405
+ - `--server-url URL`: Set custom server URL for attachments and authentication (default: http://localhost:55000)
406
+ - `SERVER_URL`: Environment variable to set server URL
407
+
408
+ ### Authentication Options
409
+ - `--setup-auth`: Set up MS365 API credentials
410
+ - `--reset-auth`: Clear stored authentication tokens
411
+ - `--multi-user`: Enable multi-user authentication mode
412
+ - `--login`: Login to MS365
413
+ - `--logout`: Logout from MS365
414
+ - `--verify-login`: Verify login status
415
+
416
+ ### General Options
417
+ - `--debug`: Enable debug output
418
+ - `--non-interactive`, `-n`: Run in non-interactive mode (no prompt)
419
+ - `--help`, `-h`: Show help message
420
+
421
+ ## 📝 Notes
422
+
423
+ - The server URL is used for:
424
+ 1. Serving email attachments
425
+ 2. Generating attachment URLs
426
+ 3. OAuth redirect URIs
427
+ 4. Authentication callbacks
428
+ - Attachments are served for 24 hours before automatic cleanup
429
+ - Default server port is 55000
430
+ - For production use, set a custom server URL with HTTPS
package/bin/cli.js CHANGED
@@ -63,6 +63,7 @@ let multiUser = false;
63
63
  let login = false;
64
64
  let logout = false;
65
65
  let verifyLogin = false;
66
+ let serverUrl = process.env.SERVER_URL || 'http://localhost:55000';
66
67
 
67
68
  // Detect if we're running under an MCP context (Claude/SIYA/ChatGPT/etc.)
68
69
  const isMcpContext =
@@ -104,6 +105,14 @@ for (let i = 0; i < args.length; i++) {
104
105
  } else if (arg === '--verify-login') {
105
106
  verifyLogin = true;
106
107
  writeDebug('Verify login mode enabled');
108
+ } else if (arg === '--server-url') {
109
+ if (i + 1 < args.length) {
110
+ serverUrl = args[++i];
111
+ writeDebug(`Server URL set to: ${serverUrl}`);
112
+ } else {
113
+ console.error('Error: --server-url requires a value');
114
+ process.exit(1);
115
+ }
107
116
  } else if (arg === '--help' || arg === '-h') {
108
117
  console.log(`
109
118
  MS365 MCP Server - Microsoft 365 Integration for Claude/SIYA Desktop
@@ -117,6 +126,7 @@ Options:
117
126
  --login Login to MS365
118
127
  --logout Logout from MS365
119
128
  --verify-login Verify login to MS365
129
+ --server-url URL Set the server URL (default: http://localhost:55000)
120
130
  --debug Enable debug output
121
131
  --non-interactive, -n Run in non-interactive mode (no prompt)
122
132
  --help, -h Show this help message
@@ -134,6 +144,7 @@ Authentication Setup:
134
144
  - MS365_CLIENT_SECRET: Your Azure app client secret
135
145
  - MS365_TENANT_ID: Your Azure tenant ID (or "common")
136
146
  - MS365_REDIRECT_URI: OAuth redirect URI (optional)
147
+ - SERVER_URL: Server URL for attachments (optional)
137
148
 
138
149
  2. Credentials File:
139
150
  - Run --setup-auth for interactive setup
@@ -158,6 +169,7 @@ Examples:
158
169
  npx ms365-mcp-server # Start the server
159
170
  npx ms365-mcp-server --multi-user # Start in multi-user mode
160
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
161
173
  `);
162
174
  process.exit(0);
163
175
  }
@@ -203,6 +215,7 @@ function startServerWithPath(serverPath) {
203
215
  if (verifyLogin) serverArgs.push('--verify-login');
204
216
  if (debug) serverArgs.push('--debug');
205
217
  if (nonInteractive) serverArgs.push('--non-interactive');
218
+ if (serverUrl) serverArgs.push('--server-url', serverUrl);
206
219
 
207
220
  writeDebug(`Server arguments: ${serverArgs.join(' ')}`);
208
221
 
@@ -213,6 +226,7 @@ function startServerWithPath(serverPath) {
213
226
  ...process.env,
214
227
  // Ensure environment variables are passed through
215
228
  NODE_PATH: process.env.NODE_PATH || '',
229
+ SERVER_URL: serverUrl
216
230
  }
217
231
  });
218
232
 
package/dist/index.js CHANGED
@@ -16,7 +16,17 @@ import { multiUserMS365Auth } from './utils/multi-user-auth.js';
16
16
  import { enhancedMS365Auth } from './utils/ms365-auth-enhanced.js';
17
17
  // Create singleton MS365Operations instance
18
18
  const ms365Ops = new MS365Operations();
19
- let ms365Config;
19
+ let ms365Config = {
20
+ setupAuth: false,
21
+ resetAuth: false,
22
+ debug: false,
23
+ nonInteractive: false,
24
+ multiUser: false,
25
+ login: false,
26
+ logout: false,
27
+ verifyLogin: false,
28
+ serverUrl: process.env.SERVER_URL || 'http://localhost:55000'
29
+ };
20
30
  function parseArgs() {
21
31
  const args = process.argv.slice(2);
22
32
  const config = {
@@ -27,40 +37,36 @@ function parseArgs() {
27
37
  multiUser: false,
28
38
  login: false,
29
39
  logout: false,
30
- verifyLogin: false
40
+ verifyLogin: false,
41
+ serverUrl: process.env.SERVER_URL || 'http://localhost:55000'
31
42
  };
32
43
  for (let i = 0; i < args.length; i++) {
33
44
  const arg = args[i];
34
- if (arg === '--setup-auth') {
45
+ if (arg === '--setup-auth')
35
46
  config.setupAuth = true;
36
- }
37
- else if (arg === '--reset-auth') {
47
+ else if (arg === '--reset-auth')
38
48
  config.resetAuth = true;
39
- }
40
- else if (arg === '--debug' || arg === '-d') {
49
+ else if (arg === '--debug')
41
50
  config.debug = true;
42
- }
43
- else if (arg === '--non-interactive' || arg === '-n') {
51
+ else if (arg === '--non-interactive' || arg === '-n')
44
52
  config.nonInteractive = true;
45
- }
46
- else if (arg === '--multi-user') {
53
+ else if (arg === '--multi-user')
47
54
  config.multiUser = true;
48
- }
49
- else if (arg === '--login') {
55
+ else if (arg === '--login')
50
56
  config.login = true;
51
- }
52
- else if (arg === '--logout') {
57
+ else if (arg === '--logout')
53
58
  config.logout = true;
54
- }
55
- else if (arg === '--verify-login') {
59
+ else if (arg === '--verify-login')
56
60
  config.verifyLogin = true;
61
+ else if (arg === '--server-url' && i + 1 < args.length) {
62
+ config.serverUrl = args[++i];
57
63
  }
58
64
  }
59
65
  return config;
60
66
  }
61
67
  const server = new Server({
62
68
  name: "ms365-mcp-server",
63
- version: "1.1.5"
69
+ version: "1.1.7"
64
70
  }, {
65
71
  capabilities: {
66
72
  resources: {
@@ -1052,7 +1058,7 @@ function getListOfArtifacts(functionName, attachments) {
1052
1058
  // Set up Express server for file serving
1053
1059
  const app = express();
1054
1060
  const PORT = process.env.PORT || 55000;
1055
- const SERVER_URL = process.env.SERVER_URL || `http://localhost:${PORT}`;
1061
+ const SERVER_URL = ms365Config.serverUrl || `http://localhost:${PORT}`;
1056
1062
  // Get the directory name in ESM
1057
1063
  const __filename = fileURLToPath(import.meta.url);
1058
1064
  const __dirname = path.dirname(__filename);
@@ -1,4 +1,5 @@
1
1
  import { logger } from './api.js';
2
+ import mimeTypes from 'mime-types';
2
3
  /**
3
4
  * Microsoft 365 operations manager class
4
5
  */
@@ -686,19 +687,48 @@ export class MS365Operations {
686
687
  async getAttachment(messageId, attachmentId) {
687
688
  try {
688
689
  const graphClient = await this.getGraphClient();
690
+ logger.log(`Fetching attachment ${attachmentId} from message ${messageId}...`);
691
+ // First get attachment metadata
689
692
  const attachment = await graphClient
690
693
  .api(`/me/messages/${messageId}/attachments/${attachmentId}`)
691
694
  .get();
692
- return {
693
- name: attachment.name || '',
694
- contentType: attachment.contentType || 'application/octet-stream',
695
- contentBytes: attachment.contentBytes || '',
695
+ logger.log(`Retrieved attachment metadata: ${attachment.name} (${attachment.contentType}, ${attachment.size} bytes)`);
696
+ // Determine content type if not provided
697
+ let contentType = attachment.contentType;
698
+ if (!contentType && attachment.name) {
699
+ contentType = mimeTypes.lookup(attachment.name) || 'application/octet-stream';
700
+ logger.log(`Inferred content type for ${attachment.name}: ${contentType}`);
701
+ }
702
+ // Validate content bytes
703
+ if (!attachment.contentBytes) {
704
+ logger.error('No content bytes found in attachment');
705
+ throw new Error('Attachment content is empty');
706
+ }
707
+ // Return the attachment data
708
+ const result = {
709
+ name: attachment.name || 'unnamed_attachment',
710
+ contentType: contentType || 'application/octet-stream',
711
+ contentBytes: attachment.contentBytes,
696
712
  size: attachment.size || 0
697
713
  };
714
+ logger.log(`Successfully processed attachment: ${result.name} (${result.contentType}, ${result.size} bytes)`);
715
+ return result;
698
716
  }
699
717
  catch (error) {
700
718
  logger.error('Error getting attachment:', error);
701
- throw error;
719
+ // Provide more specific error messages
720
+ if (error.status === 404) {
721
+ throw new Error(`Attachment not found: ${error.message}`);
722
+ }
723
+ else if (error.status === 401) {
724
+ throw new Error('Authentication failed. Please re-authenticate.');
725
+ }
726
+ else if (error.status === 403) {
727
+ throw new Error('Permission denied to access this attachment.');
728
+ }
729
+ else {
730
+ throw new Error(`Failed to get attachment: ${error.message}`);
731
+ }
702
732
  }
703
733
  }
704
734
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ms365-mcp-server",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "description": "Microsoft 365 MCP Server for managing Microsoft 365 email through natural language interactions with full OAuth2 authentication support",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",