apple-mail-mcp 2.10.5 → 2.10.6
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 +10 -1
- package/build/index.js +142 -82
- package/docs/IMAP-SETUP.md +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -485,6 +485,7 @@ for an explicitly-named IMAP account, never on an omitted account.
|
|
|
485
485
|
| `APPLE_MAIL_MCP_IMAP_ACCOUNTS` | No | — | JSON array of **additional** IMAP accounts for multi-account setups (see below) |
|
|
486
486
|
| `APPLE_MAIL_MCP_IMAP_IDLE` | No | `0` | Set `1` to enable IMAP IDLE push notifications (new-mail alerts) for every configured account |
|
|
487
487
|
| `APPLE_MAIL_MCP_IMAP_IDLE_MS` | No | `30000` | Idle timeout (ms) before a pooled IMAP connection is closed (`0` = never close) |
|
|
488
|
+
| `APPLE_MAIL_MCP_STATS_BUDGET_MS` | No | `25000` | Per-account wall-clock budget for `get-mail-stats` (minimum `1000`). Raise it for very large accounts |
|
|
488
489
|
|
|
489
490
|
**Multiple IMAP accounts (C2):** set `APPLE_MAIL_MCP_IMAP_ACCOUNTS` to a JSON array, e.g.
|
|
490
491
|
`[{"account":"Work","user":"me@co.com","host":"imap.co.com","keychainService":"imap.co.com"}]`.
|
|
@@ -1146,7 +1147,15 @@ Get mail statistics.
|
|
|
1146
1147
|
|-----------|------|----------|-------------|
|
|
1147
1148
|
| `account` | string | No | Limit to one account (uses fast IMAP `STATUS` when that account is IMAP-configured). Omit to merge across all accounts. |
|
|
1148
1149
|
|
|
1149
|
-
**Returns:** Total and per-account message/unread counts, plus recently received stats (24h, 7d, 30d).
|
|
1150
|
+
**Returns:** Total and per-account message/unread counts, plus recently received stats (24h, 7d, 30d). The scoped IMAP path also returns a `perMailbox` breakdown.
|
|
1151
|
+
|
|
1152
|
+
Gathering stats costs one IMAP `STATUS` per mailbox, and Gmail lists every label
|
|
1153
|
+
as a mailbox, so a large account is not instant. Accounts are counted
|
|
1154
|
+
**concurrently**, and each is bounded by `APPLE_MAIL_MCP_STATS_BUDGET_MS`
|
|
1155
|
+
(default `25000`). In the merged all-accounts path an account that fails or
|
|
1156
|
+
overruns is reported via `partial: true` + `failedAccounts` rather than being
|
|
1157
|
+
folded in as a silent zero; a scoped call to a single account returns an error
|
|
1158
|
+
naming the budget instead. Raise the budget if you have a very large account.
|
|
1150
1159
|
|
|
1151
1160
|
---
|
|
1152
1161
|
|
package/build/index.js
CHANGED
|
@@ -83202,6 +83202,14 @@ var server = new McpServer(
|
|
|
83202
83202
|
// logging capability lets the IMAP IDLE watcher push new-mail notifications (B5).
|
|
83203
83203
|
{ capabilities: { logging: {} } }
|
|
83204
83204
|
);
|
|
83205
|
+
function registerTool(name, config2, cb) {
|
|
83206
|
+
const { outputSchema, ...rest } = config2;
|
|
83207
|
+
return server.registerTool(
|
|
83208
|
+
name,
|
|
83209
|
+
outputSchema ? { ...rest, outputSchema: external_exports.object(outputSchema).passthrough() } : rest,
|
|
83210
|
+
cb
|
|
83211
|
+
);
|
|
83212
|
+
}
|
|
83205
83213
|
var mailManager = new AppleMailManager();
|
|
83206
83214
|
registerResourcesAndPrompts(server, mailManager);
|
|
83207
83215
|
async function hybridBatchCounts(ids, appleFn, imapFn) {
|
|
@@ -83224,7 +83232,7 @@ async function hybridBatchCounts(ids, appleFn, imapFn) {
|
|
|
83224
83232
|
}
|
|
83225
83233
|
return { success, fail, errors };
|
|
83226
83234
|
}
|
|
83227
|
-
|
|
83235
|
+
registerTool(
|
|
83228
83236
|
"search-messages",
|
|
83229
83237
|
{
|
|
83230
83238
|
description: "Use when: finding messages by query/sender/subject/date/read/flag filters and you need their ids for follow-up operations.\nReturns: matching messages with id, date, subject, sender, and read state (plus partial-coverage diagnostics when some mailboxes were skipped).\nDo not use when: you want a plain mailbox listing without filters (use list-messages), already have an id and want the body (use get-message), or want a whole conversation (use get-thread).\nPrefer this first to obtain the message ids that get-message/mark-as-read/delete-message/move-message and the batch tools require.",
|
|
@@ -83336,7 +83344,7 @@ ${messageList}${coverageBlock}`,
|
|
|
83336
83344
|
"Error searching messages"
|
|
83337
83345
|
)
|
|
83338
83346
|
);
|
|
83339
|
-
|
|
83347
|
+
registerTool(
|
|
83340
83348
|
"get-message",
|
|
83341
83349
|
{
|
|
83342
83350
|
description: `Use when: reading the full body of one message whose id you already have (numeric or imap:\u2026); set preferHtml to get the HTML body instead of plain text.
|
|
@@ -83404,7 +83412,7 @@ ${body}`, {
|
|
|
83404
83412
|
"Error retrieving message"
|
|
83405
83413
|
)
|
|
83406
83414
|
);
|
|
83407
|
-
|
|
83415
|
+
registerTool(
|
|
83408
83416
|
"get-thread",
|
|
83409
83417
|
{
|
|
83410
83418
|
description: "Use when: you have one message id and want the whole conversation it belongs to, oldest-first. With an imap: id it threads by References/Message-ID; otherwise it groups by normalized subject.\nReturns: the thread's normalized subject and its messages (id, date, subject, sender, read state).\nDo not use when: you only need the single message (use get-message) or are searching by arbitrary criteria (use search-messages).",
|
|
@@ -83523,7 +83531,7 @@ ${list}${coverageBlock}`,
|
|
|
83523
83531
|
);
|
|
83524
83532
|
}, "Error retrieving thread")
|
|
83525
83533
|
);
|
|
83526
|
-
|
|
83534
|
+
registerTool(
|
|
83527
83535
|
"list-messages",
|
|
83528
83536
|
{
|
|
83529
83537
|
description: "Use when: browsing a mailbox's recent messages (optionally filtered by sender or unread-only) with pagination via limit/offset, and you need their ids.\nReturns: messages with id, date, subject, and sender (plus partial-coverage diagnostics when some mailboxes were skipped).\nDo not use when: you have specific search criteria like subject/date/flags (use search-messages) or already have an id and want the body (use get-message).\nLike search-messages, use this to obtain the ids that read/mark/delete/move and batch tools require.",
|
|
@@ -83588,7 +83596,7 @@ ${messageList}${coverageBlock}`,
|
|
|
83588
83596
|
);
|
|
83589
83597
|
}, "Error listing messages")
|
|
83590
83598
|
);
|
|
83591
|
-
|
|
83599
|
+
registerTool(
|
|
83592
83600
|
"send-email",
|
|
83593
83601
|
{
|
|
83594
83602
|
description: "Use when: the user has explicitly confirmed they want to send a single email now to the given recipients (to/cc/bcc are arrays), optionally with attachments and a chosen transport.\nReturns: a confirmation naming the recipients and attachment count.\nDo not use when: the user wants to review first (use create-draft), is replying to or forwarding an existing message (use reply-to-message / forward-message), or wants per-recipient personalized copies (use send-serial-email).\nSafety: this SENDS real email immediately and it cannot be unsent \u2014 require explicit user confirmation of the exact recipients, subject, and body before calling. Prefer create-draft when there is any doubt.",
|
|
@@ -83639,7 +83647,7 @@ server.registerTool(
|
|
|
83639
83647
|
});
|
|
83640
83648
|
}, "Error sending email")
|
|
83641
83649
|
);
|
|
83642
|
-
|
|
83650
|
+
registerTool(
|
|
83643
83651
|
"send-serial-email",
|
|
83644
83652
|
{
|
|
83645
83653
|
description: "Use when: the user has confirmed a mail-merge \u2014 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 \u2014 require explicit user confirmation of the recipient list, the subject/body template, and the placeholder substitutions before calling.",
|
|
@@ -83695,7 +83703,7 @@ ${details}`,
|
|
|
83695
83703
|
}
|
|
83696
83704
|
}, "Error sending serial emails")
|
|
83697
83705
|
);
|
|
83698
|
-
|
|
83706
|
+
registerTool(
|
|
83699
83707
|
"create-draft",
|
|
83700
83708
|
{
|
|
83701
83709
|
description: "Use when: composing an email the user should review in Mail.app before sending \u2014 the safe default for any new message (to/cc/bcc are arrays, optional attachments).\nReturns: a confirmation that the draft was created, with recipients and attachment count.\nDo not use when: the user has already confirmed they want it sent now (use send-email).\nSafety: low risk \u2014 creates a draft only and sends nothing; the user must open Mail.app and send it themselves.",
|
|
@@ -83775,7 +83783,7 @@ async function sendForwardViaSmtp(id, to, body) {
|
|
|
83775
83783
|
if (result.success) return { sent: true };
|
|
83776
83784
|
return { sent: false, fallback: false, error: result.error ?? "unknown SMTP error" };
|
|
83777
83785
|
}
|
|
83778
|
-
|
|
83786
|
+
registerTool(
|
|
83779
83787
|
"reply-to-message",
|
|
83780
83788
|
{
|
|
83781
83789
|
description: "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 \u2014 require explicit user confirmation of the recipients and body, or pass send=false to let the user review.",
|
|
@@ -83812,7 +83820,7 @@ server.registerTool(
|
|
|
83812
83820
|
});
|
|
83813
83821
|
}, "Error replying to message")
|
|
83814
83822
|
);
|
|
83815
|
-
|
|
83823
|
+
registerTool(
|
|
83816
83824
|
"forward-message",
|
|
83817
83825
|
{
|
|
83818
83826
|
description: "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 \u2014 require explicit user confirmation of the recipients and any prepended body, or pass send=false to let the user review.",
|
|
@@ -83854,7 +83862,7 @@ server.registerTool(
|
|
|
83854
83862
|
);
|
|
83855
83863
|
}, "Error forwarding message")
|
|
83856
83864
|
);
|
|
83857
|
-
|
|
83865
|
+
registerTool(
|
|
83858
83866
|
"mark-as-read",
|
|
83859
83867
|
{
|
|
83860
83868
|
description: "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.",
|
|
@@ -83874,7 +83882,7 @@ server.registerTool(
|
|
|
83874
83882
|
"Error marking message as read"
|
|
83875
83883
|
)
|
|
83876
83884
|
);
|
|
83877
|
-
|
|
83885
|
+
registerTool(
|
|
83878
83886
|
"mark-as-unread",
|
|
83879
83887
|
{
|
|
83880
83888
|
description: "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.",
|
|
@@ -83894,7 +83902,7 @@ server.registerTool(
|
|
|
83894
83902
|
"Error marking message as unread"
|
|
83895
83903
|
)
|
|
83896
83904
|
);
|
|
83897
|
-
|
|
83905
|
+
registerTool(
|
|
83898
83906
|
"flag-message",
|
|
83899
83907
|
{
|
|
83900
83908
|
description: "Use when: flagging a single message (by id), optionally with a color (red/orange/yellow/green/blue/purple/gray).\nReturns: a confirmation that the message was flagged (and the color, when applied).\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.\nNote: the color is applied on both routes \u2014 AppleScript sets the flag index, IMAP writes the equivalent $MailFlagBit0/1/2 keywords Mail.app reads.",
|
|
@@ -83926,7 +83934,7 @@ server.registerTool(
|
|
|
83926
83934
|
});
|
|
83927
83935
|
}, "Error flagging message")
|
|
83928
83936
|
);
|
|
83929
|
-
|
|
83937
|
+
registerTool(
|
|
83930
83938
|
"unflag-message",
|
|
83931
83939
|
{
|
|
83932
83940
|
description: "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.",
|
|
@@ -83946,7 +83954,7 @@ server.registerTool(
|
|
|
83946
83954
|
"Error unflagging message"
|
|
83947
83955
|
)
|
|
83948
83956
|
);
|
|
83949
|
-
|
|
83957
|
+
registerTool(
|
|
83950
83958
|
"delete-message",
|
|
83951
83959
|
{
|
|
83952
83960
|
description: "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 \u2014 require explicit user confirmation, and search-messages/list-messages first to confirm you have the right id before deleting.",
|
|
@@ -83969,7 +83977,7 @@ server.registerTool(
|
|
|
83969
83977
|
"Error deleting message"
|
|
83970
83978
|
)
|
|
83971
83979
|
);
|
|
83972
|
-
|
|
83980
|
+
registerTool(
|
|
83973
83981
|
"move-message",
|
|
83974
83982
|
{
|
|
83975
83983
|
description: "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 \u2014 confirm the destination mailbox, and search-messages/list-messages first to confirm the id.",
|
|
@@ -83998,7 +84006,7 @@ server.registerTool(
|
|
|
83998
84006
|
"Error moving message"
|
|
83999
84007
|
)
|
|
84000
84008
|
);
|
|
84001
|
-
|
|
84009
|
+
registerTool(
|
|
84002
84010
|
"batch-delete-messages",
|
|
84003
84011
|
{
|
|
84004
84012
|
description: "Use when: deleting multiple messages in one call (1\u2013100 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 \u2014 require explicit user confirmation, and search-messages/list-messages first to confirm every id is correct before deleting.",
|
|
@@ -84023,7 +84031,7 @@ server.registerTool(
|
|
|
84023
84031
|
}
|
|
84024
84032
|
}, "Error batch deleting messages")
|
|
84025
84033
|
);
|
|
84026
|
-
|
|
84034
|
+
registerTool(
|
|
84027
84035
|
"batch-move-messages",
|
|
84028
84036
|
{
|
|
84029
84037
|
description: "Use when: moving multiple messages (1\u2013100 ids) into the same destination mailbox/folder in one call, e.g. bulk archiving.\nReturns: counts of how many were moved and how many failed.\nDo not use when: moving just one (use move-message) or deleting (use batch-delete-messages). Use list-mailboxes to confirm the destination name exists.\nSafety: moves many real messages at once \u2014 confirm the destination mailbox, and search-messages/list-messages first to confirm the ids.",
|
|
@@ -84056,7 +84064,7 @@ server.registerTool(
|
|
|
84056
84064
|
}
|
|
84057
84065
|
}, "Error batch moving messages")
|
|
84058
84066
|
);
|
|
84059
|
-
|
|
84067
|
+
registerTool(
|
|
84060
84068
|
"batch-mark-as-read",
|
|
84061
84069
|
{
|
|
84062
84070
|
description: "Use when: marking multiple messages (1\u2013100 ids) as read in one call.\nReturns: counts of how many were marked read and how many failed.\nDo not use when: marking just one (use mark-as-read) or marking unread (use batch-mark-as-unread). Get the ids from search-messages or list-messages first.",
|
|
@@ -84084,7 +84092,7 @@ server.registerTool(
|
|
|
84084
84092
|
}
|
|
84085
84093
|
}, "Error batch marking messages as read")
|
|
84086
84094
|
);
|
|
84087
|
-
|
|
84095
|
+
registerTool(
|
|
84088
84096
|
"batch-mark-as-unread",
|
|
84089
84097
|
{
|
|
84090
84098
|
description: "Use when: marking multiple messages (1\u2013100 ids) as unread in one call.\nReturns: counts of how many were marked unread and how many failed.\nDo not use when: marking just one (use mark-as-unread) or marking read (use batch-mark-as-read). Get the ids from search-messages or list-messages first.",
|
|
@@ -84115,7 +84123,7 @@ server.registerTool(
|
|
|
84115
84123
|
}
|
|
84116
84124
|
}, "Error batch marking messages as unread")
|
|
84117
84125
|
);
|
|
84118
|
-
|
|
84126
|
+
registerTool(
|
|
84119
84127
|
"batch-flag-messages",
|
|
84120
84128
|
{
|
|
84121
84129
|
description: "Use when: flagging multiple messages (1\u2013100 ids) in one call, optionally with a color (red/orange/yellow/green/blue/purple/gray).\nReturns: counts of how many were flagged and how many failed.\nDo not use when: flagging just one (use flag-message) or removing flags (use batch-unflag-messages). Get the ids from search-messages or list-messages first.\nNote: the color is applied on both routes \u2014 AppleScript sets the flag index, IMAP writes the equivalent $MailFlagBit0/1/2 keywords Mail.app reads \u2014 so a mixed batch of numeric and `imap:` ids all end up colored.",
|
|
@@ -84142,7 +84150,7 @@ server.registerTool(
|
|
|
84142
84150
|
}
|
|
84143
84151
|
}, "Error batch flagging messages")
|
|
84144
84152
|
);
|
|
84145
|
-
|
|
84153
|
+
registerTool(
|
|
84146
84154
|
"batch-unflag-messages",
|
|
84147
84155
|
{
|
|
84148
84156
|
description: "Use when: removing flags from multiple messages (1\u2013100 ids) in one call.\nReturns: counts of how many were unflagged and how many failed.\nDo not use when: unflagging just one (use unflag-message) or adding flags (use batch-flag-messages). Get the ids from search-messages or list-messages first.",
|
|
@@ -84170,7 +84178,7 @@ server.registerTool(
|
|
|
84170
84178
|
}
|
|
84171
84179
|
}, "Error batch unflagging messages")
|
|
84172
84180
|
);
|
|
84173
|
-
|
|
84181
|
+
registerTool(
|
|
84174
84182
|
"resolve-message-id",
|
|
84175
84183
|
{
|
|
84176
84184
|
description: "Use when: you have `imap:` message id(s) and genuinely need the numeric Mail.app id(s) \u2014 e.g. for reply-to-message/forward-message, which are numeric-id only. NOTE: as of 2.10.0 you no longer need this to apply a flag COLOR \u2014 flag-message/batch-flag-messages write the color over IMAP directly via Mail.app's $MailFlagBit0/1/2 keywords, so a smart mailbox keyed on flag color matches an IMAP-flagged message. Each imap: id is resolved via its RFC822 Message-ID.\nReturns: for each input id, its `numericId` (the AppleScript id) or null when it can't be resolved, plus the `messageId` used; and a `resolvedCount`.\nDo not use when: your ids are already numeric (they pass straight through), or you don't need a color \u2014 flag/move/mark tools operate on `imap:` ids directly.",
|
|
@@ -84208,7 +84216,7 @@ server.registerTool(
|
|
|
84208
84216
|
);
|
|
84209
84217
|
}, "Error resolving message ids")
|
|
84210
84218
|
);
|
|
84211
|
-
|
|
84219
|
+
registerTool(
|
|
84212
84220
|
"list-attachments",
|
|
84213
84221
|
{
|
|
84214
84222
|
description: "Use when: enumerating a message's attachments (by id) to discover their names, MIME types, and sizes \u2014 typically before saving or fetching one.\nReturns: each attachment's name, MIME type, and size, plus a count.\nDo not use when: you want the bytes (use fetch-attachment for inline base64, or save-attachment to write to disk). Get the message id from search-messages or list-messages first.",
|
|
@@ -84241,7 +84249,7 @@ ${attachmentList}`,
|
|
|
84241
84249
|
);
|
|
84242
84250
|
}, "Error listing attachments")
|
|
84243
84251
|
);
|
|
84244
|
-
|
|
84252
|
+
registerTool(
|
|
84245
84253
|
"save-attachment",
|
|
84246
84254
|
{
|
|
84247
84255
|
description: "Use when: writing one of a message's attachments to disk, by message id and attachmentName, into the savePath directory (saved as savePath/attachmentName).\nReturns: a confirmation of the saved file path.\nDo not use when: you don't know the attachment name (use list-attachments first) or want the bytes inline rather than on disk (use fetch-attachment).\nSafety: writes a file to disk \u2014 savePath must be a directory inside the configured allowed roots, and attachmentName may not contain path separators or '..'; calls outside those constraints are rejected.",
|
|
@@ -84289,7 +84297,7 @@ server.registerTool(
|
|
|
84289
84297
|
});
|
|
84290
84298
|
}, "Error saving attachment")
|
|
84291
84299
|
);
|
|
84292
|
-
|
|
84300
|
+
registerTool(
|
|
84293
84301
|
"fetch-attachment",
|
|
84294
84302
|
{
|
|
84295
84303
|
description: "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).",
|
|
@@ -84329,7 +84337,7 @@ ${r.base64}`,
|
|
|
84329
84337
|
);
|
|
84330
84338
|
}, "Error fetching attachment")
|
|
84331
84339
|
);
|
|
84332
|
-
|
|
84340
|
+
registerTool(
|
|
84333
84341
|
"list-mailboxes",
|
|
84334
84342
|
{
|
|
84335
84343
|
description: "Use when: discovering the mailbox/folder names (and unread/message counts) available in an account, e.g. before moving messages or searching a specific mailbox.\nReturns: each mailbox's name with its unread (and, for IMAP, total message) count, plus a count.\nDo not use when: you want the messages inside a mailbox (use list-messages or search-messages) or the list of accounts (use list-accounts).",
|
|
@@ -84402,7 +84410,7 @@ ${list}`, structured2);
|
|
|
84402
84410
|
${mailboxList}`, structured);
|
|
84403
84411
|
}, "Error listing mailboxes")
|
|
84404
84412
|
);
|
|
84405
|
-
|
|
84413
|
+
registerTool(
|
|
84406
84414
|
"get-unread-count",
|
|
84407
84415
|
{
|
|
84408
84416
|
description: "Use when: you only need the number of unread messages \u2014 INBOX by default, or scoped to one mailbox and/or account \u2014 without listing the messages themselves.\nReturns: the unread count for the requested scope (INBOX when no mailbox is given). If a source cannot be read the result carries `partial: true` + `failedAccounts`, and a total AppleScript failure returns an ERROR \u2014 a plain count is never a disguised transport failure.\nDo not use when: you need the actual unread messages and their ids (use list-messages with unreadOnly, or search-messages with isRead=false) or broader totals across every mailbox (use get-mail-stats).",
|
|
@@ -84466,7 +84474,7 @@ server.registerTool(
|
|
|
84466
84474
|
});
|
|
84467
84475
|
}, "Error getting unread count")
|
|
84468
84476
|
);
|
|
84469
|
-
|
|
84477
|
+
registerTool(
|
|
84470
84478
|
"create-mailbox",
|
|
84471
84479
|
{
|
|
84472
84480
|
description: "Use when: creating a new mailbox/folder in an account.\nReturns: a confirmation that the mailbox was created.\nDo not use when: renaming an existing one (use rename-mailbox) or deleting one (use delete-mailbox). Use list-mailboxes to see what already exists.\nSafety: creates a real folder in the mail account \u2014 confirm the name and target account first.",
|
|
@@ -84492,7 +84500,7 @@ server.registerTool(
|
|
|
84492
84500
|
return successResponse(`Mailbox "${name}" created`, { ok: true, name });
|
|
84493
84501
|
}, "Error creating mailbox")
|
|
84494
84502
|
);
|
|
84495
|
-
|
|
84503
|
+
registerTool(
|
|
84496
84504
|
"delete-mailbox",
|
|
84497
84505
|
{
|
|
84498
84506
|
description: "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 \u2014 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.",
|
|
@@ -84518,7 +84526,7 @@ server.registerTool(
|
|
|
84518
84526
|
return successResponse(`Mailbox "${name}" deleted`, { ok: true, name });
|
|
84519
84527
|
}, "Error deleting mailbox")
|
|
84520
84528
|
);
|
|
84521
|
-
|
|
84529
|
+
registerTool(
|
|
84522
84530
|
"rename-mailbox",
|
|
84523
84531
|
{
|
|
84524
84532
|
description: "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 \u2014 confirm oldName matches exactly (case-sensitive) before calling.",
|
|
@@ -84556,7 +84564,7 @@ server.registerTool(
|
|
|
84556
84564
|
});
|
|
84557
84565
|
}, "Error renaming mailbox")
|
|
84558
84566
|
);
|
|
84559
|
-
|
|
84567
|
+
registerTool(
|
|
84560
84568
|
"list-smart-mailboxes",
|
|
84561
84569
|
{
|
|
84562
84570
|
description: "Use when: listing Apple Mail smart mailboxes (criteria-based virtual views), including on German-localized macOS where AppleScript's smart-mailbox terms do not compile.\nReturns: each smart mailbox's name and a short criteria summary.\nDo not use when: listing real folders/mailboxes (use list-mailboxes).",
|
|
@@ -84589,7 +84597,7 @@ ${lines}`, {
|
|
|
84589
84597
|
});
|
|
84590
84598
|
}, "Error listing smart mailboxes")
|
|
84591
84599
|
);
|
|
84592
|
-
|
|
84600
|
+
registerTool(
|
|
84593
84601
|
"create-smart-mailbox",
|
|
84594
84602
|
{
|
|
84595
84603
|
description: "Use when: creating an Apple Mail smart mailbox (a criteria-based virtual view) that matches a sender, subject, or body substring \u2014 works on German-localized macOS where AppleScript's smart-mailbox terms fail.\nReturns: confirmation of creation, or a note that a smart mailbox with that name already existed.\nDo not use when: creating a real folder (use create-mailbox).\nSafety: edits Apple Mail's SyncedSmartMailboxes.plist directly. It backs the file up (.bak) and writes atomically, and never rewrites your existing smart mailboxes. It does not quit Mail \u2014 quit Mail first for reliable results, since a running Mail may not show the new smart mailbox until relaunched and can overwrite plist edits it did not make.",
|
|
@@ -84632,7 +84640,7 @@ server.registerTool(
|
|
|
84632
84640
|
});
|
|
84633
84641
|
}, "Error creating smart mailbox")
|
|
84634
84642
|
);
|
|
84635
|
-
|
|
84643
|
+
registerTool(
|
|
84636
84644
|
"delete-smart-mailbox",
|
|
84637
84645
|
{
|
|
84638
84646
|
description: "Use when: deleting an Apple Mail smart mailbox (virtual view) by name.\nReturns: confirmation of deletion.\nDo not use when: deleting a real folder (use delete-mailbox) or messages (use delete-message / batch-delete-messages).\nSafety: destructive \u2014 removes the smart mailbox from Apple Mail's SyncedSmartMailboxes.plist. It backs the file up (.bak) and writes atomically, preserving every other smart mailbox, but the removal is not undoable in-app. Confirm the exact name with list-smart-mailboxes first, and quit Mail first for reliable results.",
|
|
@@ -84655,7 +84663,7 @@ server.registerTool(
|
|
|
84655
84663
|
});
|
|
84656
84664
|
}, "Error deleting smart mailbox")
|
|
84657
84665
|
);
|
|
84658
|
-
|
|
84666
|
+
registerTool(
|
|
84659
84667
|
"create-newsletter-smart-mailboxes",
|
|
84660
84668
|
{
|
|
84661
84669
|
description: `Use when: auto-discovering newsletter/bulk senders in your INBOX(es) and (optionally) creating a dedicated smart mailbox per sender (named "NL: <sender>"). Defaults to a safe dry run that only proposes.
|
|
@@ -84685,7 +84693,7 @@ ${lines || " (none met the threshold)"}`,
|
|
|
84685
84693
|
);
|
|
84686
84694
|
}, "Error creating newsletter smart mailboxes")
|
|
84687
84695
|
);
|
|
84688
|
-
|
|
84696
|
+
registerTool(
|
|
84689
84697
|
"list-accounts",
|
|
84690
84698
|
{
|
|
84691
84699
|
description: "Use when: discovering the configured Mail accounts (e.g. iCloud, Gmail) so you can pass an exact account name to other tools.\nReturns: the account names and a count. If the AppleScript transport fails (timeout / wedged Mail / missing Automation grant) this returns an ERROR rather than an empty list \u2014 an empty list always means Mail really has no accounts.\nDo not use when: you want the folders within an account (use list-mailboxes) or messages (use list-messages / search-messages).",
|
|
@@ -84713,7 +84721,7 @@ server.registerTool(
|
|
|
84713
84721
|
${accountList}`, structured);
|
|
84714
84722
|
}, "Error listing accounts")
|
|
84715
84723
|
);
|
|
84716
|
-
|
|
84724
|
+
registerTool(
|
|
84717
84725
|
"list-rules",
|
|
84718
84726
|
{
|
|
84719
84727
|
description: "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).",
|
|
@@ -84737,7 +84745,7 @@ server.registerTool(
|
|
|
84737
84745
|
${ruleList}`, structured);
|
|
84738
84746
|
}, "Error listing rules")
|
|
84739
84747
|
);
|
|
84740
|
-
|
|
84748
|
+
registerTool(
|
|
84741
84749
|
"enable-rule",
|
|
84742
84750
|
{
|
|
84743
84751
|
description: "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.",
|
|
@@ -84758,7 +84766,7 @@ server.registerTool(
|
|
|
84758
84766
|
return successResponse(`Rule "${name}" enabled`, { ok: true, name, enabled: true });
|
|
84759
84767
|
}, "Error enabling rule")
|
|
84760
84768
|
);
|
|
84761
|
-
|
|
84769
|
+
registerTool(
|
|
84762
84770
|
"disable-rule",
|
|
84763
84771
|
{
|
|
84764
84772
|
description: "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.",
|
|
@@ -84779,7 +84787,7 @@ server.registerTool(
|
|
|
84779
84787
|
return successResponse(`Rule "${name}" disabled`, { ok: true, name, enabled: false });
|
|
84780
84788
|
}, "Error disabling rule")
|
|
84781
84789
|
);
|
|
84782
|
-
|
|
84790
|
+
registerTool(
|
|
84783
84791
|
"create-rule",
|
|
84784
84792
|
{
|
|
84785
84793
|
description: "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 \u2014 confirm the conditions and actions with the user before calling.",
|
|
@@ -84821,7 +84829,7 @@ server.registerTool(
|
|
|
84821
84829
|
);
|
|
84822
84830
|
}, "Error creating rule")
|
|
84823
84831
|
);
|
|
84824
|
-
|
|
84832
|
+
registerTool(
|
|
84825
84833
|
"delete-rule",
|
|
84826
84834
|
{
|
|
84827
84835
|
description: "Use when: permanently removing a Mail rule by name.\nReturns: a confirmation that the rule was deleted.\nDo not use when: you only want to pause it (use disable-rule) or create one (use create-rule).\nSafety: destructive \u2014 the rule is removed permanently. Require explicit user confirmation and use list-rules first to confirm the exact name.",
|
|
@@ -84841,7 +84849,7 @@ server.registerTool(
|
|
|
84841
84849
|
return successResponse(`Rule "${name}" deleted`, { name, deleted: true });
|
|
84842
84850
|
}, "Error deleting rule")
|
|
84843
84851
|
);
|
|
84844
|
-
|
|
84852
|
+
registerTool(
|
|
84845
84853
|
"search-contacts",
|
|
84846
84854
|
{
|
|
84847
84855
|
description: "Use when: looking up a person in Contacts by name, organization, nickname, or email to find their email address(es)/phone(s) before composing or sending mail. Reads the macOS Contacts database directly (needs Full Disk Access; does NOT require Contacts.app to be running or an Automation / Apple-Events grant).\nReturns: matching contacts with their names, email addresses, and phone numbers.\nDo not use when: searching email messages (use search-messages) \u2014 this queries Contacts, not the mailbox.",
|
|
@@ -84871,7 +84879,7 @@ server.registerTool(
|
|
|
84871
84879
|
${contactList}`, structured);
|
|
84872
84880
|
}, "Error searching contacts")
|
|
84873
84881
|
);
|
|
84874
|
-
|
|
84882
|
+
registerTool(
|
|
84875
84883
|
"save-template",
|
|
84876
84884
|
{
|
|
84877
84885
|
description: "Use when: creating a reusable email template (name, subject, body, optional default to/cc), or updating one by passing its existing id. Subject/body may contain placeholders for later use.\nReturns: the saved template's name and id (reuse the id with use-template / get-template / delete-template).\nDo not use when: composing a one-off message (use create-draft / send-email) or filling in a template to send (use use-template).\nSafety: writes the template to the on-disk templates store (APPLE_MAIL_MCP_TEMPLATES_FILE) and persists across restarts; passing an existing id overwrites that template.",
|
|
@@ -84898,7 +84906,7 @@ server.registerTool(
|
|
|
84898
84906
|
});
|
|
84899
84907
|
}, "Error saving template")
|
|
84900
84908
|
);
|
|
84901
|
-
|
|
84909
|
+
registerTool(
|
|
84902
84910
|
"list-templates",
|
|
84903
84911
|
{
|
|
84904
84912
|
description: "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).",
|
|
@@ -84922,7 +84930,7 @@ server.registerTool(
|
|
|
84922
84930
|
${templateList}`, structured);
|
|
84923
84931
|
}, "Error listing templates")
|
|
84924
84932
|
);
|
|
84925
|
-
|
|
84933
|
+
registerTool(
|
|
84926
84934
|
"get-template",
|
|
84927
84935
|
{
|
|
84928
84936
|
description: "Use when: reading the full contents of one saved template by id \u2014 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).",
|
|
@@ -84961,7 +84969,7 @@ ${template.body}`
|
|
|
84961
84969
|
});
|
|
84962
84970
|
}, "Error getting template")
|
|
84963
84971
|
);
|
|
84964
|
-
|
|
84972
|
+
registerTool(
|
|
84965
84973
|
"delete-template",
|
|
84966
84974
|
{
|
|
84967
84975
|
description: "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 \u2014 removes the template from the on-disk store permanently. Require explicit user confirmation and use list-templates first to confirm the id.",
|
|
@@ -84981,7 +84989,7 @@ server.registerTool(
|
|
|
84981
84989
|
return successResponse(`Template "${id}" deleted`, { ok: true, id });
|
|
84982
84990
|
}, "Error deleting template")
|
|
84983
84991
|
);
|
|
84984
|
-
|
|
84992
|
+
registerTool(
|
|
84985
84993
|
"use-template",
|
|
84986
84994
|
{
|
|
84987
84995
|
description: "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).",
|
|
@@ -85005,7 +85013,7 @@ server.registerTool(
|
|
|
85005
85013
|
return successResponse(`Draft created from template "${id}"`, { ok: true, id });
|
|
85006
85014
|
}, "Error using template")
|
|
85007
85015
|
);
|
|
85008
|
-
|
|
85016
|
+
registerTool(
|
|
85009
85017
|
"health-check",
|
|
85010
85018
|
{
|
|
85011
85019
|
description: "Use when: doing a quick check that Mail.app is reachable and the server's basic checks pass.\nReturns: an overall healthy/unhealthy status with a pass/fail line per check.\nDo not use when: you need detailed permission/account/IMAP/SMTP diagnostics with remediation steps (use doctor).",
|
|
@@ -85028,7 +85036,7 @@ server.registerTool(
|
|
|
85028
85036
|
${checkLines}`, { ...result });
|
|
85029
85037
|
}, "Error running health check")
|
|
85030
85038
|
);
|
|
85031
|
-
|
|
85039
|
+
registerTool(
|
|
85032
85040
|
"doctor",
|
|
85033
85041
|
{
|
|
85034
85042
|
description: "Use when: troubleshooting setup problems \u2014 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).",
|
|
@@ -85043,7 +85051,7 @@ server.registerTool(
|
|
|
85043
85051
|
return successResponse(formatDoctorReport(report), { ...report });
|
|
85044
85052
|
}, "Error running doctor")
|
|
85045
85053
|
);
|
|
85046
|
-
|
|
85054
|
+
registerTool(
|
|
85047
85055
|
"get-mail-stats",
|
|
85048
85056
|
{
|
|
85049
85057
|
description: "Use when: you want aggregate mailbox statistics \u2014 total and unread message counts, recently-received counts (last 24h/7d/30d), and (for the all-accounts path) a per-account breakdown.\nReturns: totals, unread counts, recent-activity counts, and per-account figures.\nDo not use when: you only need a single unread number (use get-unread-count) or want to list the messages themselves (use list-messages / search-messages).",
|
|
@@ -85056,12 +85064,42 @@ server.registerTool(
|
|
|
85056
85064
|
totalUnread: external_exports.number().optional(),
|
|
85057
85065
|
accounts: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
85058
85066
|
recentlyReceived: external_exports.object({}).passthrough().optional(),
|
|
85059
|
-
recent: external_exports.object({}).passthrough().optional()
|
|
85067
|
+
recent: external_exports.object({}).passthrough().optional(),
|
|
85068
|
+
// The scoped IMAP path spreads an ImapStats, which carries per-mailbox
|
|
85069
|
+
// STATUS rows. Declared so the shape is documented rather than merely
|
|
85070
|
+
// tolerated by the permissive advertisement (#135).
|
|
85071
|
+
perMailbox: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
85072
|
+
partial: external_exports.boolean().optional(),
|
|
85073
|
+
failedAccounts: external_exports.array(external_exports.string()).optional()
|
|
85060
85074
|
}
|
|
85061
85075
|
},
|
|
85062
85076
|
withErrorHandling(async ({ account }) => {
|
|
85077
|
+
const budgetMs = Math.max(1e3, Number(process.env.APPLE_MAIL_MCP_STATS_BUDGET_MS ?? 25e3));
|
|
85078
|
+
const withBudget = async (work, label) => {
|
|
85079
|
+
let timer;
|
|
85080
|
+
try {
|
|
85081
|
+
return await Promise.race([
|
|
85082
|
+
work,
|
|
85083
|
+
new Promise((_, reject) => {
|
|
85084
|
+
timer = setTimeout(
|
|
85085
|
+
() => reject(new Error(`${label} timed out after ${budgetMs}ms`)),
|
|
85086
|
+
budgetMs
|
|
85087
|
+
);
|
|
85088
|
+
})
|
|
85089
|
+
]);
|
|
85090
|
+
} finally {
|
|
85091
|
+
if (timer) clearTimeout(timer);
|
|
85092
|
+
}
|
|
85093
|
+
};
|
|
85063
85094
|
if (account !== void 0 && isImapAccount(account)) {
|
|
85064
|
-
|
|
85095
|
+
let s;
|
|
85096
|
+
try {
|
|
85097
|
+
s = await withBudget(imapMailStats({ account }), `IMAP mail-stats for "${account}"`);
|
|
85098
|
+
} catch (e) {
|
|
85099
|
+
return errorResponse(
|
|
85100
|
+
`Could not read mail statistics for "${account}": ${String(e)}. Gathering stats costs one IMAP STATUS per mailbox, so a very large account can exceed the ${budgetMs}ms budget \u2014 raise APPLE_MAIL_MCP_STATS_BUDGET_MS, or run the "doctor" tool if the connection itself is the problem.`
|
|
85101
|
+
);
|
|
85102
|
+
}
|
|
85065
85103
|
const lines2 = [
|
|
85066
85104
|
`\u{1F4CA} Mail Statistics \u2014 ${account} (IMAP)`,
|
|
85067
85105
|
`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
|
|
@@ -85081,40 +85119,55 @@ server.registerTool(
|
|
|
85081
85119
|
const recent = { last24h: 0, last7d: 0, last30d: 0 };
|
|
85082
85120
|
const perAccount = [];
|
|
85083
85121
|
const sources = planCountSources(mailManager.listAccounts(), resolveImapConfigs());
|
|
85084
|
-
|
|
85085
|
-
|
|
85122
|
+
const failedAccounts = [];
|
|
85123
|
+
const settled = await Promise.all(
|
|
85124
|
+
sources.filter((s) => s.kind === "imap").map(async (src) => {
|
|
85086
85125
|
try {
|
|
85087
|
-
const
|
|
85088
|
-
|
|
85089
|
-
|
|
85090
|
-
|
|
85091
|
-
|
|
85092
|
-
recent.last30d += s.recent.last30d;
|
|
85093
|
-
perAccount.push({
|
|
85094
|
-
name: src.label,
|
|
85095
|
-
totalMessages: s.totalMessages,
|
|
85096
|
-
unreadMessages: s.totalUnread,
|
|
85097
|
-
backend: "imap"
|
|
85098
|
-
});
|
|
85126
|
+
const stats2 = await withBudget(
|
|
85127
|
+
imapMailStats({ config: src.config }),
|
|
85128
|
+
`IMAP mail-stats for "${src.label}"`
|
|
85129
|
+
);
|
|
85130
|
+
return { label: src.label, stats: stats2 };
|
|
85099
85131
|
} catch (e) {
|
|
85100
85132
|
console.error(`IMAP mail-stats failed for "${src.label}": ${String(e)}`);
|
|
85133
|
+
return { label: src.label, stats: void 0 };
|
|
85101
85134
|
}
|
|
85102
|
-
}
|
|
85103
|
-
|
|
85104
|
-
|
|
85105
|
-
|
|
85106
|
-
|
|
85107
|
-
|
|
85108
|
-
}
|
|
85109
|
-
totalMessages += m;
|
|
85110
|
-
totalUnread += u;
|
|
85111
|
-
perAccount.push({
|
|
85112
|
-
name: src.label,
|
|
85113
|
-
totalMessages: m,
|
|
85114
|
-
unreadMessages: u,
|
|
85115
|
-
backend: "applescript"
|
|
85116
|
-
});
|
|
85135
|
+
})
|
|
85136
|
+
);
|
|
85137
|
+
for (const r of settled) {
|
|
85138
|
+
if (!r.stats) {
|
|
85139
|
+
failedAccounts.push(r.label);
|
|
85140
|
+
continue;
|
|
85117
85141
|
}
|
|
85142
|
+
const s = r.stats;
|
|
85143
|
+
totalMessages += s.totalMessages;
|
|
85144
|
+
totalUnread += s.totalUnread;
|
|
85145
|
+
recent.last24h += s.recent.last24h;
|
|
85146
|
+
recent.last7d += s.recent.last7d;
|
|
85147
|
+
recent.last30d += s.recent.last30d;
|
|
85148
|
+
perAccount.push({
|
|
85149
|
+
name: r.label,
|
|
85150
|
+
totalMessages: s.totalMessages,
|
|
85151
|
+
unreadMessages: s.totalUnread,
|
|
85152
|
+
backend: "imap"
|
|
85153
|
+
});
|
|
85154
|
+
}
|
|
85155
|
+
for (const src of sources) {
|
|
85156
|
+
if (src.kind === "imap") continue;
|
|
85157
|
+
let m = 0;
|
|
85158
|
+
let u = 0;
|
|
85159
|
+
for (const mb of mailManager.listMailboxes(src.account.name)) {
|
|
85160
|
+
m += mb.messageCount;
|
|
85161
|
+
u += mb.unreadCount;
|
|
85162
|
+
}
|
|
85163
|
+
totalMessages += m;
|
|
85164
|
+
totalUnread += u;
|
|
85165
|
+
perAccount.push({
|
|
85166
|
+
name: src.label,
|
|
85167
|
+
totalMessages: m,
|
|
85168
|
+
unreadMessages: u,
|
|
85169
|
+
backend: "applescript"
|
|
85170
|
+
});
|
|
85118
85171
|
}
|
|
85119
85172
|
const lines2 = [
|
|
85120
85173
|
`\u{1F4CA} Mail Statistics (merged: IMAP + AppleScript)`,
|
|
@@ -85132,11 +85185,18 @@ server.registerTool(
|
|
|
85132
85185
|
(a) => ` ${a.name}: ${a.totalMessages} messages (${a.unreadMessages} unread) [${a.backend}]`
|
|
85133
85186
|
)
|
|
85134
85187
|
];
|
|
85188
|
+
if (failedAccounts.length > 0) {
|
|
85189
|
+
lines2.push(
|
|
85190
|
+
``,
|
|
85191
|
+
`\u26A0\uFE0F PARTIAL: ${failedAccounts.length} account(s) could not be read (${failedAccounts.join(", ")}), so the real totals are higher. They either failed or exceeded the ${budgetMs}ms budget \u2014 raise APPLE_MAIL_MCP_STATS_BUDGET_MS if an account is simply large, or run the "doctor" tool to check the connection.`
|
|
85192
|
+
);
|
|
85193
|
+
}
|
|
85135
85194
|
return successResponse(lines2.join("\n"), {
|
|
85136
85195
|
totalMessages,
|
|
85137
85196
|
totalUnread,
|
|
85138
85197
|
accounts: perAccount,
|
|
85139
|
-
recent
|
|
85198
|
+
recent,
|
|
85199
|
+
...failedAccounts.length > 0 ? { partial: true, failedAccounts } : {}
|
|
85140
85200
|
});
|
|
85141
85201
|
}
|
|
85142
85202
|
const stats = mailManager.getMailStats();
|
|
@@ -85164,7 +85224,7 @@ server.registerTool(
|
|
|
85164
85224
|
return successResponse(lines.join("\n"), { ...stats });
|
|
85165
85225
|
}, "Error getting mail statistics")
|
|
85166
85226
|
);
|
|
85167
|
-
|
|
85227
|
+
registerTool(
|
|
85168
85228
|
"get-sync-status",
|
|
85169
85229
|
{
|
|
85170
85230
|
description: "Use when: checking whether Mail.app is running and actively syncing, e.g. to explain why new mail hasn't appeared yet.\nReturns: whether Mail.app is running and whether sync activity was detected.\nDo not use when: you need message counts (use get-mail-stats) or a full setup diagnosis (use doctor).",
|
package/docs/IMAP-SETUP.md
CHANGED
|
@@ -343,6 +343,7 @@ GUI is ignoring.
|
|
|
343
343
|
| `APPLE_MAIL_MCP_IMAP_ACCOUNTS` | JSON array of additional accounts (multi-account). |
|
|
344
344
|
| `APPLE_MAIL_MCP_IMAP_IDLE` | `1` to enable IMAP IDLE new-mail push. |
|
|
345
345
|
| `APPLE_MAIL_MCP_IMAP_IDLE_MS` | Pooled-connection idle timeout in ms (default `30000`; `0` = never close). |
|
|
346
|
+
| `APPLE_MAIL_MCP_STATS_BUDGET_MS` | Per-account wall-clock budget for `get-mail-stats` in ms (default `25000`, minimum `1000`). |
|
|
346
347
|
| `APPLE_MAIL_MCP_SMTP_HOST` | SMTP host; setting it enables `transport:"smtp"`. |
|
|
347
348
|
| `APPLE_MAIL_MCP_SMTP_PORT` | SMTP port (`465` if secure, else `587`). |
|
|
348
349
|
| `APPLE_MAIL_MCP_SMTP_SECURE` | `true` for implicit TLS (465); else STARTTLS. |
|
package/package.json
CHANGED