@littlebearapps/outlook-assistant 3.4.1 → 3.5.1
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/.env.example +8 -0
- package/README.md +42 -23
- package/auth/device-code.js +139 -0
- package/auth/index.js +16 -5
- package/auth/tools.js +187 -18
- package/config.js +7 -0
- package/email/export.js +2 -4
- package/email/index.js +43 -0
- package/email/mail-tips.js +211 -0
- package/email/send.js +44 -0
- package/llms-install.md +90 -0
- package/llms.txt +8 -7
- package/package.json +4 -3
- package/utils/graph-api.js +128 -5
package/config.js
CHANGED
|
@@ -54,6 +54,10 @@ module.exports = {
|
|
|
54
54
|
],
|
|
55
55
|
tokenStorePath: path.join(homeDir, '.outlook-assistant-tokens.json'),
|
|
56
56
|
authServerUrl: 'http://localhost:3333',
|
|
57
|
+
deviceCodeEndpoint:
|
|
58
|
+
'https://login.microsoftonline.com/common/oauth2/v2.0/devicecode',
|
|
59
|
+
tokenEndpoint: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
|
|
60
|
+
defaultAuthMethod: process.env.OUTLOOK_AUTH_METHOD || 'device-code',
|
|
57
61
|
},
|
|
58
62
|
|
|
59
63
|
// Microsoft Graph API
|
|
@@ -90,6 +94,9 @@ module.exports = {
|
|
|
90
94
|
// Search defaults (reduced for token efficiency)
|
|
91
95
|
DEFAULT_SEARCH_RESULTS: DEFAULT_LIMITS.searchEmails,
|
|
92
96
|
|
|
97
|
+
// Immutable IDs (opt-in: IDs persist through folder moves)
|
|
98
|
+
USE_IMMUTABLE_IDS: process.env.OUTLOOK_IMMUTABLE_IDS === 'true',
|
|
99
|
+
|
|
93
100
|
// Timezone
|
|
94
101
|
DEFAULT_TIMEZONE: 'Australia/Melbourne', // Updated for Nathan's timezone
|
|
95
102
|
};
|
package/email/export.js
CHANGED
|
@@ -281,10 +281,8 @@ async function handleBatchExportEmails(args) {
|
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
const csvContent = formatEmailsAsCSV(emails);
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
`batch_export_${new Date().toISOString().slice(0, 10)}.csv`
|
|
287
|
-
);
|
|
284
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
285
|
+
const csvPath = path.join(outputDir, `batch_export_${timestamp}.csv`);
|
|
288
286
|
fs.writeFileSync(csvPath, csvContent, 'utf8');
|
|
289
287
|
const totalBytes = Buffer.byteLength(csvContent, 'utf8');
|
|
290
288
|
|
package/email/index.js
CHANGED
|
@@ -22,6 +22,7 @@ const {
|
|
|
22
22
|
handleGetConversation,
|
|
23
23
|
handleExportConversation,
|
|
24
24
|
} = require('./conversations');
|
|
25
|
+
const { handleGetMailTips } = require('./mail-tips');
|
|
25
26
|
|
|
26
27
|
// Import flag handlers from advanced module
|
|
27
28
|
const { handleSetMessageFlag, handleClearMessageFlag } = require('../advanced');
|
|
@@ -278,6 +279,11 @@ const emailTools = [
|
|
|
278
279
|
description:
|
|
279
280
|
'Preview email without sending (default: false). Returns composed email for review.',
|
|
280
281
|
},
|
|
282
|
+
checkRecipients: {
|
|
283
|
+
type: 'boolean',
|
|
284
|
+
description:
|
|
285
|
+
'Check recipients for out-of-office, mailbox full, delivery restrictions before sending (default: false). Combine with dryRun=true for pre-send review.',
|
|
286
|
+
},
|
|
281
287
|
},
|
|
282
288
|
required: ['to', 'subject', 'body'],
|
|
283
289
|
},
|
|
@@ -513,6 +519,42 @@ const emailTools = [
|
|
|
513
519
|
}
|
|
514
520
|
},
|
|
515
521
|
},
|
|
522
|
+
{
|
|
523
|
+
name: 'get-mail-tips',
|
|
524
|
+
description:
|
|
525
|
+
'Check recipients before sending: out-of-office status, mailbox full, external recipients, delivery restrictions, moderation, group member counts, and max message size. No competitor offers this.',
|
|
526
|
+
annotations: {
|
|
527
|
+
title: 'Mail Tips',
|
|
528
|
+
readOnlyHint: true,
|
|
529
|
+
openWorldHint: false,
|
|
530
|
+
},
|
|
531
|
+
inputSchema: {
|
|
532
|
+
type: 'object',
|
|
533
|
+
properties: {
|
|
534
|
+
recipients: {
|
|
535
|
+
oneOf: [
|
|
536
|
+
{
|
|
537
|
+
type: 'array',
|
|
538
|
+
items: { type: 'string' },
|
|
539
|
+
description: 'Array of email addresses to check',
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
type: 'string',
|
|
543
|
+
description: 'Comma-separated email addresses to check',
|
|
544
|
+
},
|
|
545
|
+
],
|
|
546
|
+
description: 'Email addresses to check for mail tips',
|
|
547
|
+
},
|
|
548
|
+
tipTypes: {
|
|
549
|
+
type: 'string',
|
|
550
|
+
description:
|
|
551
|
+
'Comma-separated tip types to request (default: all). Options: automaticReplies, mailboxFullStatus, customMailTip, externalMemberCount, totalMemberCount, maxMessageSize, deliveryRestriction, moderationStatus, recipientScope, recipientSuggestions',
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
required: ['recipients'],
|
|
555
|
+
},
|
|
556
|
+
handler: handleGetMailTips,
|
|
557
|
+
},
|
|
516
558
|
];
|
|
517
559
|
|
|
518
560
|
module.exports = {
|
|
@@ -534,4 +576,5 @@ module.exports = {
|
|
|
534
576
|
handleListConversations,
|
|
535
577
|
handleGetConversation,
|
|
536
578
|
handleExportConversation,
|
|
579
|
+
handleGetMailTips,
|
|
537
580
|
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mail tips functionality — pre-send validation via Graph API
|
|
3
|
+
*
|
|
4
|
+
* Checks recipients for out-of-office, mailbox full, external,
|
|
5
|
+
* delivery restrictions, and more before sending.
|
|
6
|
+
*/
|
|
7
|
+
const { callGraphAPI } = require('../utils/graph-api');
|
|
8
|
+
const { ensureAuthenticated } = require('../auth');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* All available mail tip types from Microsoft Graph API
|
|
12
|
+
*/
|
|
13
|
+
const MAIL_TIP_TYPES = [
|
|
14
|
+
'automaticReplies',
|
|
15
|
+
'mailboxFullStatus',
|
|
16
|
+
'customMailTip',
|
|
17
|
+
'externalMemberCount',
|
|
18
|
+
'totalMemberCount',
|
|
19
|
+
'maxMessageSize',
|
|
20
|
+
'deliveryRestriction',
|
|
21
|
+
'moderationStatus',
|
|
22
|
+
'recipientScope',
|
|
23
|
+
'recipientSuggestions',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Format mail tips into readable markdown
|
|
28
|
+
* @param {Array} mailTips - Array of mail tip objects from Graph API
|
|
29
|
+
* @returns {string} - Formatted markdown output
|
|
30
|
+
*/
|
|
31
|
+
function formatMailTips(mailTips) {
|
|
32
|
+
const lines = [];
|
|
33
|
+
let warningCount = 0;
|
|
34
|
+
|
|
35
|
+
for (const tip of mailTips) {
|
|
36
|
+
const email = tip.emailAddress?.address || 'Unknown';
|
|
37
|
+
const tipLines = [];
|
|
38
|
+
const warnings = [];
|
|
39
|
+
|
|
40
|
+
// Out-of-office / automatic replies
|
|
41
|
+
if (
|
|
42
|
+
tip.automaticReplies?.message &&
|
|
43
|
+
tip.automaticReplies.message.trim() !== ''
|
|
44
|
+
) {
|
|
45
|
+
warnings.push('Out of Office');
|
|
46
|
+
const reply = tip.automaticReplies;
|
|
47
|
+
tipLines.push(
|
|
48
|
+
` **Out of Office**: ${reply.message.replace(/\n/g, ' ').substring(0, 200)}`
|
|
49
|
+
);
|
|
50
|
+
if (reply.scheduledStartTime || reply.scheduledEndTime) {
|
|
51
|
+
const start = reply.scheduledStartTime?.dateTime || '';
|
|
52
|
+
const end = reply.scheduledEndTime?.dateTime || '';
|
|
53
|
+
if (start || end) {
|
|
54
|
+
tipLines.push(` *Schedule*: ${start} → ${end}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Mailbox full
|
|
60
|
+
if (tip.mailboxFullStatus) {
|
|
61
|
+
warnings.push('Mailbox Full');
|
|
62
|
+
tipLines.push(
|
|
63
|
+
` **Mailbox Full**: Recipient's mailbox is full — delivery may fail`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Custom mail tip (admin-configured)
|
|
68
|
+
if (tip.customMailTip) {
|
|
69
|
+
warnings.push('Custom Tip');
|
|
70
|
+
tipLines.push(` **Notice**: ${tip.customMailTip}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Delivery restriction
|
|
74
|
+
if (tip.deliveryRestriction) {
|
|
75
|
+
const restriction = tip.deliveryRestriction;
|
|
76
|
+
if (restriction.isDeliveryRestricted) {
|
|
77
|
+
warnings.push('Delivery Restricted');
|
|
78
|
+
tipLines.push(
|
|
79
|
+
` **Delivery Restricted**: ${restriction.message || 'Cannot deliver to this recipient'}`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Moderation status
|
|
85
|
+
if (tip.moderationStatus && tip.moderationStatus !== 'notModerated') {
|
|
86
|
+
warnings.push('Moderated');
|
|
87
|
+
tipLines.push(
|
|
88
|
+
` **Moderated**: Messages to this recipient require approval`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Recipient scope (external)
|
|
93
|
+
if (tip.recipientScope === 'external') {
|
|
94
|
+
tipLines.push(` **External**: Recipient is outside your organisation`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Max message size
|
|
98
|
+
if (tip.maxMessageSize && tip.maxMessageSize > 0) {
|
|
99
|
+
const sizeMB = (tip.maxMessageSize / (1024 * 1024)).toFixed(1);
|
|
100
|
+
tipLines.push(` *Max message size*: ${sizeMB} MB`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Group member counts
|
|
104
|
+
if (tip.totalMemberCount > 0) {
|
|
105
|
+
tipLines.push(
|
|
106
|
+
` *Group members*: ${tip.totalMemberCount} total (${tip.externalMemberCount || 0} external)`
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Build section for this recipient
|
|
111
|
+
const statusIcon = warnings.length > 0 ? '⚠' : '✓';
|
|
112
|
+
lines.push(`### ${statusIcon} ${email}`);
|
|
113
|
+
|
|
114
|
+
if (warnings.length > 0) {
|
|
115
|
+
lines.push(`**Warnings**: ${warnings.join(', ')}`);
|
|
116
|
+
warningCount += warnings.length;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (tipLines.length > 0) {
|
|
120
|
+
lines.push(tipLines.join('\n'));
|
|
121
|
+
} else {
|
|
122
|
+
lines.push(' No issues detected');
|
|
123
|
+
}
|
|
124
|
+
lines.push('');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return { formatted: lines.join('\n'), warningCount };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get mail tips for specified recipients
|
|
132
|
+
* @param {object} args - Tool arguments
|
|
133
|
+
* @returns {object} - MCP response
|
|
134
|
+
*/
|
|
135
|
+
async function handleGetMailTips(args) {
|
|
136
|
+
const { recipients, tipTypes } = args;
|
|
137
|
+
|
|
138
|
+
if (!recipients || recipients.length === 0) {
|
|
139
|
+
return {
|
|
140
|
+
content: [
|
|
141
|
+
{
|
|
142
|
+
type: 'text',
|
|
143
|
+
text: 'At least one recipient email address is required.',
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const accessToken = await ensureAuthenticated();
|
|
151
|
+
|
|
152
|
+
const requestBody = {
|
|
153
|
+
EmailAddresses: Array.isArray(recipients)
|
|
154
|
+
? recipients
|
|
155
|
+
: recipients.split(',').map((e) => e.trim()),
|
|
156
|
+
MailTipsOptions: tipTypes || MAIL_TIP_TYPES.join(','),
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const response = await callGraphAPI(
|
|
160
|
+
accessToken,
|
|
161
|
+
'POST',
|
|
162
|
+
'me/getMailTips',
|
|
163
|
+
requestBody
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const mailTips = response.value || [];
|
|
167
|
+
|
|
168
|
+
if (mailTips.length === 0) {
|
|
169
|
+
return {
|
|
170
|
+
content: [
|
|
171
|
+
{
|
|
172
|
+
type: 'text',
|
|
173
|
+
text: 'No mail tips returned for the specified recipients.',
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const { formatted, warningCount } = formatMailTips(mailTips);
|
|
180
|
+
|
|
181
|
+
let header = `# Mail Tips\n\n`;
|
|
182
|
+
header += `**Recipients checked**: ${mailTips.length}\n`;
|
|
183
|
+
header += `**Warnings**: ${warningCount}\n\n`;
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
content: [{ type: 'text', text: header + formatted }],
|
|
187
|
+
_meta: {
|
|
188
|
+
recipientCount: mailTips.length,
|
|
189
|
+
warningCount,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
} catch (error) {
|
|
193
|
+
if (error.message === 'Authentication required') {
|
|
194
|
+
return {
|
|
195
|
+
content: [
|
|
196
|
+
{
|
|
197
|
+
type: 'text',
|
|
198
|
+
text: "Authentication required. Please use the 'auth' tool with action=authenticate first.",
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
content: [
|
|
205
|
+
{ type: 'text', text: `Error getting mail tips: ${error.message}` },
|
|
206
|
+
],
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = { handleGetMailTips, formatMailTips, MAIL_TIP_TYPES };
|
package/email/send.js
CHANGED
|
@@ -9,6 +9,7 @@ const {
|
|
|
9
9
|
checkRecipientAllowlist,
|
|
10
10
|
formatDryRunPreview,
|
|
11
11
|
} = require('../utils/safety');
|
|
12
|
+
const { handleGetMailTips } = require('./mail-tips');
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Send email handler
|
|
@@ -25,6 +26,7 @@ async function handleSendEmail(args) {
|
|
|
25
26
|
importance = 'normal',
|
|
26
27
|
saveToSentItems = true,
|
|
27
28
|
dryRun = false,
|
|
29
|
+
checkRecipients = false,
|
|
28
30
|
} = args;
|
|
29
31
|
|
|
30
32
|
// Validate required parameters
|
|
@@ -99,6 +101,48 @@ async function handleSendEmail(args) {
|
|
|
99
101
|
const allowlistError = checkRecipientAllowlist(allRecipients);
|
|
100
102
|
if (allowlistError) return allowlistError;
|
|
101
103
|
|
|
104
|
+
// Pre-send mail tips check
|
|
105
|
+
if (checkRecipients) {
|
|
106
|
+
const allAddresses = allRecipients.map((r) => r.emailAddress.address);
|
|
107
|
+
const tipsResult = await handleGetMailTips({
|
|
108
|
+
recipients: allAddresses,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// If there are warnings, prepend them to the response
|
|
112
|
+
if (tipsResult._meta?.warningCount > 0 && dryRun) {
|
|
113
|
+
// In dry-run mode, include mail tips in the preview
|
|
114
|
+
const tipsText = tipsResult.content[0]?.text || '';
|
|
115
|
+
const preview = formatDryRunPreview({
|
|
116
|
+
message: {
|
|
117
|
+
subject,
|
|
118
|
+
body: {
|
|
119
|
+
contentType:
|
|
120
|
+
/<(html|div|p|h[1-6]|br|table|ul|ol|li|span|a\s|img|strong|em|b|i)\b/i.test(
|
|
121
|
+
body
|
|
122
|
+
)
|
|
123
|
+
? 'html'
|
|
124
|
+
: 'text',
|
|
125
|
+
content: body,
|
|
126
|
+
},
|
|
127
|
+
toRecipients,
|
|
128
|
+
ccRecipients: ccRecipients.length > 0 ? ccRecipients : undefined,
|
|
129
|
+
bccRecipients: bccRecipients.length > 0 ? bccRecipients : undefined,
|
|
130
|
+
importance,
|
|
131
|
+
},
|
|
132
|
+
saveToSentItems,
|
|
133
|
+
});
|
|
134
|
+
return {
|
|
135
|
+
content: [
|
|
136
|
+
{
|
|
137
|
+
type: 'text',
|
|
138
|
+
text: tipsText + '\n\n---\n\n' + preview.content[0].text,
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
_meta: { mailTips: tipsResult._meta },
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
102
146
|
// Prepare email object
|
|
103
147
|
const emailObject = {
|
|
104
148
|
message: {
|
package/llms-install.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Installing Outlook Assistant
|
|
2
|
+
|
|
3
|
+
## Quick Install (npx — no global install needed)
|
|
4
|
+
|
|
5
|
+
Add to your MCP client configuration:
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"mcpServers": {
|
|
10
|
+
"outlook": {
|
|
11
|
+
"command": "npx",
|
|
12
|
+
"args": ["-y", "@littlebearapps/outlook-assistant"],
|
|
13
|
+
"env": {
|
|
14
|
+
"OUTLOOK_CLIENT_ID": "<user-must-provide>",
|
|
15
|
+
"OUTLOOK_CLIENT_SECRET": "<user-must-provide>"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Prerequisites
|
|
23
|
+
|
|
24
|
+
1. **Node.js 18+** must be installed
|
|
25
|
+
2. **Azure app registration** is required for authentication (free tier works)
|
|
26
|
+
|
|
27
|
+
## Getting the Client ID and Secret
|
|
28
|
+
|
|
29
|
+
Users must create an Azure app registration to get credentials:
|
|
30
|
+
|
|
31
|
+
1. Go to https://portal.azure.com/ and sign in
|
|
32
|
+
2. Search for "App registrations" → click "New registration"
|
|
33
|
+
3. Name: "Outlook Assistant" (or any name)
|
|
34
|
+
4. Supported account types: "Accounts in any organizational directory and personal Microsoft accounts"
|
|
35
|
+
5. Redirect URI: platform "Web", URI `http://localhost:3333/auth/callback`
|
|
36
|
+
6. Click "Register"
|
|
37
|
+
7. Copy the **Application (client) ID** → this is `OUTLOOK_CLIENT_ID`
|
|
38
|
+
|
|
39
|
+
### Create a client secret:
|
|
40
|
+
1. Go to "Certificates & secrets" → "New client secret"
|
|
41
|
+
2. Add a description, select expiration, click "Add"
|
|
42
|
+
3. **Copy the Value immediately** (not the Secret ID) → this is `OUTLOOK_CLIENT_SECRET`
|
|
43
|
+
|
|
44
|
+
### Add API permissions:
|
|
45
|
+
1. Go to "API permissions" → "Add a permission" → "Microsoft Graph" → "Delegated permissions"
|
|
46
|
+
2. Add: `offline_access`, `User.Read`, `Mail.Read`, `Mail.ReadWrite`, `Mail.Send`, `Calendars.Read`, `Calendars.ReadWrite`, `Contacts.Read`, `Contacts.ReadWrite`, `People.Read`, `MailboxSettings.ReadWrite`
|
|
47
|
+
3. Click "Add permissions"
|
|
48
|
+
|
|
49
|
+
## First-Time Authentication
|
|
50
|
+
|
|
51
|
+
After configuring the MCP server:
|
|
52
|
+
|
|
53
|
+
1. Start the auth server: `npx @littlebearapps/outlook-assistant-auth` (or run `npm run auth-server` from source)
|
|
54
|
+
2. Use the `auth` tool with `action=authenticate` to get an OAuth URL
|
|
55
|
+
3. Open the URL in a browser, sign in with your Microsoft account
|
|
56
|
+
4. Grant permissions — tokens are saved to `~/.outlook-assistant-tokens.json` and refresh automatically
|
|
57
|
+
|
|
58
|
+
**Note**: The auth server needs `OUTLOOK_CLIENT_ID` and `OUTLOOK_CLIENT_SECRET` as environment variables. If running it separately from the MCP server, export them in your shell or create a `.env` file.
|
|
59
|
+
|
|
60
|
+
## Configuration Files by Client
|
|
61
|
+
|
|
62
|
+
### Claude Desktop
|
|
63
|
+
File: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows)
|
|
64
|
+
|
|
65
|
+
### Claude Code
|
|
66
|
+
```bash
|
|
67
|
+
claude mcp add outlook -- npx @littlebearapps/outlook-assistant
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Cursor
|
|
71
|
+
File: `.cursor/mcp.json` in your project root
|
|
72
|
+
|
|
73
|
+
### Windsurf
|
|
74
|
+
File: `~/.codeium/windsurf/mcp_config.json`
|
|
75
|
+
|
|
76
|
+
## Verify Installation
|
|
77
|
+
|
|
78
|
+
After authentication, test with:
|
|
79
|
+
- `auth` tool with `action=status` — should show "authenticated"
|
|
80
|
+
- `search-emails` with no parameters — should list recent inbox emails
|
|
81
|
+
|
|
82
|
+
## Troubleshooting
|
|
83
|
+
|
|
84
|
+
| Problem | Solution |
|
|
85
|
+
|---------|----------|
|
|
86
|
+
| "Invalid client secret" (AADSTS7000215) | Use the secret **Value**, not the Secret ID |
|
|
87
|
+
| Auth URL doesn't work | Start the auth server first |
|
|
88
|
+
| "EADDRINUSE :3333" | Run `npx kill-port 3333` then restart auth server |
|
|
89
|
+
| Empty API responses | Run `auth` tool with `action=status` to check token |
|
|
90
|
+
| Search returns no results (personal account) | Use `from`, `subject`, `to` filters instead of `query` |
|
package/llms.txt
CHANGED
|
@@ -11,12 +11,12 @@ Built by [Little Bear Apps](https://littlebearapps.com).
|
|
|
11
11
|
- **License**: MIT
|
|
12
12
|
- **Node.js**: >= 18.0.0
|
|
13
13
|
- **Authentication**: OAuth 2.0 with Microsoft Graph API (requires Azure app registration)
|
|
14
|
-
- **Tools**:
|
|
14
|
+
- **Tools**: 21 tools across 9 modules (reduced from 55 for optimal AI performance)
|
|
15
15
|
|
|
16
16
|
## Why Outlook Assistant?
|
|
17
17
|
|
|
18
18
|
- Read, search, send, and export emails directly from Claude instead of switching apps
|
|
19
|
-
-
|
|
19
|
+
- 7 email tools covering search, conversations, attachments, bulk export, and pre-send mail tips
|
|
20
20
|
- Manage calendar events, contacts, rules, categories, and mailbox settings in one place
|
|
21
21
|
- Export to multiple formats: MIME/EML, MBOX, Markdown, JSON, HTML
|
|
22
22
|
|
|
@@ -26,13 +26,14 @@ Built by [Little Bear Apps](https://littlebearapps.com).
|
|
|
26
26
|
- **Email forensics**: Built-in header analysis for DKIM, SPF, DMARC authentication, delivery chains, and spam scores — useful for phishing investigation and compliance
|
|
27
27
|
- **Delta sync**: Incremental inbox monitoring — returns only new, modified, and deleted emails since last check, with tokens for continuous polling
|
|
28
28
|
- **Batch operations**: Flag, move, export, or categorise multiple emails in a single tool call; search-driven export for batch archiving without collecting IDs
|
|
29
|
+
- **Pre-send intelligence**: Check recipients for out-of-office, mailbox full, delivery restrictions, and moderation before sending — no other Outlook MCP server offers this
|
|
29
30
|
- **Compound automation**: Rules + categories + folders + Focused Inbox for complete inbox management in one conversation
|
|
30
31
|
|
|
31
32
|
## Safety & Token Efficiency
|
|
32
33
|
|
|
33
|
-
- **MCP safety annotations** on all
|
|
34
|
-
- **Send-email protections**: dry-run preview, session rate limiting, recipient allowlist
|
|
35
|
-
- **Token-optimised**:
|
|
34
|
+
- **MCP safety annotations** on all 21 tools — AI clients auto-approve reads and prompt for destructive operations
|
|
35
|
+
- **Send-email protections**: pre-send mail tips, dry-run preview, session rate limiting, recipient allowlist
|
|
36
|
+
- **Token-optimised**: 21 tools instead of 55 saves ~11,000 tokens per turn (~64% reduction), improving AI accuracy and context efficiency
|
|
36
37
|
- These safeguards reduce risk but are not foolproof — always review actions before approving
|
|
37
38
|
|
|
38
39
|
## Quick Start
|
|
@@ -57,7 +58,7 @@ Requires an Azure app registration with Microsoft Graph delegated permissions. S
|
|
|
57
58
|
## Tool Categories
|
|
58
59
|
|
|
59
60
|
- **Authentication (1 tool)**: `auth` — OAuth flow, status, about
|
|
60
|
-
- **Email (
|
|
61
|
+
- **Email (7 tools)**: `search-emails`, `read-email`, `send-email`, `update-email`, `attachments`, `export`, `get-mail-tips`
|
|
61
62
|
- **Calendar (3 tools)**: `list-events`, `create-event`, `manage-event`
|
|
62
63
|
- **Contacts (2 tools)**: `manage-contact`, `search-people`
|
|
63
64
|
- **Folders (1 tool)**: `folders` — list, create, move, stats
|
|
@@ -69,7 +70,7 @@ Requires an Azure app registration with Microsoft Graph delegated permissions. S
|
|
|
69
70
|
## Documentation
|
|
70
71
|
|
|
71
72
|
- [README](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/README.md): Full documentation including setup, Azure configuration, and usage
|
|
72
|
-
- [Tools Reference](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/quickrefs/tools-reference.md): All
|
|
73
|
+
- [Tools Reference](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/docs/quickrefs/tools-reference.md): All 21 tools with parameters and safety annotations
|
|
73
74
|
- [CLAUDE.md](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CLAUDE.md): Quick reference for development
|
|
74
75
|
- [CONTRIBUTING](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CONTRIBUTING.md): Contribution guidelines
|
|
75
76
|
- [CHANGELOG](https://raw.githubusercontent.com/littlebearapps/outlook-assistant/main/CHANGELOG.md): Version history
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@littlebearapps/outlook-assistant",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.1",
|
|
4
4
|
"mcpName": "io.github.littlebearapps/outlook-assistant",
|
|
5
|
-
"description": "Outlook Assistant — MCP server with
|
|
5
|
+
"description": "Outlook Assistant — MCP server with 21 tools for email, calendar, contacts, and settings via Microsoft Graph API",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"outlook-assistant": "./index.js"
|
|
@@ -70,7 +70,8 @@
|
|
|
70
70
|
".env.example",
|
|
71
71
|
"README.md",
|
|
72
72
|
"LICENSE",
|
|
73
|
-
"llms.txt"
|
|
73
|
+
"llms.txt",
|
|
74
|
+
"llms-install.md"
|
|
74
75
|
],
|
|
75
76
|
"dependencies": {
|
|
76
77
|
"@modelcontextprotocol/sdk": "^1.27.1",
|