@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 +23 -12
- package/auth/tools.js +11 -2
- package/cli.js +5 -24
- package/config.js +1 -1
- package/email/date-utils.js +21 -0
- package/email/list.js +4 -3
- package/email/read.js +3 -2
- package/email/search.js +4 -3
- package/package.json +1 -1
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
|
-
|
|
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
|
-
"@
|
|
145
|
+
"@tgai96/outlook-mcp"
|
|
146
146
|
]
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
```
|
|
151
151
|
|
|
152
|
-
**
|
|
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
|
|
360
|
-
- `name` field
|
|
361
|
-
- `author` field
|
|
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. **
|
|
372
|
+
3. **Verify what will be published** (recommended):
|
|
370
373
|
```bash
|
|
371
|
-
npm
|
|
374
|
+
npm pack --dry-run
|
|
372
375
|
```
|
|
373
376
|
|
|
374
|
-
|
|
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
|
-
|
|
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
|
-
"@
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
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
|
@@ -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 =
|
|
48
|
+
const date = formatDateTime(email.receivedDateTime);
|
|
48
49
|
const readStatus = email.isRead ? '' : '[UNREAD] ';
|
|
49
50
|
|
|
50
|
-
return `${index + 1}. ${readStatus}${date}
|
|
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 =
|
|
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 =
|
|
266
|
+
const date = formatDateTime(email.receivedDateTime);
|
|
266
267
|
const readStatus = email.isRead ? '' : '[UNREAD] ';
|
|
267
268
|
|
|
268
|
-
return `${index + 1}. ${readStatus}${date}
|
|
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
|