@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.
@@ -9,7 +9,10 @@
9
9
  "Bash(osascript:*)",
10
10
  "Bash(npm publish:*)",
11
11
  "Bash(bun run build)",
12
- "Bash(npx tsc:*)"
12
+ "Bash(npx tsc:*)",
13
+ "Bash(git push:*)",
14
+ "Bash(git add:*)",
15
+ "Bash(git commit:*)"
13
16
  ]
14
17
  }
15
18
  }
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sempervirens-labs/apple-mail-mcp",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "MCP server for Apple Mail - list accounts, mailboxes, search emails, and send messages",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -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
- set results to results & msgId & "<<>>" & msgSubject & "<<>>" & msgSender & "<<>>" & (msgDate as string) & "<<>>" & msgRead & "<<>>" & msgContent & "|||"
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
- set results to results & msgId & "<<>>" & msgSubject & "<<>>" & msgSender & "<<>>" & (msgDate as string) & "<<>>" & msgRead & "|||"
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
- const script = `
373
- tell application "Mail"
374
- try
375
- set theMailbox to ${accountPart}
376
- set theMessage to (first message of theMailbox whose id is ${messageId})
377
- set theAccount to account of theMailbox
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
- -- Find the Archive mailbox for this account
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
  },