apple-mail-mcp 2.10.3 → 2.10.4
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/build/index.js +75 -9
- package/package.json +1 -1
package/build/index.js
CHANGED
|
@@ -76842,6 +76842,12 @@ var AppleMailManager = class {
|
|
|
76842
76842
|
};
|
|
76843
76843
|
/** Cache TTL in milliseconds (60 seconds). */
|
|
76844
76844
|
CACHE_TTL_MS = 6e4;
|
|
76845
|
+
/**
|
|
76846
|
+
* Last AppleScript transport error from an account/count read, or null when the
|
|
76847
|
+
* last one succeeded. Lets a tool report "the transport failed" instead of
|
|
76848
|
+
* presenting a fallback zero/empty as a real answer. (#130)
|
|
76849
|
+
*/
|
|
76850
|
+
lastAccountsError = null;
|
|
76845
76851
|
/**
|
|
76846
76852
|
* Remembers where each message id was last seen: id → {account, mailbox}.
|
|
76847
76853
|
*
|
|
@@ -76877,6 +76883,10 @@ var AppleMailManager = class {
|
|
|
76877
76883
|
return this.cache.accounts.data;
|
|
76878
76884
|
}
|
|
76879
76885
|
const accounts = this.fetchAccounts();
|
|
76886
|
+
if (accounts === null) {
|
|
76887
|
+
return this.cache.accounts?.data ?? [];
|
|
76888
|
+
}
|
|
76889
|
+
this.lastAccountsError = null;
|
|
76880
76890
|
this.cache.accounts = { data: accounts, expiry: now + this.CACHE_TTL_MS };
|
|
76881
76891
|
return accounts;
|
|
76882
76892
|
}
|
|
@@ -78683,6 +78693,7 @@ var AppleMailManager = class {
|
|
|
78683
78693
|
const result = executeAppleScript(script, { timeoutMs: 6e4 });
|
|
78684
78694
|
if (!result.success) {
|
|
78685
78695
|
console.error(`Failed to get unread count: ${result.error}`);
|
|
78696
|
+
this.lastAccountsError = result.error ?? "AppleScript transport failed";
|
|
78686
78697
|
return 0;
|
|
78687
78698
|
}
|
|
78688
78699
|
return parseInt(result.output) || 0;
|
|
@@ -79208,9 +79219,38 @@ end tell`;
|
|
|
79208
79219
|
listAccounts() {
|
|
79209
79220
|
return this.getCachedAccounts();
|
|
79210
79221
|
}
|
|
79222
|
+
/**
|
|
79223
|
+
* listAccounts() plus whether the underlying AppleScript read actually worked.
|
|
79224
|
+
*
|
|
79225
|
+
* `failed: true` means the list is a fallback (stale cache or empty) because the
|
|
79226
|
+
* transport errored — NOT that Mail has no accounts. (#130)
|
|
79227
|
+
*/
|
|
79228
|
+
listAccountsChecked() {
|
|
79229
|
+
this.lastAccountsError = null;
|
|
79230
|
+
const accounts = this.getCachedAccounts();
|
|
79231
|
+
const error2 = this.lastAccountsError;
|
|
79232
|
+
return error2 ? { accounts, failed: true, error: error2 } : { accounts, failed: false };
|
|
79233
|
+
}
|
|
79234
|
+
/**
|
|
79235
|
+
* getUnreadCount() plus whether the AppleScript read actually worked.
|
|
79236
|
+
*
|
|
79237
|
+
* On failure the count is `null` rather than 0, so a caller can never mistake a
|
|
79238
|
+
* wedged transport for an empty inbox. (#130)
|
|
79239
|
+
*/
|
|
79240
|
+
getUnreadCountChecked(mailbox, account) {
|
|
79241
|
+
this.lastAccountsError = null;
|
|
79242
|
+
const count = this.getUnreadCount(mailbox, account);
|
|
79243
|
+
const error2 = this.lastAccountsError;
|
|
79244
|
+
return error2 ? { count: null, failed: true, error: error2 } : { count, failed: false };
|
|
79245
|
+
}
|
|
79211
79246
|
/**
|
|
79212
79247
|
* Fetches account list directly from Mail.app via AppleScript.
|
|
79213
79248
|
* Used internally by the cache; prefer getCachedAccounts() or listAccounts().
|
|
79249
|
+
*
|
|
79250
|
+
* Returns `null` when the AppleScript transport itself failed (timeout, wedged
|
|
79251
|
+
* Mail, denied Automation). That is deliberately distinct from `[]`, which means
|
|
79252
|
+
* "Mail answered, and there genuinely are no accounts" — collapsing the two is
|
|
79253
|
+
* what let a wedged transport report a confident "No Mail accounts found". (#130)
|
|
79214
79254
|
*/
|
|
79215
79255
|
fetchAccounts() {
|
|
79216
79256
|
const script = buildAppLevelScript(`
|
|
@@ -79231,7 +79271,8 @@ end tell`;
|
|
|
79231
79271
|
const result = executeAppleScript(script);
|
|
79232
79272
|
if (!result.success) {
|
|
79233
79273
|
console.error(`Failed to list accounts: ${result.error}`);
|
|
79234
|
-
|
|
79274
|
+
this.lastAccountsError = result.error ?? "AppleScript transport failed";
|
|
79275
|
+
return null;
|
|
79235
79276
|
}
|
|
79236
79277
|
if (!result.output.trim()) return [];
|
|
79237
79278
|
const items = result.output.split(RECORD_SEP);
|
|
@@ -82824,7 +82865,7 @@ ${mailboxList}`, structured);
|
|
|
82824
82865
|
server.registerTool(
|
|
82825
82866
|
"get-unread-count",
|
|
82826
82867
|
{
|
|
82827
|
-
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).\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).",
|
|
82868
|
+
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).",
|
|
82828
82869
|
inputSchema: {
|
|
82829
82870
|
mailbox: external_exports.string().optional().describe("Mailbox to check (default: INBOX)"),
|
|
82830
82871
|
account: external_exports.string().optional().describe("Account to check")
|
|
@@ -82832,11 +82873,14 @@ server.registerTool(
|
|
|
82832
82873
|
outputSchema: {
|
|
82833
82874
|
unread: external_exports.number().optional(),
|
|
82834
82875
|
mailbox: external_exports.string().optional(),
|
|
82835
|
-
account: external_exports.string().optional()
|
|
82876
|
+
account: external_exports.string().optional(),
|
|
82877
|
+
partial: external_exports.boolean().optional(),
|
|
82878
|
+
failedAccounts: external_exports.array(external_exports.string()).optional()
|
|
82836
82879
|
}
|
|
82837
82880
|
},
|
|
82838
82881
|
withErrorHandling(async ({ mailbox, account }) => {
|
|
82839
82882
|
let count;
|
|
82883
|
+
const failedAccounts = [];
|
|
82840
82884
|
if (shouldUseImap(account)) {
|
|
82841
82885
|
if (account !== void 0) {
|
|
82842
82886
|
count = await imapUnreadCount(mailbox, { account });
|
|
@@ -82849,17 +82893,32 @@ server.registerTool(
|
|
|
82849
82893
|
total += await imapUnreadCount(mailbox, { config: src.config });
|
|
82850
82894
|
} catch (e) {
|
|
82851
82895
|
console.error(`IMAP unread-count failed for "${src.label}": ${String(e)}`);
|
|
82896
|
+
failedAccounts.push(src.label);
|
|
82852
82897
|
}
|
|
82853
82898
|
} else {
|
|
82854
|
-
|
|
82899
|
+
const r = mailManager.getUnreadCountChecked(mailbox, src.account.name);
|
|
82900
|
+
if (r.failed) failedAccounts.push(src.account.name);
|
|
82901
|
+
else total += r.count ?? 0;
|
|
82855
82902
|
}
|
|
82856
82903
|
}
|
|
82857
82904
|
count = total;
|
|
82858
82905
|
}
|
|
82859
82906
|
} else {
|
|
82860
|
-
|
|
82907
|
+
const r = mailManager.getUnreadCountChecked(mailbox, account);
|
|
82908
|
+
if (r.failed) {
|
|
82909
|
+
return errorResponse(
|
|
82910
|
+
`Could not read the unread count \u2014 the AppleScript transport failed: ${r.error}. This is NOT the same as zero unread. Mail may be busy, wedged, or missing an Automation grant; run the "doctor" tool to check.`
|
|
82911
|
+
);
|
|
82912
|
+
}
|
|
82913
|
+
count = r.count ?? 0;
|
|
82861
82914
|
}
|
|
82862
82915
|
const location = mailbox ? ` in "${mailbox}"` : "";
|
|
82916
|
+
if (failedAccounts.length > 0) {
|
|
82917
|
+
return successResponse(
|
|
82918
|
+
`${count} unread message(s)${location} \u2014 PARTIAL: ${failedAccounts.length} account(s) could not be read (${failedAccounts.join(", ")}), so the real total is higher. Run the "doctor" tool to check.`,
|
|
82919
|
+
{ unread: count, mailbox, account, partial: true, failedAccounts }
|
|
82920
|
+
);
|
|
82921
|
+
}
|
|
82863
82922
|
return successResponse(`${count} unread message(s)${location}`, {
|
|
82864
82923
|
unread: count,
|
|
82865
82924
|
mailbox,
|
|
@@ -83089,16 +83148,23 @@ ${lines || " (none met the threshold)"}`,
|
|
|
83089
83148
|
server.registerTool(
|
|
83090
83149
|
"list-accounts",
|
|
83091
83150
|
{
|
|
83092
|
-
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.\nDo not use when: you want the folders within an account (use list-mailboxes) or messages (use list-messages / search-messages).",
|
|
83151
|
+
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).",
|
|
83093
83152
|
inputSchema: {},
|
|
83094
83153
|
outputSchema: {
|
|
83095
83154
|
accounts: external_exports.array(external_exports.object({}).passthrough()).optional(),
|
|
83096
|
-
count: external_exports.number().optional()
|
|
83155
|
+
count: external_exports.number().optional(),
|
|
83156
|
+
partial: external_exports.boolean().optional(),
|
|
83157
|
+
error: external_exports.string().optional()
|
|
83097
83158
|
}
|
|
83098
83159
|
},
|
|
83099
83160
|
withErrorHandling(() => {
|
|
83100
|
-
const accounts = mailManager.
|
|
83101
|
-
const structured = { accounts, count: accounts.length };
|
|
83161
|
+
const { accounts, failed, error: error2 } = mailManager.listAccountsChecked();
|
|
83162
|
+
const structured = failed ? { accounts, count: accounts.length, partial: true, error: error2 } : { accounts, count: accounts.length };
|
|
83163
|
+
if (failed) {
|
|
83164
|
+
return errorResponse(
|
|
83165
|
+
`Could not read the Mail account list \u2014 the AppleScript transport failed: ${error2}. This is NOT the same as having no accounts. Mail may be busy, wedged, or missing an Automation grant; run the "doctor" tool to check.`
|
|
83166
|
+
);
|
|
83167
|
+
}
|
|
83102
83168
|
if (accounts.length === 0) {
|
|
83103
83169
|
return successResponse("No Mail accounts found", structured);
|
|
83104
83170
|
}
|
package/package.json
CHANGED