@sempervirens-labs/apple-mail-mcp 1.4.1 → 1.5.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 +51 -0
- package/package.json +1 -1
- package/src/applescript/mail.ts +102 -0
- package/src/index.ts +22 -0
- package/src/tools.ts +33 -0
package/README.md
CHANGED
|
@@ -181,6 +181,57 @@ Get recent emails from a mailbox.
|
|
|
181
181
|
}
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
+
### `mail_get_emails_by_ids`
|
|
185
|
+
|
|
186
|
+
Get specific emails by their IDs. Useful for retrieving full details of specific emails after browsing with `mail_get_emails` (with `includeContent: false`).
|
|
187
|
+
|
|
188
|
+
| Parameter | Type | Required | Default | Description |
|
|
189
|
+
|-----------|------|----------|---------|-------------|
|
|
190
|
+
| `ids` | number[] | **Yes** | - | Array of email IDs to retrieve |
|
|
191
|
+
| `account` | string | No | - | Account name (helps optimize search) |
|
|
192
|
+
| `mailbox` | string | No | "INBOX" | Mailbox name (helps optimize search) |
|
|
193
|
+
| `includeContent` | boolean | No | true | Include email body |
|
|
194
|
+
|
|
195
|
+
**Example usage:**
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"ids": [12345, 67890],
|
|
199
|
+
"includeContent": true
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Example response:**
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"emails": [
|
|
207
|
+
{
|
|
208
|
+
"id": 12345,
|
|
209
|
+
"subject": "Meeting tomorrow",
|
|
210
|
+
"sender": "John Doe <john@example.com>",
|
|
211
|
+
"to": ["you@example.com"],
|
|
212
|
+
"cc": [],
|
|
213
|
+
"bcc": [],
|
|
214
|
+
"dateSent": "Monday, 10. January 2025 at 09:30:00",
|
|
215
|
+
"isRead": false,
|
|
216
|
+
"content": "Let's meet at 2pm to discuss the project..."
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"id": 67890,
|
|
220
|
+
"subject": "Project update",
|
|
221
|
+
"sender": "Jane Smith <jane@example.com>",
|
|
222
|
+
"to": ["you@example.com"],
|
|
223
|
+
"cc": [],
|
|
224
|
+
"bcc": [],
|
|
225
|
+
"dateSent": "Tuesday, 11. January 2025 at 14:15:00",
|
|
226
|
+
"isRead": true,
|
|
227
|
+
"content": "The project is progressing well..."
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
"count": 2,
|
|
231
|
+
"requestedIds": [12345, 67890]
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
184
235
|
### `mail_search`
|
|
185
236
|
|
|
186
237
|
Search emails by subject, sender, or content.
|
package/package.json
CHANGED
package/src/applescript/mail.ts
CHANGED
|
@@ -207,6 +207,108 @@ end tell
|
|
|
207
207
|
return emails;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
/**
|
|
211
|
+
* Get specific emails by their IDs
|
|
212
|
+
*/
|
|
213
|
+
export function getEmailsByIds(options: {
|
|
214
|
+
ids: number[];
|
|
215
|
+
account?: string;
|
|
216
|
+
mailbox?: string;
|
|
217
|
+
includeContent?: boolean;
|
|
218
|
+
}): Email[] {
|
|
219
|
+
const { ids, account, mailbox = "INBOX", includeContent = true } = options;
|
|
220
|
+
|
|
221
|
+
if (!ids || ids.length === 0) {
|
|
222
|
+
return [];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const contentPart = includeContent
|
|
226
|
+
? `set msgContent to content of msg`
|
|
227
|
+
: `set msgContent to ""`;
|
|
228
|
+
|
|
229
|
+
const accountPart = account
|
|
230
|
+
? `mailbox "${mailbox}" of account "${account}"`
|
|
231
|
+
: `mailbox "${mailbox}"`;
|
|
232
|
+
|
|
233
|
+
// Build the ID list for AppleScript
|
|
234
|
+
const idList = ids.join(", ");
|
|
235
|
+
|
|
236
|
+
const script = `
|
|
237
|
+
tell application "Mail"
|
|
238
|
+
set results to ""
|
|
239
|
+
set targetIds to {${idList}}
|
|
240
|
+
try
|
|
241
|
+
set theMailbox to ${accountPart}
|
|
242
|
+
set allMessages to messages of theMailbox
|
|
243
|
+
|
|
244
|
+
repeat with targetId in targetIds
|
|
245
|
+
repeat with msg in allMessages
|
|
246
|
+
if id of msg is targetId then
|
|
247
|
+
set msgId to id of msg
|
|
248
|
+
set msgSubject to subject of msg
|
|
249
|
+
set msgSender to sender of msg
|
|
250
|
+
set msgDate to date sent of msg
|
|
251
|
+
set msgRead to read status of msg
|
|
252
|
+
${contentPart}
|
|
253
|
+
|
|
254
|
+
-- Get recipients
|
|
255
|
+
set toList to ""
|
|
256
|
+
repeat with r in to recipients of msg
|
|
257
|
+
set toList to toList & address of r & ","
|
|
258
|
+
end repeat
|
|
259
|
+
if toList is not "" then set toList to text 1 thru -2 of toList
|
|
260
|
+
|
|
261
|
+
set ccList to ""
|
|
262
|
+
repeat with r in cc recipients of msg
|
|
263
|
+
set ccList to ccList & address of r & ","
|
|
264
|
+
end repeat
|
|
265
|
+
if ccList is not "" then set ccList to text 1 thru -2 of ccList
|
|
266
|
+
|
|
267
|
+
set bccList to ""
|
|
268
|
+
repeat with r in bcc recipients of msg
|
|
269
|
+
set bccList to bccList & address of r & ","
|
|
270
|
+
end repeat
|
|
271
|
+
if bccList is not "" then set bccList to text 1 thru -2 of bccList
|
|
272
|
+
|
|
273
|
+
set results to results & msgId & "<<>>" & msgSubject & "<<>>" & msgSender & "<<>>" & toList & "<<>>" & ccList & "<<>>" & bccList & "<<>>" & (msgDate as string) & "<<>>" & msgRead & "<<>>" & msgContent & "|||"
|
|
274
|
+
exit repeat -- Found the message, move to next ID
|
|
275
|
+
end if
|
|
276
|
+
end repeat
|
|
277
|
+
end repeat
|
|
278
|
+
on error errMsg
|
|
279
|
+
return "ERROR:" & errMsg
|
|
280
|
+
end try
|
|
281
|
+
return results
|
|
282
|
+
end tell
|
|
283
|
+
`;
|
|
284
|
+
|
|
285
|
+
const result = runAppleScript(script);
|
|
286
|
+
|
|
287
|
+
if (result.startsWith("ERROR:")) {
|
|
288
|
+
throw new Error(result.substring(6));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const emails: Email[] = [];
|
|
292
|
+
const parts = result.split("|||").filter(Boolean);
|
|
293
|
+
|
|
294
|
+
for (const part of parts) {
|
|
295
|
+
const [id, subject, sender, to, cc, bcc, dateSent, isRead, content] = part.split("<<>>");
|
|
296
|
+
emails.push({
|
|
297
|
+
id: parseInt(id) || 0,
|
|
298
|
+
subject: subject || "(No Subject)",
|
|
299
|
+
sender: sender || "(Unknown)",
|
|
300
|
+
to: to ? to.split(",").map(s => s.trim()).filter(Boolean) : [],
|
|
301
|
+
cc: cc ? cc.split(",").map(s => s.trim()).filter(Boolean) : [],
|
|
302
|
+
bcc: bcc ? bcc.split(",").map(s => s.trim()).filter(Boolean) : [],
|
|
303
|
+
dateSent: dateSent || "",
|
|
304
|
+
isRead: isRead === "true",
|
|
305
|
+
content: content || undefined,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return emails;
|
|
310
|
+
}
|
|
311
|
+
|
|
210
312
|
/**
|
|
211
313
|
* Search emails by query
|
|
212
314
|
*/
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
listAccounts,
|
|
13
13
|
listMailboxes,
|
|
14
14
|
getEmails,
|
|
15
|
+
getEmailsByIds,
|
|
15
16
|
searchEmails,
|
|
16
17
|
getUnreadCount,
|
|
17
18
|
sendEmail,
|
|
@@ -90,6 +91,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
90
91
|
};
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
case "mail_get_emails_by_ids": {
|
|
95
|
+
const ids = args?.ids as number[];
|
|
96
|
+
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
|
97
|
+
throw new Error("Required field: ids (must be a non-empty array of email IDs)");
|
|
98
|
+
}
|
|
99
|
+
const emails = getEmailsByIds({
|
|
100
|
+
ids,
|
|
101
|
+
account: args?.account as string | undefined,
|
|
102
|
+
mailbox: (args?.mailbox as string) || "INBOX",
|
|
103
|
+
includeContent: (args?.includeContent as boolean) ?? true,
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
content: [
|
|
107
|
+
{
|
|
108
|
+
type: "text",
|
|
109
|
+
text: JSON.stringify({ emails, count: emails.length, requestedIds: ids }, null, 2),
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
93
115
|
case "mail_search": {
|
|
94
116
|
const query = args?.query as string;
|
|
95
117
|
if (!query) {
|
package/src/tools.ts
CHANGED
|
@@ -60,6 +60,38 @@ export const MAIL_GET_EMAILS: Tool = {
|
|
|
60
60
|
},
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
+
export const MAIL_GET_EMAILS_BY_IDS: Tool = {
|
|
64
|
+
name: "mail_get_emails_by_ids",
|
|
65
|
+
description: "Get specific emails by their IDs in Apple Mail. Use this to retrieve full details of specific emails after browsing with mail_get_emails (includeContent: false).",
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: "object",
|
|
68
|
+
properties: {
|
|
69
|
+
ids: {
|
|
70
|
+
type: "array",
|
|
71
|
+
items: {
|
|
72
|
+
type: "number",
|
|
73
|
+
},
|
|
74
|
+
description: "Array of email IDs to retrieve (obtained from mail_get_emails or mail_search)",
|
|
75
|
+
},
|
|
76
|
+
account: {
|
|
77
|
+
type: "string",
|
|
78
|
+
description: "The name of the email account (helps optimize search)",
|
|
79
|
+
},
|
|
80
|
+
mailbox: {
|
|
81
|
+
type: "string",
|
|
82
|
+
description: "The name of the mailbox/folder where the emails are located (default: INBOX, helps optimize search)",
|
|
83
|
+
default: "INBOX",
|
|
84
|
+
},
|
|
85
|
+
includeContent: {
|
|
86
|
+
type: "boolean",
|
|
87
|
+
description: "Whether to include the email body content (default: true)",
|
|
88
|
+
default: true,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
required: ["ids"],
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
63
95
|
export const MAIL_SEARCH: Tool = {
|
|
64
96
|
name: "mail_search",
|
|
65
97
|
description: "Search emails in Apple Mail by subject, sender, or content",
|
|
@@ -332,6 +364,7 @@ export const tools: Tool[] = [
|
|
|
332
364
|
MAIL_LIST_ACCOUNTS,
|
|
333
365
|
MAIL_LIST_MAILBOXES,
|
|
334
366
|
MAIL_GET_EMAILS,
|
|
367
|
+
MAIL_GET_EMAILS_BY_IDS,
|
|
335
368
|
MAIL_SEARCH,
|
|
336
369
|
MAIL_GET_UNREAD_COUNT,
|
|
337
370
|
MAIL_SEND,
|