apple-mail-mcp 2.1.4 → 2.2.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 CHANGED
@@ -62,11 +62,14 @@ codex plugin marketplace add sweetrb/apple-mail-mcp
62
62
  codex plugin add apple-mail@apple-mail-mcp
63
63
  ```
64
64
 
65
- The Codex package registers the same `apple-mail` MCP server through `npx -y github:sweetrb/apple-mail-mcp` and includes the Apple Mail skill guidance.
65
+ The Codex package registers the same `apple-mail` MCP server through `npx -y apple-mail-mcp` and includes the Apple Mail skill guidance.
66
66
 
67
67
  ### Other Hosts (Hermes, Antigravity)
68
68
 
69
- Plugin packaging for the Hermes and Antigravity hosts is also included (`.hermes-plugin/` and `.antigravity-plugin/`). Each registers the same `apple-mail` MCP server (launched via `npx -y github:sweetrb/apple-mail-mcp`) and bundles the Apple Mail skill, so behavior matches the Claude Code and Codex plugins. Install them through each host's plugin/marketplace mechanism pointed at this repository.
69
+ Configuration for two more hosts is included each registers the same `apple-mail` MCP server (`npx -y apple-mail-mcp`):
70
+
71
+ - **[Hermes Agent](https://hermes-agent.nousresearch.com/)** (NousResearch) — Hermes has no plugin/marketplace drop-in. Add the server with `hermes mcp add apple-mail --command npx --args -y apple-mail-mcp`, or merge [`.hermes-plugin/config.yaml`](.hermes-plugin/config.yaml) into `~/.hermes/config.yaml`. Details: [`.hermes-plugin/README.md`](.hermes-plugin/README.md).
72
+ - **[Antigravity](https://antigravity.google/)** (Google) — add the server entry from [`.antigravity-plugin/mcp_config.json`](.antigravity-plugin/mcp_config.json) to `~/.gemini/config/mcp_config.json` (or via Antigravity's MCP settings).
70
73
 
71
74
  ### Manual Installation
72
75
 
package/build/index.js CHANGED
@@ -153,7 +153,7 @@ server.tool("search-messages", "Use when: finding messages by query/sender/subje
153
153
  // IMAP backend (issue #43): server-side search when this account is
154
154
  // explicitly configured for IMAP; otherwise fall through to AppleScript.
155
155
  if (isImapAccount(account)) {
156
- return successResponse(await imapSearchMessages({
156
+ const r = await imapSearchMessages({
157
157
  query,
158
158
  mailbox,
159
159
  account,
@@ -164,7 +164,12 @@ server.tool("search-messages", "Use when: finding messages by query/sender/subje
164
164
  subject,
165
165
  isRead,
166
166
  isFlagged,
167
- }));
167
+ });
168
+ return successResponse(r.text, {
169
+ messages: r.messages,
170
+ count: r.count,
171
+ partial: r.partial,
172
+ });
168
173
  }
169
174
  const { messages, diagnostics } = mailManager.searchMessagesWithDiagnostics(query, mailbox, account, limit, dateFrom, dateTo, from, subject, isRead, isFlagged);
170
175
  const coverageBlock = partialCoverageBlock(diagnostics);
@@ -197,6 +202,19 @@ server.tool("get-message", "Use when: reading the full body of one message whose
197
202
  }, withErrorHandling(({ id, preferHtml }) => routeMessage(id, {
198
203
  // IMAP id (imap:…) → fetch via IMAP (#43 Phase 3); else AppleScript.
199
204
  imap: () => imapGetMessage(id, preferHtml === true),
205
+ // IMAP path: parse subject/body out of the returned source so the
206
+ // structuredContent matches the AppleScript branch's shape.
207
+ structuredFromResult: (r) => {
208
+ if (!r.info)
209
+ return undefined;
210
+ const sep = r.info.indexOf("\n\n");
211
+ return {
212
+ id,
213
+ subject: subjectFromGetMessage(r.info),
214
+ body: sep >= 0 ? r.info.slice(sep + 2) : r.info,
215
+ isHtml: preferHtml === true,
216
+ };
217
+ },
200
218
  apple: () => {
201
219
  // Only fetch/parse the raw source when HTML is actually requested (#32).
202
220
  const content = mailManager.getMessageContent(id, preferHtml === true);
@@ -249,8 +267,13 @@ server.tool("get-thread", "Use when: you have one message id and want the whole
249
267
  const base = normalizeSubject(seedSubject);
250
268
  // IMAP backend: server-side subject search.
251
269
  if (isImapAccount(account)) {
252
- const text = await imapSearchMessages({ subject: base, mailbox, account, limit });
253
- return successResponse(`Thread "${base}":\n${text}`, { subject: base });
270
+ const r = await imapSearchMessages({ subject: base, mailbox, account, limit });
271
+ return successResponse(`Thread "${base}":\n${r.text}`, {
272
+ subject: base,
273
+ messages: r.messages,
274
+ count: r.count,
275
+ partial: r.partial,
276
+ });
254
277
  }
255
278
  const { messages, diagnostics } = mailManager.searchMessagesWithDiagnostics(undefined, mailbox, account, limit, undefined, undefined, undefined, base);
256
279
  // Oldest-first is the natural reading order for a conversation.
@@ -287,7 +310,12 @@ server.tool("list-messages", "Use when: browsing a mailbox's recent messages (op
287
310
  // IMAP backend (issue #43): server-side listing when this account is
288
311
  // explicitly configured for IMAP; otherwise fall through to AppleScript.
289
312
  if (isImapAccount(account)) {
290
- return successResponse(await imapListMessages({ mailbox, account, limit, offset, from, unreadOnly }));
313
+ const r = await imapListMessages({ mailbox, account, limit, offset, from, unreadOnly });
314
+ return successResponse(r.text, {
315
+ messages: r.messages,
316
+ count: r.count,
317
+ partial: r.partial,
318
+ });
291
319
  }
292
320
  const { messages, diagnostics } = mailManager.listMessagesWithDiagnostics(mailbox, account, limit, from, offset);
293
321
  const coverageBlock = partialCoverageBlock(diagnostics);
@@ -327,18 +355,29 @@ server.tool("send-email", "Use when: the user has explicitly confirmed they want
327
355
  "Mail.app <blockquote> wrapping (issue #12); requires APPLE_MAIL_MCP_SMTP_* env config."),
328
356
  }, withErrorHandling(async ({ to, subject, body, cc, bcc, account, attachments, transport }) => {
329
357
  const attachInfo = attachments?.length ? ` with ${attachments.length} attachment(s)` : "";
358
+ const attachmentCount = attachments?.length ?? 0;
330
359
  if (transport === "smtp") {
331
360
  const result = await sendViaSmtp({ to, subject, body, cc, bcc, from: account, attachments });
332
361
  if (!result.success) {
333
362
  return errorResponse(result.error ?? "Failed to send email via SMTP.");
334
363
  }
335
- return successResponse(`Email sent via SMTP to ${to.join(", ")}${attachInfo}`);
364
+ return successResponse(`Email sent via SMTP to ${to.join(", ")}${attachInfo}`, {
365
+ ok: true,
366
+ recipients: to,
367
+ attachmentCount,
368
+ transport: "smtp",
369
+ });
336
370
  }
337
371
  const success = mailManager.sendEmail(to, subject, body, cc, bcc, account, attachments);
338
372
  if (!success) {
339
373
  return errorResponse("Failed to send email. Check Mail.app configuration.");
340
374
  }
341
- return successResponse(`Email sent to ${to.join(", ")}${attachInfo}`);
375
+ return successResponse(`Email sent to ${to.join(", ")}${attachInfo}`, {
376
+ ok: true,
377
+ recipients: to,
378
+ attachmentCount,
379
+ transport: "applescript",
380
+ });
342
381
  }, "Error sending email"));
343
382
  // --- send-serial-email ---
344
383
  server.tool("send-serial-email", "Use when: the user has confirmed a mail-merge — sending individually personalized copies to many recipients (max 100), with {{Key}} placeholders in subject/body replaced per-recipient from each recipient's variables. Recipients do not see each other.\nReturns: a per-recipient sent/failed report with counts.\nDo not use when: sending one message to a shared recipient list (use send-email) or saving for review (use create-draft).\nSafety: this SENDS many real emails immediately and they cannot be unsent — require explicit user confirmation of the recipient list, the subject/body template, and the placeholder substitutions before calling.", {
@@ -374,14 +413,20 @@ server.tool("send-serial-email", "Use when: the user has confirmed a mail-merge
374
413
  const details = results
375
414
  .map((r) => ` - ${r.email}: ${r.success ? "sent" : `FAILED (${r.error})`}`)
376
415
  .join("\n");
416
+ const structured = {
417
+ ok: failCount === 0,
418
+ sent: successCount,
419
+ failed: failCount,
420
+ results: results.map((r) => ({ email: r.email, success: r.success, error: r.error })),
421
+ };
377
422
  if (failCount === 0) {
378
- return successResponse(`Successfully sent ${successCount} email(s):\n${details}`);
423
+ return successResponse(`Successfully sent ${successCount} email(s):\n${details}`, structured);
379
424
  }
380
425
  else if (successCount === 0) {
381
426
  return errorResponse(`Failed to send all ${failCount} email(s):\n${details}`);
382
427
  }
383
428
  else {
384
- return successResponse(`Sent ${successCount} of ${results.length} email(s), ${failCount} failed:\n${details}`);
429
+ return successResponse(`Sent ${successCount} of ${results.length} email(s), ${failCount} failed:\n${details}`, structured);
385
430
  }
386
431
  }, "Error sending serial emails"));
387
432
  // --- create-draft ---
@@ -398,8 +443,13 @@ server.tool("create-draft", "Use when: composing an email the user should review
398
443
  if (!success) {
399
444
  return errorResponse("Failed to create draft. Check Mail.app configuration.");
400
445
  }
401
- const attachInfo = attachments?.length ? ` with ${attachments.length} attachment(s)` : "";
402
- return successResponse(`Draft created for ${to.join(", ")}${attachInfo}`);
446
+ const attachmentCount = attachments?.length ?? 0;
447
+ const attachInfo = attachmentCount ? ` with ${attachmentCount} attachment(s)` : "";
448
+ return successResponse(`Draft created for ${to.join(", ")}${attachInfo}`, {
449
+ ok: true,
450
+ recipients: to,
451
+ attachmentCount,
452
+ });
403
453
  }, "Error creating draft"));
404
454
  // --- reply-to-message ---
405
455
  server.tool("reply-to-message", "Use when: replying to an existing message by id, preserving its threading headers. Set replyAll for all recipients; set send=false to save as a draft instead of sending.\nReturns: a confirmation that the reply was sent or saved as a draft.\nDo not use when: composing a brand-new message (use send-email / create-draft) or forwarding to new recipients (use forward-message).\nSafety: with the default send=true this SENDS real email immediately and cannot be unsent — require explicit user confirmation of the recipients and body, or pass send=false to let the user review.", {
@@ -412,7 +462,11 @@ server.tool("reply-to-message", "Use when: replying to an existing message by id
412
462
  if (!success) {
413
463
  return errorResponse(`Failed to reply to message "${id}"`);
414
464
  }
415
- return successResponse(send ? "Reply sent" : "Reply saved as draft");
465
+ return successResponse(send ? "Reply sent" : "Reply saved as draft", {
466
+ ok: true,
467
+ sent: send,
468
+ id,
469
+ });
416
470
  }, "Error replying to message"));
417
471
  // --- forward-message ---
418
472
  server.tool("forward-message", "Use when: forwarding an existing message (by id) to new recipients (to is an array), with an optional body to prepend. Set send=false to save as a draft.\nReturns: a confirmation that the message was forwarded or saved as a draft.\nDo not use when: replying to the sender/recipients (use reply-to-message) or composing a new message (use send-email / create-draft).\nSafety: with the default send=true this SENDS real email immediately and cannot be unsent — require explicit user confirmation of the recipients and any prepended body, or pass send=false to let the user review.", {
@@ -425,7 +479,7 @@ server.tool("forward-message", "Use when: forwarding an existing message (by id)
425
479
  if (!success) {
426
480
  return errorResponse(`Failed to forward message "${id}"`);
427
481
  }
428
- return successResponse(send ? `Message forwarded to ${to.join(", ")}` : "Forward saved as draft");
482
+ return successResponse(send ? `Message forwarded to ${to.join(", ")}` : "Forward saved as draft", { ok: true, sent: send, recipients: to, id });
429
483
  }, "Error forwarding message"));
430
484
  // --- mark-as-read ---
431
485
  server.tool("mark-as-read", "Use when: marking a single message (by id) as read.\nReturns: a confirmation that the message was marked read.\nDo not use when: marking several at once (use batch-mark-as-read) or marking unread (use mark-as-unread). Get the id from search-messages or list-messages first.", {
@@ -433,10 +487,11 @@ server.tool("mark-as-read", "Use when: marking a single message (by id) as read.
433
487
  }, withErrorHandling(({ id }) => routeMessage(id, {
434
488
  imap: () => imapMarkRead(id),
435
489
  apple: () => mailManager.markAsRead(id)
436
- ? successResponse("Message marked as read")
490
+ ? successResponse("Message marked as read", { ok: true, id })
437
491
  : errorResponse(`Failed to mark message "${id}" as read`),
438
492
  ok: "Message marked as read",
439
493
  fail: `Failed to mark message "${id}" as read`,
494
+ structured: { ok: true, id },
440
495
  }), "Error marking message as read"));
441
496
  // --- mark-as-unread ---
442
497
  server.tool("mark-as-unread", "Use when: marking a single message (by id) as unread.\nReturns: a confirmation that the message was marked unread.\nDo not use when: marking several at once (use batch-mark-as-unread) or marking read (use mark-as-read). Get the id from search-messages or list-messages first.", {
@@ -444,10 +499,11 @@ server.tool("mark-as-unread", "Use when: marking a single message (by id) as unr
444
499
  }, withErrorHandling(({ id }) => routeMessage(id, {
445
500
  imap: () => imapMarkUnread(id),
446
501
  apple: () => mailManager.markAsUnread(id)
447
- ? successResponse("Message marked as unread")
502
+ ? successResponse("Message marked as unread", { ok: true, id })
448
503
  : errorResponse(`Failed to mark message "${id}" as unread`),
449
504
  ok: "Message marked as unread",
450
505
  fail: `Failed to mark message "${id}" as unread`,
506
+ structured: { ok: true, id },
451
507
  }), "Error marking message as unread"));
452
508
  // --- flag-message ---
453
509
  server.tool("flag-message", "Use when: flagging a single message (by id).\nReturns: a confirmation that the message was flagged.\nDo not use when: flagging several at once (use batch-flag-messages) or removing a flag (use unflag-message). Get the id from search-messages or list-messages first.", {
@@ -455,10 +511,11 @@ server.tool("flag-message", "Use when: flagging a single message (by id).\nRetur
455
511
  }, withErrorHandling(({ id }) => routeMessage(id, {
456
512
  imap: () => imapFlagMessage(id),
457
513
  apple: () => mailManager.flagMessage(id)
458
- ? successResponse("Message flagged")
514
+ ? successResponse("Message flagged", { ok: true, id })
459
515
  : errorResponse(`Failed to flag message "${id}"`),
460
516
  ok: "Message flagged",
461
517
  fail: `Failed to flag message "${id}"`,
518
+ structured: { ok: true, id },
462
519
  }), "Error flagging message"));
463
520
  // --- unflag-message ---
464
521
  server.tool("unflag-message", "Use when: removing the flag from a single message (by id).\nReturns: a confirmation that the message was unflagged.\nDo not use when: unflagging several at once (use batch-unflag-messages) or adding a flag (use flag-message). Get the id from search-messages or list-messages first.", {
@@ -466,10 +523,11 @@ server.tool("unflag-message", "Use when: removing the flag from a single message
466
523
  }, withErrorHandling(({ id }) => routeMessage(id, {
467
524
  imap: () => imapUnflagMessage(id),
468
525
  apple: () => mailManager.unflagMessage(id)
469
- ? successResponse("Message unflagged")
526
+ ? successResponse("Message unflagged", { ok: true, id })
470
527
  : errorResponse(`Failed to unflag message "${id}"`),
471
528
  ok: "Message unflagged",
472
529
  fail: `Failed to unflag message "${id}"`,
530
+ structured: { ok: true, id },
473
531
  }), "Error unflagging message"));
474
532
  // --- delete-message ---
475
533
  server.tool("delete-message", "Use when: deleting a single message by id (moves it to Trash).\nReturns: a confirmation that the message was deleted.\nDo not use when: deleting several at once (use batch-delete-messages) or just filing it away (use move-message).\nSafety: destructive — require explicit user confirmation, and search-messages/list-messages first to confirm you have the right id before deleting.", {
@@ -479,11 +537,12 @@ server.tool("delete-message", "Use when: deleting a single message by id (moves
479
537
  apple: () => {
480
538
  const { success, error } = mailManager.deleteMessage(id);
481
539
  return success
482
- ? successResponse("Message deleted")
540
+ ? successResponse("Message deleted", { ok: true, id })
483
541
  : errorResponse(error || `Failed to delete message "${id}"`);
484
542
  },
485
543
  ok: "Message deleted",
486
544
  fail: `Failed to delete message "${id}"`,
545
+ structured: { ok: true, id },
487
546
  }), "Error deleting message"));
488
547
  // --- move-message ---
489
548
  server.tool("move-message", "Use when: moving a single message (by id) into another mailbox/folder, e.g. archiving or filing.\nReturns: a confirmation naming the destination mailbox.\nDo not use when: moving several at once (use batch-move-messages) or deleting (use delete-message). Use list-mailboxes to confirm the destination name exists.\nSafety: moves a real message between folders — confirm the destination mailbox, and search-messages/list-messages first to confirm the id.", {
@@ -495,25 +554,27 @@ server.tool("move-message", "Use when: moving a single message (by id) into anot
495
554
  apple: () => {
496
555
  const { success, error } = mailManager.moveMessage(id, mailbox, account);
497
556
  return success
498
- ? successResponse(`Message moved to "${mailbox}"`)
557
+ ? successResponse(`Message moved to "${mailbox}"`, { ok: true, id, mailbox })
499
558
  : errorResponse(error || `Failed to move message to "${mailbox}"`);
500
559
  },
501
560
  ok: `Message moved to "${mailbox}"`,
502
561
  fail: `Failed to move message to "${mailbox}"`,
562
+ structured: { ok: true, id, mailbox },
503
563
  }), "Error moving message"));
504
564
  // --- batch-delete-messages ---
505
565
  server.tool("batch-delete-messages", "Use when: deleting multiple messages in one call (1–100 ids; moves them to Trash).\nReturns: counts of how many were deleted and how many failed.\nDo not use when: deleting just one (use delete-message) or filing messages away (use batch-move-messages).\nSafety: destructive and applies to many messages at once — require explicit user confirmation, and search-messages/list-messages first to confirm every id is correct before deleting.", {
506
566
  ids: BATCH_IDS_SCHEMA,
507
567
  }, withErrorHandling(async ({ ids }) => {
508
568
  const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchDeleteMessages(n), (im) => imapBatchDelete(im));
569
+ const structured = { ok: failCount === 0, success: successCount, failed: failCount };
509
570
  if (failCount === 0) {
510
- return successResponse(`Successfully deleted ${successCount} message(s)`);
571
+ return successResponse(`Successfully deleted ${successCount} message(s)`, structured);
511
572
  }
512
573
  else if (successCount === 0) {
513
574
  return errorResponse(`Failed to delete all ${failCount} message(s)`);
514
575
  }
515
576
  else {
516
- return successResponse(`Deleted ${successCount} message(s), ${failCount} failed`);
577
+ return successResponse(`Deleted ${successCount} message(s), ${failCount} failed`, structured);
517
578
  }
518
579
  }, "Error batch deleting messages"));
519
580
  // --- batch-move-messages ---
@@ -523,14 +584,15 @@ server.tool("batch-move-messages", "Use when: moving multiple messages (1–100
523
584
  account: z.string().optional().describe("Account containing the destination mailbox"),
524
585
  }, withErrorHandling(async ({ ids, mailbox, account }) => {
525
586
  const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchMoveMessages(n, mailbox, account), (im) => imapBatchMove(im, mailbox, { account }));
587
+ const structured = { ok: failCount === 0, success: successCount, failed: failCount, mailbox };
526
588
  if (failCount === 0) {
527
- return successResponse(`Successfully moved ${successCount} message(s) to "${mailbox}"`);
589
+ return successResponse(`Successfully moved ${successCount} message(s) to "${mailbox}"`, structured);
528
590
  }
529
591
  else if (successCount === 0) {
530
592
  return errorResponse(`Failed to move all ${failCount} message(s)`);
531
593
  }
532
594
  else {
533
- return successResponse(`Moved ${successCount} message(s) to "${mailbox}", ${failCount} failed`);
595
+ return successResponse(`Moved ${successCount} message(s) to "${mailbox}", ${failCount} failed`, structured);
534
596
  }
535
597
  }, "Error batch moving messages"));
536
598
  // --- batch-mark-as-read ---
@@ -538,14 +600,15 @@ server.tool("batch-mark-as-read", "Use when: marking multiple messages (1–100
538
600
  ids: BATCH_IDS_SCHEMA,
539
601
  }, withErrorHandling(async ({ ids }) => {
540
602
  const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchMarkAsRead(n), (im) => imapBatchMarkRead(im));
603
+ const structured = { ok: failCount === 0, success: successCount, failed: failCount };
541
604
  if (failCount === 0) {
542
- return successResponse(`Successfully marked ${successCount} message(s) as read`);
605
+ return successResponse(`Successfully marked ${successCount} message(s) as read`, structured);
543
606
  }
544
607
  else if (successCount === 0) {
545
608
  return errorResponse(`Failed to mark all ${failCount} message(s) as read`);
546
609
  }
547
610
  else {
548
- return successResponse(`Marked ${successCount} message(s) as read, ${failCount} failed`);
611
+ return successResponse(`Marked ${successCount} message(s) as read, ${failCount} failed`, structured);
549
612
  }
550
613
  }, "Error batch marking messages as read"));
551
614
  // --- batch-mark-as-unread ---
@@ -553,14 +616,15 @@ server.tool("batch-mark-as-unread", "Use when: marking multiple messages (1–10
553
616
  ids: BATCH_IDS_SCHEMA,
554
617
  }, withErrorHandling(async ({ ids }) => {
555
618
  const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchMarkAsUnread(n), (im) => imapBatchMarkUnread(im));
619
+ const structured = { ok: failCount === 0, success: successCount, failed: failCount };
556
620
  if (failCount === 0) {
557
- return successResponse(`Successfully marked ${successCount} message(s) as unread`);
621
+ return successResponse(`Successfully marked ${successCount} message(s) as unread`, structured);
558
622
  }
559
623
  else if (successCount === 0) {
560
624
  return errorResponse(`Failed to mark all ${failCount} message(s) as unread`);
561
625
  }
562
626
  else {
563
- return successResponse(`Marked ${successCount} message(s) as unread, ${failCount} failed`);
627
+ return successResponse(`Marked ${successCount} message(s) as unread, ${failCount} failed`, structured);
564
628
  }
565
629
  }, "Error batch marking messages as unread"));
566
630
  // --- batch-flag-messages ---
@@ -568,14 +632,15 @@ server.tool("batch-flag-messages", "Use when: flagging multiple messages (1–10
568
632
  ids: BATCH_IDS_SCHEMA,
569
633
  }, withErrorHandling(async ({ ids }) => {
570
634
  const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchFlagMessages(n), (im) => imapBatchFlag(im));
635
+ const structured = { ok: failCount === 0, success: successCount, failed: failCount };
571
636
  if (failCount === 0) {
572
- return successResponse(`Successfully flagged ${successCount} message(s)`);
637
+ return successResponse(`Successfully flagged ${successCount} message(s)`, structured);
573
638
  }
574
639
  else if (successCount === 0) {
575
640
  return errorResponse(`Failed to flag all ${failCount} message(s)`);
576
641
  }
577
642
  else {
578
- return successResponse(`Flagged ${successCount} message(s), ${failCount} failed`);
643
+ return successResponse(`Flagged ${successCount} message(s), ${failCount} failed`, structured);
579
644
  }
580
645
  }, "Error batch flagging messages"));
581
646
  // --- batch-unflag-messages ---
@@ -583,14 +648,15 @@ server.tool("batch-unflag-messages", "Use when: removing flags from multiple mes
583
648
  ids: BATCH_IDS_SCHEMA,
584
649
  }, withErrorHandling(async ({ ids }) => {
585
650
  const { success: successCount, fail: failCount } = await hybridBatchCounts(ids, (n) => mailManager.batchUnflagMessages(n), (im) => imapBatchUnflag(im));
651
+ const structured = { ok: failCount === 0, success: successCount, failed: failCount };
586
652
  if (failCount === 0) {
587
- return successResponse(`Successfully unflagged ${successCount} message(s)`);
653
+ return successResponse(`Successfully unflagged ${successCount} message(s)`, structured);
588
654
  }
589
655
  else if (successCount === 0) {
590
656
  return errorResponse(`Failed to unflag all ${failCount} message(s)`);
591
657
  }
592
658
  else {
593
- return successResponse(`Unflagged ${successCount} message(s), ${failCount} failed`);
659
+ return successResponse(`Unflagged ${successCount} message(s), ${failCount} failed`, structured);
594
660
  }
595
661
  }, "Error batch unflagging messages"));
596
662
  // --- list-attachments ---
@@ -640,14 +706,23 @@ server.tool("save-attachment", "Use when: writing one of a message's attachments
640
706
  if (!r.success || !r.base64) {
641
707
  return errorResponse(r.error || `Failed to fetch attachment "${attachmentName}"`);
642
708
  }
643
- writeFileSync(joinPath(resolvedDir, attachmentName), Buffer.from(r.base64, "base64"));
644
- return successResponse(`Attachment "${attachmentName}" saved to ${savePath}`);
709
+ const savedPath = joinPath(resolvedDir, attachmentName);
710
+ writeFileSync(savedPath, Buffer.from(r.base64, "base64"));
711
+ return successResponse(`Attachment "${attachmentName}" saved to ${savePath}`, {
712
+ ok: true,
713
+ attachmentName,
714
+ savedPath,
715
+ });
645
716
  }
646
717
  const success = mailManager.saveAttachment(id, attachmentName, savePath);
647
718
  if (!success) {
648
719
  return errorResponse(`Failed to save attachment "${attachmentName}"`);
649
720
  }
650
- return successResponse(`Attachment "${attachmentName}" saved to ${savePath}`);
721
+ return successResponse(`Attachment "${attachmentName}" saved to ${savePath}`, {
722
+ ok: true,
723
+ attachmentName,
724
+ savedPath: joinPath(savePath, attachmentName),
725
+ });
651
726
  }, "Error saving attachment"));
652
727
  // --- fetch-attachment ---
653
728
  server.tool("fetch-attachment", "Use when: retrieving an attachment's raw bytes inline as base64 (by message id and attachmentName), e.g. to process its contents without touching disk.\nReturns: the attachment's bytes base64-encoded, with its size and (for IMAP) MIME type.\nDo not use when: you don't know the attachment name (use list-attachments first) or you just want it saved to disk (use save-attachment).", {
@@ -730,13 +805,13 @@ server.tool("create-mailbox", "Use when: creating a new mailbox/folder in an acc
730
805
  const r = await imapCreateMailbox(name, { account });
731
806
  if (!r.success)
732
807
  return errorResponse(r.error || `Failed to create mailbox "${name}"`);
733
- return successResponse(r.info || `Mailbox "${name}" created`);
808
+ return successResponse(r.info || `Mailbox "${name}" created`, { ok: true, name });
734
809
  }
735
810
  const success = mailManager.createMailbox(name, account);
736
811
  if (!success) {
737
812
  return errorResponse(`Failed to create mailbox "${name}"`);
738
813
  }
739
- return successResponse(`Mailbox "${name}" created`);
814
+ return successResponse(`Mailbox "${name}" created`, { ok: true, name });
740
815
  }, "Error creating mailbox"));
741
816
  // --- delete-mailbox ---
742
817
  server.tool("delete-mailbox", "Use when: deleting a mailbox/folder from an account.\nReturns: a confirmation that the mailbox was deleted.\nDo not use when: renaming it (use rename-mailbox) or deleting messages within it (use delete-message / batch-delete-messages).\nSafety: destructive — deleting a mailbox removes the folder and any messages it contains. Require explicit user confirmation and use list-mailboxes first to confirm the exact name.", {
@@ -747,13 +822,13 @@ server.tool("delete-mailbox", "Use when: deleting a mailbox/folder from an accou
747
822
  const r = await imapDeleteMailbox(name, { account });
748
823
  if (!r.success)
749
824
  return errorResponse(r.error || `Failed to delete mailbox "${name}"`);
750
- return successResponse(r.info || `Mailbox "${name}" deleted`);
825
+ return successResponse(r.info || `Mailbox "${name}" deleted`, { ok: true, name });
751
826
  }
752
827
  const { success, error } = mailManager.deleteMailbox(name, account);
753
828
  if (!success) {
754
829
  return errorResponse(error || `Failed to delete mailbox "${name}"`);
755
830
  }
756
- return successResponse(`Mailbox "${name}" deleted`);
831
+ return successResponse(`Mailbox "${name}" deleted`, { ok: true, name });
757
832
  }, "Error deleting mailbox"));
758
833
  // --- rename-mailbox ---
759
834
  server.tool("rename-mailbox", "Use when: renaming an existing mailbox/folder from oldName to newName within an account.\nReturns: a confirmation naming the old and new mailbox names.\nDo not use when: creating a new folder (use create-mailbox) or deleting one (use delete-mailbox). Use list-mailboxes to confirm the current name.\nSafety: renames a real folder in the mail account — confirm oldName matches exactly (case-sensitive) before calling.", {
@@ -766,13 +841,21 @@ server.tool("rename-mailbox", "Use when: renaming an existing mailbox/folder fro
766
841
  if (!r.success) {
767
842
  return errorResponse(r.error || `Failed to rename mailbox "${oldName}" to "${newName}"`);
768
843
  }
769
- return successResponse(r.info || `Mailbox renamed from "${oldName}" to "${newName}"`);
844
+ return successResponse(r.info || `Mailbox renamed from "${oldName}" to "${newName}"`, {
845
+ ok: true,
846
+ oldName,
847
+ newName,
848
+ });
770
849
  }
771
850
  const { success, error } = mailManager.renameMailbox(oldName, newName, account);
772
851
  if (!success) {
773
852
  return errorResponse(error || `Failed to rename mailbox "${oldName}" to "${newName}"`);
774
853
  }
775
- return successResponse(`Mailbox renamed from "${oldName}" to "${newName}"`);
854
+ return successResponse(`Mailbox renamed from "${oldName}" to "${newName}"`, {
855
+ ok: true,
856
+ oldName,
857
+ newName,
858
+ });
776
859
  }, "Error renaming mailbox"));
777
860
  // =============================================================================
778
861
  // Account Tools
@@ -793,13 +876,17 @@ server.tool("list-accounts", "Use when: discovering the configured Mail accounts
793
876
  // --- list-rules ---
794
877
  server.tool("list-rules", "Use when: discovering the Mail rules that exist and whether each is enabled or disabled, e.g. before enabling/disabling/deleting one.\nReturns: each rule's name and enabled/disabled state.\nDo not use when: you want to change a rule (use enable-rule / disable-rule / create-rule / delete-rule).", {}, withErrorHandling(() => {
795
878
  const rules = mailManager.listRules();
879
+ const structured = {
880
+ rules: rules.map((r) => ({ name: r.name, enabled: r.enabled })),
881
+ count: rules.length,
882
+ };
796
883
  if (rules.length === 0) {
797
- return successResponse("No mail rules found");
884
+ return successResponse("No mail rules found", structured);
798
885
  }
799
886
  const ruleList = rules
800
887
  .map((r) => ` - ${r.name} [${r.enabled ? "enabled" : "disabled"}]`)
801
888
  .join("\n");
802
- return successResponse(`Found ${rules.length} rule(s):\n${ruleList}`);
889
+ return successResponse(`Found ${rules.length} rule(s):\n${ruleList}`, structured);
803
890
  }, "Error listing rules"));
804
891
  // --- enable-rule ---
805
892
  server.tool("enable-rule", "Use when: turning on an existing Mail rule by name.\nReturns: a confirmation that the rule was enabled.\nDo not use when: turning a rule off (use disable-rule), creating one (use create-rule), or deleting one (use delete-rule). Use list-rules to confirm the exact rule name.", {
@@ -809,7 +896,7 @@ server.tool("enable-rule", "Use when: turning on an existing Mail rule by name.\
809
896
  if (!success) {
810
897
  return errorResponse(`Failed to enable rule "${name}"`);
811
898
  }
812
- return successResponse(`Rule "${name}" enabled`);
899
+ return successResponse(`Rule "${name}" enabled`, { ok: true, name, enabled: true });
813
900
  }, "Error enabling rule"));
814
901
  // --- disable-rule ---
815
902
  server.tool("disable-rule", "Use when: turning off an existing Mail rule by name (without deleting it).\nReturns: a confirmation that the rule was disabled.\nDo not use when: turning a rule on (use enable-rule), creating one (use create-rule), or removing it permanently (use delete-rule). Use list-rules to confirm the exact rule name.", {
@@ -819,7 +906,7 @@ server.tool("disable-rule", "Use when: turning off an existing Mail rule by name
819
906
  if (!success) {
820
907
  return errorResponse(`Failed to disable rule "${name}"`);
821
908
  }
822
- return successResponse(`Rule "${name}" disabled`);
909
+ return successResponse(`Rule "${name}" disabled`, { ok: true, name, enabled: false });
823
910
  }, "Error disabling rule"));
824
911
  // --- create-rule ---
825
912
  server.tool("create-rule", "Use when: creating a new Mail rule with one or more conditions (field/operator/value) and at least one action (markRead, markFlagged, delete, or moveTo). Set matchAll to require all conditions vs. any.\nReturns: a confirmation naming the rule and its condition count.\nDo not use when: toggling an existing rule (use enable-rule / disable-rule) or removing one (use delete-rule). Use list-rules to avoid duplicating an existing rule.\nSafety: creates a rule that automatically acts on real mail (including delete/move actions) on an ongoing basis — confirm the conditions and actions with the user before calling.", {
@@ -869,8 +956,12 @@ server.tool("search-contacts", "Use when: looking up a person in Contacts.app by
869
956
  query: z.string().min(1, "Search query is required"),
870
957
  }, withErrorHandling(({ query }) => {
871
958
  const contacts = mailManager.searchContacts(query);
959
+ const structured = {
960
+ contacts: contacts.map((c) => ({ name: c.name, emails: c.emails })),
961
+ count: contacts.length,
962
+ };
872
963
  if (contacts.length === 0) {
873
- return successResponse("No contacts found");
964
+ return successResponse("No contacts found", structured);
874
965
  }
875
966
  const contactList = contacts
876
967
  .map((c) => {
@@ -878,7 +969,7 @@ server.tool("search-contacts", "Use when: looking up a person in Contacts.app by
878
969
  return ` - ${c.name} (${emails})`;
879
970
  })
880
971
  .join("\n");
881
- return successResponse(`Found ${contacts.length} contact(s):\n${contactList}`);
972
+ return successResponse(`Found ${contacts.length} contact(s):\n${contactList}`, structured);
882
973
  }, "Error searching contacts"));
883
974
  // =============================================================================
884
975
  // Email Template Tools
@@ -893,18 +984,26 @@ server.tool("save-template", "Use when: creating a reusable email template (name
893
984
  id: z.string().optional().describe("Template ID (for updating existing template)"),
894
985
  }, withErrorHandling(({ name, subject, body, to, cc, id }) => {
895
986
  const template = mailManager.saveTemplate(name, subject, body, to, cc, id);
896
- return successResponse(`Template "${template.name}" saved with ID: ${template.id}`);
987
+ return successResponse(`Template "${template.name}" saved with ID: ${template.id}`, {
988
+ ok: true,
989
+ id: template.id,
990
+ name: template.name,
991
+ });
897
992
  }, "Error saving template"));
898
993
  // --- list-templates ---
899
994
  server.tool("list-templates", "Use when: discovering the saved email templates and their ids, e.g. before using or editing one.\nReturns: each template's id, name, and subject.\nDo not use when: you want a single template's full body (use get-template) or want to apply one (use use-template).", {}, withErrorHandling(() => {
900
995
  const templates = mailManager.listTemplates();
996
+ const structured = {
997
+ templates: templates.map((t) => ({ id: t.id, name: t.name, subject: t.subject })),
998
+ count: templates.length,
999
+ };
901
1000
  if (templates.length === 0) {
902
- return successResponse("No templates saved");
1001
+ return successResponse("No templates saved", structured);
903
1002
  }
904
1003
  const templateList = templates
905
1004
  .map((t) => ` - [${t.id}] ${t.name} — "${t.subject}"`)
906
1005
  .join("\n");
907
- return successResponse(`Found ${templates.length} template(s):\n${templateList}`);
1006
+ return successResponse(`Found ${templates.length} template(s):\n${templateList}`, structured);
908
1007
  }, "Error listing templates"));
909
1008
  // --- get-template ---
910
1009
  server.tool("get-template", "Use when: reading the full contents of one saved template by id — its name, subject, default to/cc, and body.\nReturns: the template's name, subject, default recipients, and body text.\nDo not use when: you don't have the id (use list-templates first) or want to apply the template into a draft (use use-template).", {
@@ -923,7 +1022,14 @@ server.tool("get-template", "Use when: reading the full contents of one saved te
923
1022
  ]
924
1023
  .filter(Boolean)
925
1024
  .join("\n");
926
- return successResponse(lines);
1025
+ return successResponse(lines, {
1026
+ id: template.id,
1027
+ name: template.name,
1028
+ subject: template.subject,
1029
+ to: template.to ?? [],
1030
+ cc: template.cc ?? [],
1031
+ body: template.body,
1032
+ });
927
1033
  }, "Error getting template"));
928
1034
  // --- delete-template ---
929
1035
  server.tool("delete-template", "Use when: permanently removing a saved email template by id.\nReturns: a confirmation that the template was deleted.\nDo not use when: you only want to view it (use get-template) or update it (use save-template with the existing id).\nSafety: destructive — removes the template from the on-disk store permanently. Require explicit user confirmation and use list-templates first to confirm the id.", {
@@ -933,7 +1039,7 @@ server.tool("delete-template", "Use when: permanently removing a saved email tem
933
1039
  if (!success) {
934
1040
  return errorResponse(`Template "${id}" not found`);
935
1041
  }
936
- return successResponse(`Template "${id}" deleted`);
1042
+ return successResponse(`Template "${id}" deleted`, { ok: true, id });
937
1043
  }, "Error deleting template"));
938
1044
  // --- use-template ---
939
1045
  server.tool("use-template", "Use when: composing a new draft from a saved template (by id), optionally overriding the recipients, subject, or body. Creates a draft in Mail.app for the user to review and send.\nReturns: a confirmation that a draft was created from the template.\nDo not use when: you want to inspect the template without composing (use get-template) or send immediately without a draft (use send-email).", {
@@ -947,7 +1053,7 @@ server.tool("use-template", "Use when: composing a new draft from a saved templa
947
1053
  if (!success) {
948
1054
  return errorResponse(`Failed to use template "${id}". Template not found or no recipients.`);
949
1055
  }
950
- return successResponse(`Draft created from template "${id}"`);
1056
+ return successResponse(`Draft created from template "${id}"`, { ok: true, id });
951
1057
  }, "Error using template"));
952
1058
  // =============================================================================
953
1059
  // Diagnostics Tools
@@ -963,7 +1069,7 @@ server.tool("health-check", "Use when: doing a quick check that Mail.app is reac
963
1069
  return ` ${icon} ${c.name}: ${c.message}`;
964
1070
  })
965
1071
  .join("\n");
966
- return successResponse(`${statusIcon} ${statusText}\n\n${checkLines}`);
1072
+ return successResponse(`${statusIcon} ${statusText}\n\n${checkLines}`, { ...result });
967
1073
  }, "Error running health check"));
968
1074
  // --- doctor ---
969
1075
  server.tool("doctor", "Use when: troubleshooting setup problems — diagnoses Mail.app automation permissions, account state, and the IMAP/SMTP backends with actionable remediation messages.\nReturns: a detailed diagnostic report (formatted text plus structured checks).\nDo not use when: you just want a quick up/down status (use health-check) or message counts (use get-mail-stats).", {}, withErrorHandling(async () => {
@@ -155,8 +155,20 @@ export declare function resolveImapConfigs(env?: NodeJS.ProcessEnv): ImapConfig[
155
155
  export declare function resolveImapConfig(env?: NodeJS.ProcessEnv, account?: string): ImapConfig;
156
156
  /** Map common (Gmail) mailbox names to their IMAP paths. */
157
157
  export declare function resolveMailboxPath(mailbox: string | undefined, mode: "search" | "list"): string;
158
- export declare function imapSearchMessages(args: ImapSearchArgs, deps?: ImapDeps): Promise<string>;
159
- export declare function imapListMessages(args: ImapSearchArgs, deps?: ImapDeps): Promise<string>;
158
+ /**
159
+ * Result of an IMAP search/list: the human text identical to before, plus the
160
+ * structured payload (messages + count) so callers can pass it straight to
161
+ * `successResponse(text, structured)` and emit `structuredContent` on the IMAP
162
+ * path the same way the AppleScript path does.
163
+ */
164
+ export interface ImapListResult {
165
+ text: string;
166
+ messages: Record<string, unknown>[];
167
+ count: number;
168
+ partial: boolean;
169
+ }
170
+ export declare function imapSearchMessages(args: ImapSearchArgs, deps?: ImapDeps): Promise<ImapListResult>;
171
+ export declare function imapListMessages(args: ImapSearchArgs, deps?: ImapDeps): Promise<ImapListResult>;
160
172
  /** Unread count via IMAP STATUS (UNSEEN). No mailbox → sum across all mailboxes. */
161
173
  export declare function imapUnreadCount(mailbox: string | undefined, deps?: ImapDeps): Promise<number>;
162
174
  export interface ImapMailboxInfo {
@@ -1 +1 @@
1
- {"version":3,"file":"imapClient.d.ts","sourceRoot":"","sources":["../../src/services/imapClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"imapClient.d.ts","sourceRoot":"","sources":["../../src/services/imapClient.ts"],"names":[],"mappings":"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"}
@@ -254,6 +254,25 @@ function formatRow(m, account, path) {
254
254
  // can route this row back to IMAP (Phase 3).
255
255
  return ` - ID: ${encodeImapId(account, path, m.uid)} | ${date} | ${subject} (from: ${from}) [${read}]`;
256
256
  }
257
+ /**
258
+ * JSON-friendly summary of an IMAP message for `structuredContent`, mirroring the
259
+ * AppleScript path's `messageSummary` shape so the search/list/thread tools emit
260
+ * the same structured payload regardless of backend (A1).
261
+ */
262
+ function structuredRow(m, account, path) {
263
+ const env = m.envelope ?? {};
264
+ return {
265
+ id: encodeImapId(account, path, m.uid),
266
+ subject: env.subject || "(no subject)",
267
+ sender: senderName(env.from),
268
+ dateReceived: env.date ? new Date(env.date).toISOString() : "",
269
+ isRead: m.flags?.has("\\Seen") ?? false,
270
+ isFlagged: m.flags?.has("\\Flagged") ?? false,
271
+ mailbox: path,
272
+ account,
273
+ hasAttachments: false,
274
+ };
275
+ }
257
276
  async function run(args, listMode, deps) {
258
277
  // Reads are idempotent → safe to retry once if a pooled connection is dead.
259
278
  // Route to the account named in the search args (C2 multi-account).
@@ -264,7 +283,12 @@ async function run(args, listMode, deps) {
264
283
  const found = await client.search(buildCriteria(args, listMode), { uid: true });
265
284
  const uids = Array.isArray(found) ? found : [];
266
285
  if (uids.length === 0) {
267
- return `No messages found via IMAP in "${path}" (account ${cfg.accountLabel}).`;
286
+ return {
287
+ text: `No messages found via IMAP in "${path}" (account ${cfg.accountLabel}).`,
288
+ messages: [],
289
+ count: 0,
290
+ partial: false,
291
+ };
268
292
  }
269
293
  const limit = args.limit ?? 50;
270
294
  const offset = args.offset ?? 0;
@@ -275,13 +299,18 @@ async function run(args, listMode, deps) {
275
299
  .slice(offset, offset + limit);
276
300
  const byUid = new Map();
277
301
  for await (const msg of client.fetch(newest.join(","), { envelope: true, flags: true }, { uid: true })) {
278
- byUid.set(msg.uid, formatRow(msg, cfg.accountLabel, path));
302
+ byUid.set(msg.uid, msg);
279
303
  }
280
- const rows = newest.map((u) => byUid.get(u)).filter((r) => Boolean(r));
304
+ const ordered = newest
305
+ .map((u) => byUid.get(u))
306
+ .filter((m) => m !== undefined);
307
+ const rows = ordered.map((m) => formatRow(m, cfg.accountLabel, path));
308
+ const messages = ordered.map((m) => structuredRow(m, cfg.accountLabel, path));
281
309
  const verb = listMode ? "listed" : "matched";
282
- return (`Found ${rows.length} message(s) via IMAP (server-side, account ${cfg.accountLabel}, mailbox "${path}"; ${uids.length} total ${verb}):\n` +
310
+ const text = `Found ${rows.length} message(s) via IMAP (server-side, account ${cfg.accountLabel}, mailbox "${path}"; ${uids.length} total ${verb}):\n` +
283
311
  rows.join("\n") +
284
- `\n\nNote: these IMAP IDs (imap:…) work with get-message and the message mutations (mark/flag/move/delete-message), which route back to IMAP.`);
312
+ `\n\nNote: these IMAP IDs (imap:…) work with get-message and the message mutations (mark/flag/move/delete-message), which route back to IMAP.`;
313
+ return { text, messages, count: messages.length, partial: false };
285
314
  }
286
315
  finally {
287
316
  lock.release();
@@ -12,5 +12,13 @@ export declare function routeMessage(id: string, opts: {
12
12
  apple: () => ToolResponse | Promise<ToolResponse>;
13
13
  ok: string;
14
14
  fail: string;
15
+ /** Optional ack payload attached as `structuredContent` on the IMAP success
16
+ * path, so a caller can verify the mutation programmatically regardless of
17
+ * backend (A1). The AppleScript path supplies its own via `apple`. */
18
+ structured?: Record<string, unknown>;
19
+ /** Derive `structuredContent` from the IMAP result on success (e.g. parse
20
+ * subject/body from `info`). Takes precedence over `structured`; return
21
+ * undefined to attach none. */
22
+ structuredFromResult?: (r: ImapOpResult) => Record<string, unknown> | undefined;
15
23
  }): Promise<ToolResponse>;
16
24
  //# sourceMappingURL=messageRouter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messageRouter.d.ts","sourceRoot":"","sources":["../../src/services/messageRouter.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvF,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,GACA,OAAO,CAAC,YAAY,CAAC,CAMvB"}
1
+ {"version":3,"file":"messageRouter.d.ts","sourceRoot":"","sources":["../../src/services/messageRouter.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvF,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb;;2EAEuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC;;oCAEgC;IAChC,oBAAoB,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CACjF,GACA,OAAO,CAAC,YAAY,CAAC,CAWvB"}
@@ -23,7 +23,9 @@ export function isImapId(id) {
23
23
  export async function routeMessage(id, opts) {
24
24
  if (decodeImapId(id)) {
25
25
  const r = await opts.imap();
26
- return r.success ? successResponse(r.info ?? opts.ok) : errorResponse(r.error ?? opts.fail);
26
+ return r.success
27
+ ? successResponse(r.info ?? opts.ok, opts.structuredFromResult ? opts.structuredFromResult(r) : opts.structured)
28
+ : errorResponse(r.error ?? opts.fail);
27
29
  }
28
30
  return opts.apple();
29
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.1.4",
3
+ "version": "2.2.0",
4
4
  "description": "MCP server for Apple Mail - read, search, send, and manage emails via Claude and other AI assistants",
5
5
  "type": "module",
6
6
  "main": "build/index.js",