@sempervirens-labs/apple-mail-mcp 1.1.0 → 1.3.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/.claude/settings.local.json +4 -1
- package/README.md +4 -0
- package/package.json +1 -1
- package/src/applescript/mail.ts +79 -15
- package/src/index.ts +1 -0
- package/src/tools.ts +4 -0
package/README.md
CHANGED
|
@@ -169,6 +169,9 @@ Get recent emails from a mailbox.
|
|
|
169
169
|
"id": 12345,
|
|
170
170
|
"subject": "Meeting tomorrow",
|
|
171
171
|
"sender": "John Doe <john@example.com>",
|
|
172
|
+
"to": ["you@example.com", "team@example.com"],
|
|
173
|
+
"cc": ["manager@example.com"],
|
|
174
|
+
"bcc": [],
|
|
172
175
|
"dateSent": "Monday, 10. January 2025 at 09:30:00",
|
|
173
176
|
"isRead": false
|
|
174
177
|
}
|
|
@@ -234,6 +237,7 @@ Archive an email by moving it to the Archive mailbox.
|
|
|
234
237
|
| `messageId` | number | **Yes** | - | Email ID (from mail_get_emails or mail_search) |
|
|
235
238
|
| `account` | string | No | - | Account name |
|
|
236
239
|
| `mailbox` | string | No | "INBOX" | Current mailbox of the email |
|
|
240
|
+
| `archiveMailbox` | string | No | auto-detect | Name of the archive folder (auto-detects "Archive", "Archives", or "All Mail") |
|
|
237
241
|
|
|
238
242
|
**Example response:**
|
|
239
243
|
```json
|
package/package.json
CHANGED
package/src/applescript/mail.ts
CHANGED
|
@@ -100,6 +100,9 @@ export interface Email {
|
|
|
100
100
|
id: number;
|
|
101
101
|
subject: string;
|
|
102
102
|
sender: string;
|
|
103
|
+
to: string[];
|
|
104
|
+
cc: string[];
|
|
105
|
+
bcc: string[];
|
|
103
106
|
dateSent: string;
|
|
104
107
|
isRead: boolean;
|
|
105
108
|
content?: string;
|
|
@@ -142,7 +145,26 @@ tell application "Mail"
|
|
|
142
145
|
set msgRead to read status of msg
|
|
143
146
|
${contentPart}
|
|
144
147
|
|
|
145
|
-
|
|
148
|
+
-- Get recipients
|
|
149
|
+
set toList to ""
|
|
150
|
+
repeat with r in to recipients of msg
|
|
151
|
+
set toList to toList & address of r & ","
|
|
152
|
+
end repeat
|
|
153
|
+
if toList is not "" then set toList to text 1 thru -2 of toList
|
|
154
|
+
|
|
155
|
+
set ccList to ""
|
|
156
|
+
repeat with r in cc recipients of msg
|
|
157
|
+
set ccList to ccList & address of r & ","
|
|
158
|
+
end repeat
|
|
159
|
+
if ccList is not "" then set ccList to text 1 thru -2 of ccList
|
|
160
|
+
|
|
161
|
+
set bccList to ""
|
|
162
|
+
repeat with r in bcc recipients of msg
|
|
163
|
+
set bccList to bccList & address of r & ","
|
|
164
|
+
end repeat
|
|
165
|
+
if bccList is not "" then set bccList to text 1 thru -2 of bccList
|
|
166
|
+
|
|
167
|
+
set results to results & msgId & "<<>>" & msgSubject & "<<>>" & msgSender & "<<>>" & toList & "<<>>" & ccList & "<<>>" & bccList & "<<>>" & (msgDate as string) & "<<>>" & msgRead & "<<>>" & msgContent & "|||"
|
|
146
168
|
end repeat
|
|
147
169
|
on error errMsg
|
|
148
170
|
return "ERROR:" & errMsg
|
|
@@ -161,11 +183,14 @@ end tell
|
|
|
161
183
|
const parts = result.split("|||").filter(Boolean);
|
|
162
184
|
|
|
163
185
|
for (const part of parts) {
|
|
164
|
-
const [id, subject, sender, dateSent, isRead, content] = part.split("<<>>");
|
|
186
|
+
const [id, subject, sender, to, cc, bcc, dateSent, isRead, content] = part.split("<<>>");
|
|
165
187
|
emails.push({
|
|
166
188
|
id: parseInt(id) || 0,
|
|
167
189
|
subject: subject || "(No Subject)",
|
|
168
190
|
sender: sender || "(Unknown)",
|
|
191
|
+
to: to ? to.split(",").map(s => s.trim()).filter(Boolean) : [],
|
|
192
|
+
cc: cc ? cc.split(",").map(s => s.trim()).filter(Boolean) : [],
|
|
193
|
+
bcc: bcc ? bcc.split(",").map(s => s.trim()).filter(Boolean) : [],
|
|
169
194
|
dateSent: dateSent || "",
|
|
170
195
|
isRead: isRead === "true",
|
|
171
196
|
content: content || undefined,
|
|
@@ -219,7 +244,26 @@ tell application "Mail"
|
|
|
219
244
|
set msgDate to date sent of msg
|
|
220
245
|
set msgRead to read status of msg
|
|
221
246
|
|
|
222
|
-
|
|
247
|
+
-- Get recipients
|
|
248
|
+
set toList to ""
|
|
249
|
+
repeat with r in to recipients of msg
|
|
250
|
+
set toList to toList & address of r & ","
|
|
251
|
+
end repeat
|
|
252
|
+
if toList is not "" then set toList to text 1 thru -2 of toList
|
|
253
|
+
|
|
254
|
+
set ccList to ""
|
|
255
|
+
repeat with r in cc recipients of msg
|
|
256
|
+
set ccList to ccList & address of r & ","
|
|
257
|
+
end repeat
|
|
258
|
+
if ccList is not "" then set ccList to text 1 thru -2 of ccList
|
|
259
|
+
|
|
260
|
+
set bccList to ""
|
|
261
|
+
repeat with r in bcc recipients of msg
|
|
262
|
+
set bccList to bccList & address of r & ","
|
|
263
|
+
end repeat
|
|
264
|
+
if bccList is not "" then set bccList to text 1 thru -2 of bccList
|
|
265
|
+
|
|
266
|
+
set results to results & msgId & "<<>>" & msgSubject & "<<>>" & msgSender & "<<>>" & toList & "<<>>" & ccList & "<<>>" & bccList & "<<>>" & (msgDate as string) & "<<>>" & msgRead & "|||"
|
|
223
267
|
set foundCount to foundCount + 1
|
|
224
268
|
end repeat
|
|
225
269
|
end repeat
|
|
@@ -240,11 +284,14 @@ end tell
|
|
|
240
284
|
const parts = result.split("|||").filter(Boolean);
|
|
241
285
|
|
|
242
286
|
for (const part of parts) {
|
|
243
|
-
const [id, subject, sender, dateSent, isRead] = part.split("<<>>");
|
|
287
|
+
const [id, subject, sender, to, cc, bcc, dateSent, isRead] = part.split("<<>>");
|
|
244
288
|
emails.push({
|
|
245
289
|
id: parseInt(id) || 0,
|
|
246
290
|
subject: subject || "(No Subject)",
|
|
247
291
|
sender: sender || "(Unknown)",
|
|
292
|
+
to: to ? to.split(",").map(s => s.trim()).filter(Boolean) : [],
|
|
293
|
+
cc: cc ? cc.split(",").map(s => s.trim()).filter(Boolean) : [],
|
|
294
|
+
bcc: bcc ? bcc.split(",").map(s => s.trim()).filter(Boolean) : [],
|
|
248
295
|
dateSent: dateSent || "",
|
|
249
296
|
isRead: isRead === "true",
|
|
250
297
|
});
|
|
@@ -362,32 +409,49 @@ export function archiveEmail(options: {
|
|
|
362
409
|
messageId: number;
|
|
363
410
|
account?: string;
|
|
364
411
|
mailbox?: string;
|
|
412
|
+
archiveMailbox?: string;
|
|
365
413
|
}): { success: boolean; message: string } {
|
|
366
|
-
const { messageId, account, mailbox = "INBOX" } = options;
|
|
414
|
+
const { messageId, account, mailbox = "INBOX", archiveMailbox: customArchiveMailbox } = options;
|
|
367
415
|
|
|
368
416
|
const accountPart = account
|
|
369
417
|
? `mailbox "${mailbox}" of account "${account}"`
|
|
370
418
|
: `mailbox "${mailbox}"`;
|
|
371
419
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
set
|
|
376
|
-
|
|
377
|
-
|
|
420
|
+
// If a custom archive mailbox is specified, use it directly
|
|
421
|
+
const archiveLogic = customArchiveMailbox
|
|
422
|
+
? `
|
|
423
|
+
set archiveMailbox to missing value
|
|
424
|
+
repeat with mb in mailboxes of theAccount
|
|
425
|
+
if name of mb is "${customArchiveMailbox}" then
|
|
426
|
+
set archiveMailbox to mb
|
|
427
|
+
exit repeat
|
|
428
|
+
end if
|
|
429
|
+
end repeat
|
|
378
430
|
|
|
379
|
-
|
|
431
|
+
if archiveMailbox is missing value then
|
|
432
|
+
return "ERROR:Archive mailbox '${customArchiveMailbox}' not found for this account"
|
|
433
|
+
end if`
|
|
434
|
+
: `
|
|
435
|
+
-- Find the Archive mailbox for this account (try common names)
|
|
380
436
|
set archiveMailbox to missing value
|
|
381
437
|
repeat with mb in mailboxes of theAccount
|
|
382
|
-
if name of mb is "Archive" or name of mb is "All Mail" then
|
|
438
|
+
if name of mb is "Archive" or name of mb is "Archives" or name of mb is "All Mail" then
|
|
383
439
|
set archiveMailbox to mb
|
|
384
440
|
exit repeat
|
|
385
441
|
end if
|
|
386
442
|
end repeat
|
|
387
443
|
|
|
388
444
|
if archiveMailbox is missing value then
|
|
389
|
-
return "ERROR:No Archive mailbox found for this account"
|
|
390
|
-
end if
|
|
445
|
+
return "ERROR:No Archive mailbox found for this account. Try specifying archiveMailbox parameter with the exact folder name."
|
|
446
|
+
end if`;
|
|
447
|
+
|
|
448
|
+
const script = `
|
|
449
|
+
tell application "Mail"
|
|
450
|
+
try
|
|
451
|
+
set theMailbox to ${accountPart}
|
|
452
|
+
set theMessage to (first message of theMailbox whose id is ${messageId})
|
|
453
|
+
set theAccount to account of theMailbox
|
|
454
|
+
${archiveLogic}
|
|
391
455
|
|
|
392
456
|
move theMessage to archiveMailbox
|
|
393
457
|
return "Message archived successfully"
|
package/src/index.ts
CHANGED
|
@@ -163,6 +163,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
163
163
|
messageId,
|
|
164
164
|
account: args?.account as string | undefined,
|
|
165
165
|
mailbox: (args?.mailbox as string) || "INBOX",
|
|
166
|
+
archiveMailbox: args?.archiveMailbox as string | undefined,
|
|
166
167
|
});
|
|
167
168
|
|
|
168
169
|
return {
|
package/src/tools.ts
CHANGED
|
@@ -165,6 +165,10 @@ export const MAIL_ARCHIVE: Tool = {
|
|
|
165
165
|
description: "The name of the mailbox/folder where the email currently is (default: INBOX)",
|
|
166
166
|
default: "INBOX",
|
|
167
167
|
},
|
|
168
|
+
archiveMailbox: {
|
|
169
|
+
type: "string",
|
|
170
|
+
description: "The name of the archive mailbox to move the email to (default: auto-detects 'Archive', 'Archives', or 'All Mail')",
|
|
171
|
+
},
|
|
168
172
|
},
|
|
169
173
|
required: ["messageId"],
|
|
170
174
|
},
|