outlook-reader-mcp 1.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/LICENSE +674 -0
- package/README.md +74 -0
- package/dist/auth.js +219 -0
- package/dist/files.js +32 -0
- package/dist/mail.js +120 -0
- package/dist/mcp-server.js +31 -0
- package/dist/tools/authenticate/definition.js +31 -0
- package/dist/tools/authenticate/index.js +10 -0
- package/dist/tools/authenticate/key.js +4 -0
- package/dist/tools/authenticate/schema.js +5 -0
- package/dist/tools/download-attachment/definition.js +36 -0
- package/dist/tools/download-attachment/index.js +10 -0
- package/dist/tools/download-attachment/key.js +4 -0
- package/dist/tools/download-attachment/schema.js +14 -0
- package/dist/tools/download-attachments/definition.js +51 -0
- package/dist/tools/download-attachments/index.js +10 -0
- package/dist/tools/download-attachments/key.js +4 -0
- package/dist/tools/download-attachments/schema.js +20 -0
- package/dist/tools/get-email/definition.js +33 -0
- package/dist/tools/get-email/index.js +10 -0
- package/dist/tools/get-email/key.js +4 -0
- package/dist/tools/get-email/schema.js +9 -0
- package/dist/tools/get-emails/definition.js +31 -0
- package/dist/tools/get-emails/index.js +10 -0
- package/dist/tools/get-emails/key.js +4 -0
- package/dist/tools/get-emails/schema.js +11 -0
- package/dist/tools/index.js +25 -0
- package/dist/tools/list-attachments/definition.js +24 -0
- package/dist/tools/list-attachments/index.js +10 -0
- package/dist/tools/list-attachments/key.js +4 -0
- package/dist/tools/list-attachments/schema.js +9 -0
- package/dist/tools/list-emails/definition.js +33 -0
- package/dist/tools/list-emails/index.js +10 -0
- package/dist/tools/list-emails/key.js +4 -0
- package/dist/tools/list-emails/schema.js +34 -0
- package/dist/tools/list-folders/definition.js +15 -0
- package/dist/tools/list-folders/index.js +10 -0
- package/dist/tools/list-folders/key.js +4 -0
- package/dist/tools/list-folders/schema.js +5 -0
- package/dist/tools/search-emails/definition.js +24 -0
- package/dist/tools/search-emails/index.js +10 -0
- package/dist/tools/search-emails/key.js +4 -0
- package/dist/tools/search-emails/schema.js +17 -0
- package/dist/tools/sign-out/definition.js +13 -0
- package/dist/tools/sign-out/index.js +10 -0
- package/dist/tools/sign-out/key.js +4 -0
- package/dist/tools/sign-out/schema.js +5 -0
- package/dist/tools/wrap.js +45 -0
- package/package.json +55 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.schema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.schema = zod_1.z.object({
|
|
6
|
+
messageId: zod_1.z.string().describe('The email message ID'),
|
|
7
|
+
attachmentIds: zod_1.z
|
|
8
|
+
.array(zod_1.z.string())
|
|
9
|
+
.optional()
|
|
10
|
+
.describe('Specific attachment IDs to download (from list_attachments). Omit to download ALL file attachments of the message.'),
|
|
11
|
+
saveTo: zod_1.z
|
|
12
|
+
.string()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe('Directory path to save the files. Defaults to user Downloads folder (e.g. C:\\Users\\username\\Downloads)'),
|
|
15
|
+
includeInline: zod_1.z
|
|
16
|
+
.boolean()
|
|
17
|
+
.optional()
|
|
18
|
+
.default(false)
|
|
19
|
+
.describe('When downloading all attachments, also include inline ones (embedded images, signatures). Default false.'),
|
|
20
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.description = void 0;
|
|
4
|
+
exports.handler = handler;
|
|
5
|
+
const mail_js_1 = require("../../mail.js");
|
|
6
|
+
exports.description = 'Get the full content of a specific email by its ID, including the complete body. To fetch several emails at once, use get_emails instead.';
|
|
7
|
+
async function handler({ id }) {
|
|
8
|
+
const m = await (0, mail_js_1.getEmail)(id);
|
|
9
|
+
const from = m.from?.emailAddress;
|
|
10
|
+
const to = (m.toRecipients ?? [])
|
|
11
|
+
.map((r) => `${r.emailAddress?.name ?? ''} <${r.emailAddress?.address ?? ''}>`)
|
|
12
|
+
.join(', ');
|
|
13
|
+
// Graph returns plain text thanks to the Prefer header; the regex strip is
|
|
14
|
+
// only a fallback in case the header is ignored.
|
|
15
|
+
const body = m.body?.content ?? '';
|
|
16
|
+
const plainBody = m.body?.contentType === 'html'
|
|
17
|
+
? body
|
|
18
|
+
.replace(/<[^>]+>/g, ' ')
|
|
19
|
+
.replace(/\s+/g, ' ')
|
|
20
|
+
.trim()
|
|
21
|
+
: body;
|
|
22
|
+
const text = [
|
|
23
|
+
`ID: ${m.id}`,
|
|
24
|
+
`Subject: ${m.subject ?? '(no subject)'}`,
|
|
25
|
+
`From: ${from?.name ?? ''} <${from?.address ?? ''}>`,
|
|
26
|
+
`To: ${to}`,
|
|
27
|
+
`Date: ${m.receivedDateTime ?? ''}`,
|
|
28
|
+
`Attachments: ${m.hasAttachments ?? false}`,
|
|
29
|
+
`---`,
|
|
30
|
+
plainBody,
|
|
31
|
+
].join('\n');
|
|
32
|
+
return { content: [{ type: 'text', text }] };
|
|
33
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.register = register;
|
|
4
|
+
const wrap_js_1 = require("../wrap.js");
|
|
5
|
+
const definition_js_1 = require("./definition.js");
|
|
6
|
+
const key_js_1 = require("./key.js");
|
|
7
|
+
const schema_js_1 = require("./schema.js");
|
|
8
|
+
function register(server) {
|
|
9
|
+
server.registerTool(key_js_1.KEY, { description: definition_js_1.description, inputSchema: schema_js_1.schema }, (0, wrap_js_1.wrapHandler)(definition_js_1.handler));
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.schema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.schema = zod_1.z.object({
|
|
6
|
+
id: zod_1.z
|
|
7
|
+
.string()
|
|
8
|
+
.describe('The email message ID (obtained from list_emails or search_emails)'),
|
|
9
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.description = void 0;
|
|
4
|
+
exports.handler = handler;
|
|
5
|
+
const mail_js_1 = require("../../mail.js");
|
|
6
|
+
exports.description = 'Get the full content of multiple emails by their IDs in a single batched request. Much faster than calling get_email repeatedly. Returns subject, sender, recipients, and complete body for each.';
|
|
7
|
+
function formatMessage(m) {
|
|
8
|
+
const from = m.from?.emailAddress;
|
|
9
|
+
const to = (m.toRecipients ?? [])
|
|
10
|
+
.map((r) => `${r.emailAddress?.name ?? ''} <${r.emailAddress?.address ?? ''}>`)
|
|
11
|
+
.join(', ');
|
|
12
|
+
return [
|
|
13
|
+
`ID: ${m.id}`,
|
|
14
|
+
`Subject: ${m.subject ?? '(no subject)'}`,
|
|
15
|
+
`From: ${from?.name ?? ''} <${from?.address ?? ''}>`,
|
|
16
|
+
`To: ${to}`,
|
|
17
|
+
`Date: ${m.receivedDateTime ?? ''}`,
|
|
18
|
+
`Attachments: ${m.hasAttachments ?? false}`,
|
|
19
|
+
`---`,
|
|
20
|
+
m.body?.content ?? '',
|
|
21
|
+
].join('\n');
|
|
22
|
+
}
|
|
23
|
+
async function handler({ ids }) {
|
|
24
|
+
const results = await (0, mail_js_1.getEmails)(ids);
|
|
25
|
+
const text = results
|
|
26
|
+
.map((r, i) => r.ok
|
|
27
|
+
? `===== [${i + 1}/${results.length}] =====\n${formatMessage(r.message)}`
|
|
28
|
+
: `===== [${i + 1}/${results.length}] =====\nFailed to fetch ${r.id}: ${r.error}`)
|
|
29
|
+
.join('\n\n');
|
|
30
|
+
return { content: [{ type: 'text', text }] };
|
|
31
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.register = register;
|
|
4
|
+
const wrap_js_1 = require("../wrap.js");
|
|
5
|
+
const definition_js_1 = require("./definition.js");
|
|
6
|
+
const key_js_1 = require("./key.js");
|
|
7
|
+
const schema_js_1 = require("./schema.js");
|
|
8
|
+
function register(server) {
|
|
9
|
+
server.registerTool(key_js_1.KEY, { description: definition_js_1.description, inputSchema: schema_js_1.schema }, (0, wrap_js_1.wrapHandler)(definition_js_1.handler));
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.schema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.schema = zod_1.z.object({
|
|
6
|
+
ids: zod_1.z
|
|
7
|
+
.array(zod_1.z.string())
|
|
8
|
+
.min(1)
|
|
9
|
+
.max(50)
|
|
10
|
+
.describe('Email message IDs to fetch (from list_emails or search_emails). Max 50.'),
|
|
11
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerAllTools = registerAllTools;
|
|
4
|
+
const index_js_1 = require("./authenticate/index.js");
|
|
5
|
+
const index_js_2 = require("./download-attachment/index.js");
|
|
6
|
+
const index_js_3 = require("./download-attachments/index.js");
|
|
7
|
+
const index_js_4 = require("./get-email/index.js");
|
|
8
|
+
const index_js_5 = require("./get-emails/index.js");
|
|
9
|
+
const index_js_6 = require("./list-attachments/index.js");
|
|
10
|
+
const index_js_7 = require("./list-emails/index.js");
|
|
11
|
+
const index_js_8 = require("./list-folders/index.js");
|
|
12
|
+
const index_js_9 = require("./search-emails/index.js");
|
|
13
|
+
const index_js_10 = require("./sign-out/index.js");
|
|
14
|
+
function registerAllTools(server) {
|
|
15
|
+
(0, index_js_1.register)(server);
|
|
16
|
+
(0, index_js_10.register)(server);
|
|
17
|
+
(0, index_js_7.register)(server);
|
|
18
|
+
(0, index_js_4.register)(server);
|
|
19
|
+
(0, index_js_5.register)(server);
|
|
20
|
+
(0, index_js_9.register)(server);
|
|
21
|
+
(0, index_js_8.register)(server);
|
|
22
|
+
(0, index_js_6.register)(server);
|
|
23
|
+
(0, index_js_2.register)(server);
|
|
24
|
+
(0, index_js_3.register)(server);
|
|
25
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.description = void 0;
|
|
4
|
+
exports.handler = handler;
|
|
5
|
+
const mail_js_1 = require("../../mail.js");
|
|
6
|
+
exports.description = 'List all attachments for a specific email. Returns attachment IDs, names, sizes, and content types. Use download_attachment for one file, or download_attachments to save several (or all) in a single call.';
|
|
7
|
+
async function handler({ messageId }) {
|
|
8
|
+
const attachments = await (0, mail_js_1.listAttachments)(messageId);
|
|
9
|
+
if (attachments.length === 0) {
|
|
10
|
+
return {
|
|
11
|
+
content: [{ type: 'text', text: 'No attachments found.' }],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const text = attachments
|
|
15
|
+
.map((a, i) => [
|
|
16
|
+
`[${i + 1}] ID: ${a.id}`,
|
|
17
|
+
` Name: ${a.name}`,
|
|
18
|
+
` Size: ${(a.size / 1024).toFixed(1)} KB`,
|
|
19
|
+
` Type: ${a.contentType}`,
|
|
20
|
+
` Inline: ${a.isInline}`,
|
|
21
|
+
].join('\n'))
|
|
22
|
+
.join('\n\n');
|
|
23
|
+
return { content: [{ type: 'text', text }] };
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.register = register;
|
|
4
|
+
const wrap_js_1 = require("../wrap.js");
|
|
5
|
+
const definition_js_1 = require("./definition.js");
|
|
6
|
+
const key_js_1 = require("./key.js");
|
|
7
|
+
const schema_js_1 = require("./schema.js");
|
|
8
|
+
function register(server) {
|
|
9
|
+
server.registerTool(key_js_1.KEY, { description: definition_js_1.description, inputSchema: schema_js_1.schema }, (0, wrap_js_1.wrapHandler)(definition_js_1.handler));
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.schema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.schema = zod_1.z.object({
|
|
6
|
+
messageId: zod_1.z
|
|
7
|
+
.string()
|
|
8
|
+
.describe('The email message ID (from list_emails or search_emails)'),
|
|
9
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.description = void 0;
|
|
4
|
+
exports.handler = handler;
|
|
5
|
+
const mail_js_1 = require("../../mail.js");
|
|
6
|
+
exports.description = 'List emails from an Outlook mailbox folder. Supports filtering by read status, sender, date range, and more using OData filter syntax. Use skip to page through results.';
|
|
7
|
+
async function handler({ folder, top, skip, filter, orderby }) {
|
|
8
|
+
const emails = await (0, mail_js_1.listEmails)({ folder, top, skip, filter, orderby });
|
|
9
|
+
const text = emails
|
|
10
|
+
.map((m, i) => {
|
|
11
|
+
const from = m.from?.emailAddress;
|
|
12
|
+
return [
|
|
13
|
+
`[${(skip ?? 0) + i + 1}] ID: ${m.id}`,
|
|
14
|
+
` Subject: ${m.subject ?? '(no subject)'}`,
|
|
15
|
+
` From: ${from?.name ?? ''} <${from?.address ?? ''}>`,
|
|
16
|
+
` Date: ${m.receivedDateTime ?? ''}`,
|
|
17
|
+
` Read: ${m.isRead} | Attachments: ${m.hasAttachments ?? false}`,
|
|
18
|
+
` Preview: ${(m.bodyPreview ?? '').slice(0, 150)}`,
|
|
19
|
+
].join('\n');
|
|
20
|
+
})
|
|
21
|
+
.join('\n\n');
|
|
22
|
+
const footer = emails.length === top
|
|
23
|
+
? `\n\n(Showing ${emails.length} results — more may exist. Use skip=${(skip ?? 0) + top} for the next page.)`
|
|
24
|
+
: '';
|
|
25
|
+
return {
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: 'text',
|
|
29
|
+
text: text ? text + footer : 'No emails found.',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.register = register;
|
|
4
|
+
const wrap_js_1 = require("../wrap.js");
|
|
5
|
+
const definition_js_1 = require("./definition.js");
|
|
6
|
+
const key_js_1 = require("./key.js");
|
|
7
|
+
const schema_js_1 = require("./schema.js");
|
|
8
|
+
function register(server) {
|
|
9
|
+
server.registerTool(key_js_1.KEY, { description: definition_js_1.description, inputSchema: schema_js_1.schema }, (0, wrap_js_1.wrapHandler)(definition_js_1.handler));
|
|
10
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.schema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.schema = zod_1.z.object({
|
|
6
|
+
folder: zod_1.z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.default('inbox')
|
|
10
|
+
.describe('Folder name or well-known folder: inbox, sentitems, drafts, deleteditems'),
|
|
11
|
+
top: zod_1.z
|
|
12
|
+
.number()
|
|
13
|
+
.int()
|
|
14
|
+
.min(1)
|
|
15
|
+
.max(50)
|
|
16
|
+
.optional()
|
|
17
|
+
.default(10)
|
|
18
|
+
.describe('Number of emails to return (max 50)'),
|
|
19
|
+
skip: zod_1.z
|
|
20
|
+
.number()
|
|
21
|
+
.int()
|
|
22
|
+
.min(0)
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Number of emails to skip, for paging through results (e.g. skip=50 for page 2 with top=50)'),
|
|
25
|
+
filter: zod_1.z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('OData filter expression. Examples: "isRead eq false", "from/emailAddress/address eq \'someone@example.com\'", "receivedDateTime ge 2024-01-01T00:00:00Z"'),
|
|
29
|
+
orderby: zod_1.z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.default('receivedDateTime desc')
|
|
33
|
+
.describe('OData orderBy clause. Default: receivedDateTime desc'),
|
|
34
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.description = void 0;
|
|
4
|
+
exports.handler = handler;
|
|
5
|
+
const mail_js_1 = require("../../mail.js");
|
|
6
|
+
exports.description = 'List all mail folders in the mailbox, including custom folders.';
|
|
7
|
+
async function handler(_input) {
|
|
8
|
+
const folders = await (0, mail_js_1.listFolders)();
|
|
9
|
+
const text = folders
|
|
10
|
+
.map((f) => `${f.displayName} (id: ${f.id}, unread: ${f.unreadItemCount ?? 0}, total: ${f.totalItemCount ?? 0})`)
|
|
11
|
+
.join('\n');
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: 'text', text: text || 'No folders found.' }],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.register = register;
|
|
4
|
+
const wrap_js_1 = require("../wrap.js");
|
|
5
|
+
const definition_js_1 = require("./definition.js");
|
|
6
|
+
const key_js_1 = require("./key.js");
|
|
7
|
+
const schema_js_1 = require("./schema.js");
|
|
8
|
+
function register(server) {
|
|
9
|
+
server.registerTool(key_js_1.KEY, { description: definition_js_1.description, inputSchema: schema_js_1.schema }, (0, wrap_js_1.wrapHandler)(definition_js_1.handler));
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.description = void 0;
|
|
4
|
+
exports.handler = handler;
|
|
5
|
+
const mail_js_1 = require("../../mail.js");
|
|
6
|
+
exports.description = 'Search emails using a keyword query. Searches across subject, body, sender, and recipients.';
|
|
7
|
+
async function handler({ query, top }) {
|
|
8
|
+
const emails = await (0, mail_js_1.searchEmails)(query, top);
|
|
9
|
+
const text = emails
|
|
10
|
+
.map((m, i) => {
|
|
11
|
+
const from = m.from?.emailAddress;
|
|
12
|
+
return [
|
|
13
|
+
`[${i + 1}] ID: ${m.id}`,
|
|
14
|
+
` Subject: ${m.subject ?? '(no subject)'}`,
|
|
15
|
+
` From: ${from?.name ?? ''} <${from?.address ?? ''}>`,
|
|
16
|
+
` Date: ${m.receivedDateTime ?? ''}`,
|
|
17
|
+
` Preview: ${(m.bodyPreview ?? '').slice(0, 150)}`,
|
|
18
|
+
].join('\n');
|
|
19
|
+
})
|
|
20
|
+
.join('\n\n');
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text', text: text || 'No results found.' }],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.register = register;
|
|
4
|
+
const wrap_js_1 = require("../wrap.js");
|
|
5
|
+
const definition_js_1 = require("./definition.js");
|
|
6
|
+
const key_js_1 = require("./key.js");
|
|
7
|
+
const schema_js_1 = require("./schema.js");
|
|
8
|
+
function register(server) {
|
|
9
|
+
server.registerTool(key_js_1.KEY, { description: definition_js_1.description, inputSchema: schema_js_1.schema }, (0, wrap_js_1.wrapHandler)(definition_js_1.handler));
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.schema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.schema = zod_1.z.object({
|
|
6
|
+
query: zod_1.z
|
|
7
|
+
.string()
|
|
8
|
+
.describe("Search terms, e.g. 'invoice from acme', 'meeting next week'"),
|
|
9
|
+
top: zod_1.z
|
|
10
|
+
.number()
|
|
11
|
+
.int()
|
|
12
|
+
.min(1)
|
|
13
|
+
.max(25)
|
|
14
|
+
.optional()
|
|
15
|
+
.default(10)
|
|
16
|
+
.describe('Number of results to return (max 25)'),
|
|
17
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.description = void 0;
|
|
4
|
+
exports.handler = handler;
|
|
5
|
+
const auth_js_1 = require("../../auth.js");
|
|
6
|
+
exports.description = 'Sign out of the Microsoft account: removes the cached session from this machine and cancels any pending sign-in. After this, the authenticate tool must be run again before other tools work. Note: this clears the local token cache but does not revoke app consent in the Microsoft account.';
|
|
7
|
+
async function handler(_input) {
|
|
8
|
+
const removed = await (0, auth_js_1.clearAuth)();
|
|
9
|
+
const text = removed.length > 0
|
|
10
|
+
? `Signed out: ${removed.join(', ')}. Run the authenticate tool to sign in again.`
|
|
11
|
+
: 'No cached session found — already signed out.';
|
|
12
|
+
return { content: [{ type: 'text', text }] };
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.register = register;
|
|
4
|
+
const wrap_js_1 = require("../wrap.js");
|
|
5
|
+
const definition_js_1 = require("./definition.js");
|
|
6
|
+
const key_js_1 = require("./key.js");
|
|
7
|
+
const schema_js_1 = require("./schema.js");
|
|
8
|
+
function register(server) {
|
|
9
|
+
server.registerTool(key_js_1.KEY, { description: definition_js_1.description, inputSchema: schema_js_1.schema }, (0, wrap_js_1.wrapHandler)(definition_js_1.handler));
|
|
10
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapHandler = wrapHandler;
|
|
4
|
+
const auth_js_1 = require("../auth.js");
|
|
5
|
+
/**
|
|
6
|
+
* Wraps a tool handler so Graph/network errors come back as readable tool
|
|
7
|
+
* output instead of a raw stack trace.
|
|
8
|
+
*/
|
|
9
|
+
function wrapHandler(fn) {
|
|
10
|
+
return async (input) => {
|
|
11
|
+
try {
|
|
12
|
+
return await fn(input);
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
return {
|
|
16
|
+
content: [{ type: 'text', text: friendlyError(err) }],
|
|
17
|
+
isError: true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function friendlyError(err) {
|
|
23
|
+
if (err instanceof auth_js_1.AuthRequiredError)
|
|
24
|
+
return err.message;
|
|
25
|
+
const e = err;
|
|
26
|
+
// statusCode -1 = client-side failure: the Graph middleware wraps errors
|
|
27
|
+
// thrown by the auth provider (e.g. AuthRequiredError), losing the class
|
|
28
|
+
// but keeping the message — pass it through untouched.
|
|
29
|
+
if (e?.statusCode === -1 && e?.message)
|
|
30
|
+
return e.message;
|
|
31
|
+
switch (e?.statusCode) {
|
|
32
|
+
case 400:
|
|
33
|
+
return `Bad request — likely invalid OData filter/orderby syntax. Details: ${e.message ?? ''}`;
|
|
34
|
+
case 401:
|
|
35
|
+
return 'Authentication failed or token expired. Restart the server to re-authenticate.';
|
|
36
|
+
case 403:
|
|
37
|
+
return 'Permission denied. The app registration may be missing the Mail.Read scope.';
|
|
38
|
+
case 404:
|
|
39
|
+
return 'Not found. The message or attachment ID may be stale — re-run list_emails or list_attachments to get fresh IDs.';
|
|
40
|
+
case 429:
|
|
41
|
+
return 'Microsoft Graph throttled the request (429). Wait a moment and retry.';
|
|
42
|
+
default:
|
|
43
|
+
return `Request failed${e?.statusCode ? ` (HTTP ${e.statusCode})` : ''}: ${e?.message ?? String(err)}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "outlook-reader-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for reading Outlook mail via Microsoft Graph: list, search, and fetch emails (batched), and download attachments.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"outlook-reader-mcp": "dist/mcp-server.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"mcp": "tsx src/mcp-server.ts",
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"prepublishOnly": "npm run format:check && npm run build",
|
|
15
|
+
"format": "prettier --write .",
|
|
16
|
+
"format:check": "prettier --check ."
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"mcp",
|
|
20
|
+
"model-context-protocol",
|
|
21
|
+
"outlook",
|
|
22
|
+
"microsoft-graph",
|
|
23
|
+
"email"
|
|
24
|
+
],
|
|
25
|
+
"author": "Jesús Imitola",
|
|
26
|
+
"license": "GPL-3.0-only",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/jgimitola/outlook-reader-mcp.git"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/jgimitola/outlook-reader-mcp/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/jgimitola/outlook-reader-mcp#readme",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"type": "commonjs",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@azure/msal-node": "^5.2.3",
|
|
41
|
+
"@azure/msal-node-extensions": "^5.2.4",
|
|
42
|
+
"@microsoft/microsoft-graph-client": "^3.0.7",
|
|
43
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
44
|
+
"dotenv": "^17.4.2",
|
|
45
|
+
"zod": "^4.4.3"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@microsoft/microsoft-graph-types": "^2.43.1",
|
|
49
|
+
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
|
50
|
+
"@types/node": "^25.9.2",
|
|
51
|
+
"prettier": "^3.8.4",
|
|
52
|
+
"tsx": "^4.22.4",
|
|
53
|
+
"typescript": "^6.0.3"
|
|
54
|
+
}
|
|
55
|
+
}
|