@tgai96/outlook-mcp 1.0.0 → 1.1.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 CHANGED
@@ -133,7 +133,7 @@ To use this MCP server with an MCP client, you can either use the published npm
133
133
 
134
134
  #### Option 1: Using Published npm Package (Recommended)
135
135
 
136
- If the package is published to npm, you can use it directly:
136
+ **To use the current package as-is**, use `@tgai96/outlook-mcp`:
137
137
 
138
138
  ```json
139
139
  {
@@ -142,14 +142,14 @@ If the package is published to npm, you can use it directly:
142
142
  "command": "npx",
143
143
  "args": [
144
144
  "-y",
145
- "@yourusername/outlook-mcp"
145
+ "@tgai96/outlook-mcp"
146
146
  ]
147
147
  }
148
148
  }
149
149
  }
150
150
  ```
151
151
 
152
- **Note**: The package name is `@tgai96/outlook-mcp` once published.
152
+ **To create and publish your own version**, replace `@tgai96/outlook-mcp` with your own package name and follow the [Publishing to npm](#publishing-to-npm) guide below.
153
153
 
154
154
  #### Option 2: Using Local Installation
155
155
 
@@ -354,29 +354,36 @@ If you see "Access is denied" errors:
354
354
 
355
355
  ## Publishing to npm
356
356
 
357
- To publish this package to npm:
357
+ To publish this package to npm under your own namespace:
358
358
 
359
- 1. **Update package.json metadata** (optional but recommended):
360
- - `name` field is already set to `@tgai96/outlook-mcp`
361
- - `author` field is set to `tgai96`
359
+ 1. **Update package.json metadata**:
360
+ - Update the `name` field to your desired package name (e.g., `@your-username/outlook-mcp` or `outlook-mcp`)
361
+ - Update the `author` field with your name/username
362
362
  - Optionally add `repository`, `bugs`, and `homepage` fields if you have a GitHub repo
363
+ - Update the `version` field (following semantic versioning)
363
364
 
364
365
  2. **Login to npm**:
365
366
  ```bash
366
367
  npm login
367
368
  ```
369
+
370
+ Enter your npm username, password, and email when prompted.
368
371
 
369
- 3. **Publish to npm**:
372
+ 3. **Verify what will be published** (recommended):
370
373
  ```bash
371
- npm publish
374
+ npm pack --dry-run
372
375
  ```
373
376
 
374
- For scoped packages like `@tgai96/outlook-mcp`, use:
377
+ This shows which files will be included in the package (based on the `files` field in `package.json`).
378
+
379
+ 4. **Publish to npm**:
380
+
381
+ For scoped packages (packages starting with `@username/`), use:
375
382
  ```bash
376
383
  npm publish --access public
377
384
  ```
378
385
 
379
- 4. **After publishing**, users can use it in their MCP client configuration:
386
+ 5. **After publishing**, users can use it in their MCP client configuration:
380
387
  ```json
381
388
  {
382
389
  "mcpServers": {
@@ -384,12 +391,16 @@ To publish this package to npm:
384
391
  "command": "npx",
385
392
  "args": [
386
393
  "-y",
387
- "@tgai96/outlook-mcp"
394
+ "@your-username/outlook-mcp"
388
395
  ]
389
396
  }
390
397
  }
391
398
  }
392
399
  ```
400
+
401
+ Replace `@your-username/outlook-mcp` with your actual published package name.
402
+
403
+ **Note**: Make sure to review the `files` field in `package.json` to ensure only necessary files are published (sensitive files, test files, and development scripts should be excluded).
393
404
 
394
405
  ## License
395
406
 
package/auth/tools.js CHANGED
@@ -3,7 +3,15 @@
3
3
  */
4
4
  const config = require('../config');
5
5
  const tokenManager = require('./token-manager');
6
- const { ensureAuthenticated, tokenStorage } = require('./index');
6
+ // Lazy load to avoid circular dependency with ./index
7
+ let ensureAuthenticated = null;
8
+ function getEnsureAuthenticated() {
9
+ if (!ensureAuthenticated) {
10
+ const authModule = require('./index');
11
+ ensureAuthenticated = authModule.ensureAuthenticated;
12
+ }
13
+ return ensureAuthenticated;
14
+ }
7
15
 
8
16
  /**
9
17
  * About tool handler
@@ -42,7 +50,8 @@ async function handleAuthenticate(args) {
42
50
  // If not forcing, try to get a valid token first (will auto-refresh if needed)
43
51
  if (!force) {
44
52
  try {
45
- const accessToken = await ensureAuthenticated();
53
+ const ensureAuth = getEnsureAuthenticated();
54
+ const accessToken = await ensureAuth();
46
55
  if (accessToken) {
47
56
  console.error('[AUTHENTICATE] Successfully obtained valid access token (may have been refreshed)');
48
57
  return {
package/cli.js CHANGED
@@ -216,31 +216,12 @@ if (command === 'config') {
216
216
  process.exit(1);
217
217
  });
218
218
  } else {
219
- // Default: Start the MCP server
219
+ // Default: Start the MCP server directly (not as child process)
220
220
  // This is what gets run when npx outlook-mcp is called without arguments
221
+ // We need to run index.js directly (not spawn) for proper stdio communication with MCP clients
221
222
  const mcpServerPath = path.join(__dirname, 'index.js');
222
- const child = spawn('node', [mcpServerPath], {
223
- stdio: 'inherit',
224
- env: process.env
225
- });
226
223
 
227
- // Handle process termination
228
- process.on('SIGINT', () => {
229
- child.kill('SIGINT');
230
- process.exit(0);
231
- });
232
-
233
- process.on('SIGTERM', () => {
234
- child.kill('SIGTERM');
235
- process.exit(0);
236
- });
237
-
238
- child.on('exit', (code) => {
239
- process.exit(code || 0);
240
- });
241
-
242
- child.on('error', (error) => {
243
- console.error('Error starting MCP server:', error.message);
244
- process.exit(1);
245
- });
224
+ // For MCP server mode, we need direct stdio, so require and run index.js directly
225
+ // This ensures proper communication with MCP clients
226
+ require(mcpServerPath);
246
227
  }
package/config.js CHANGED
@@ -51,7 +51,7 @@ const loadedConfig = loadConfig();
51
51
  module.exports = {
52
52
  // Server information
53
53
  SERVER_NAME: "outlook-assistant",
54
- SERVER_VERSION: "1.0.0",
54
+ SERVER_VERSION: "1.1.0",
55
55
 
56
56
  // Test mode setting
57
57
  USE_TEST_MODE: loadedConfig.USE_TEST_MODE,
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Date formatting utilities for email module
3
+ */
4
+
5
+ /**
6
+ * Format date to show both UTC and local time
7
+ * @param {string} dateTimeString - ISO 8601 date string from API
8
+ * @returns {string} - Formatted date string with UTC and local time
9
+ */
10
+ function formatDateTime(dateTimeString) {
11
+ const date = new Date(dateTimeString);
12
+ const utcString = date.toUTCString();
13
+ const localString = date.toLocaleString();
14
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
15
+ return `${utcString} (UTC) / ${localString} (${timezone})`;
16
+ }
17
+
18
+ module.exports = {
19
+ formatDateTime
20
+ };
21
+
package/email/list.js CHANGED
@@ -5,11 +5,12 @@ const config = require('../config');
5
5
  const { callGraphAPI, callGraphAPIPaginated } = require('../utils/graph-api');
6
6
  const { ensureAuthenticated } = require('../auth');
7
7
  const { resolveFolderPath } = require('./folder-utils');
8
+ const { formatDateTime } = require('./date-utils');
8
9
 
9
10
  /**
10
11
  * List emails handler
11
12
  * @param {object} args - Tool arguments
12
- * @returns {object} - MCP response
13
+ * @returns {Promise<object>} - MCP response
13
14
  */
14
15
  async function handleListEmails(args) {
15
16
  const folder = args.folder || "inbox";
@@ -44,10 +45,10 @@ async function handleListEmails(args) {
44
45
  // Format results
45
46
  const emailList = response.value.map((email, index) => {
46
47
  const sender = email.from ? email.from.emailAddress : { name: 'Unknown', address: 'unknown' };
47
- const date = new Date(email.receivedDateTime).toLocaleString();
48
+ const date = formatDateTime(email.receivedDateTime);
48
49
  const readStatus = email.isRead ? '' : '[UNREAD] ';
49
50
 
50
- return `${index + 1}. ${readStatus}${date} - From: ${sender.name} (${sender.address})\nSubject: ${email.subject}\nID: ${email.id}\n`;
51
+ return `${index + 1}. ${readStatus}Date: ${date}\nFrom: ${sender.name} (${sender.address})\nSubject: ${email.subject}\nID: ${email.id}\n`;
51
52
  }).join("\n");
52
53
 
53
54
  return {
package/email/read.js CHANGED
@@ -4,11 +4,12 @@
4
4
  const config = require('../config');
5
5
  const { callGraphAPI } = require('../utils/graph-api');
6
6
  const { ensureAuthenticated } = require('../auth');
7
+ const { formatDateTime } = require('./date-utils');
7
8
 
8
9
  /**
9
10
  * Read email handler
10
11
  * @param {object} args - Tool arguments
11
- * @returns {object} - MCP response
12
+ * @returns {Promise<object>} - MCP response
12
13
  */
13
14
  async function handleReadEmail(args) {
14
15
  const emailId = args.id;
@@ -51,7 +52,7 @@ async function handleReadEmail(args) {
51
52
  const to = email.toRecipients ? email.toRecipients.map(r => `${r.emailAddress.name} (${r.emailAddress.address})`).join(", ") : 'None';
52
53
  const cc = email.ccRecipients && email.ccRecipients.length > 0 ? email.ccRecipients.map(r => `${r.emailAddress.name} (${r.emailAddress.address})`).join(", ") : 'None';
53
54
  const bcc = email.bccRecipients && email.bccRecipients.length > 0 ? email.bccRecipients.map(r => `${r.emailAddress.name} (${r.emailAddress.address})`).join(", ") : 'None';
54
- const date = new Date(email.receivedDateTime).toLocaleString();
55
+ const date = formatDateTime(email.receivedDateTime);
55
56
 
56
57
  // Extract body content
57
58
  let body = '';
package/email/search.js CHANGED
@@ -5,11 +5,12 @@ const config = require('../config');
5
5
  const { callGraphAPI, callGraphAPIPaginated } = require('../utils/graph-api');
6
6
  const { ensureAuthenticated } = require('../auth');
7
7
  const { resolveFolderPath } = require('./folder-utils');
8
+ const { formatDateTime } = require('./date-utils');
8
9
 
9
10
  /**
10
11
  * Search emails handler
11
12
  * @param {object} args - Tool arguments
12
- * @returns {object} - MCP response
13
+ * @returns {Promise<object>} - MCP response
13
14
  */
14
15
  async function handleSearchEmails(args) {
15
16
  const folder = args.folder || "inbox";
@@ -262,10 +263,10 @@ function formatSearchResults(response) {
262
263
  // Format results
263
264
  const emailList = response.value.map((email, index) => {
264
265
  const sender = email.from?.emailAddress || { name: 'Unknown', address: 'unknown' };
265
- const date = new Date(email.receivedDateTime).toLocaleString();
266
+ const date = formatDateTime(email.receivedDateTime);
266
267
  const readStatus = email.isRead ? '' : '[UNREAD] ';
267
268
 
268
- return `${index + 1}. ${readStatus}${date} - From: ${sender.name} (${sender.address})\nSubject: ${email.subject}\nID: ${email.id}\n`;
269
+ return `${index + 1}. ${readStatus}Date: ${date}\nFrom: ${sender.name} (${sender.address})\nSubject: ${email.subject}\nID: ${email.id}\n`;
269
270
  }).join("\n");
270
271
 
271
272
  // Add search strategy info if available
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tgai96/outlook-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "MCP server for Claude to access Outlook data via Microsoft Graph API",
5
5
  "main": "index.js",
6
6
  "bin": {