apple-mail-mcp 2.15.1 → 2.16.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 +5 -0
- package/build/index.js +57 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -953,6 +953,11 @@ accounts only: the local store is a store, not an account. Nothing selects it
|
|
|
953
953
|
implicitly — omitting `account` still resolves to a real account for every other
|
|
954
954
|
tool.
|
|
955
955
|
|
|
956
|
+
The mail inside them is reachable too: `list-messages` and `search-messages`
|
|
957
|
+
accept `account="On My Mac"`, and `get-message` resolves an id that lives only in
|
|
958
|
+
a local mailbox. An id present **both** in an account mailbox and locally is
|
|
959
|
+
reported as ambiguous rather than silently resolving to the account copy.
|
|
960
|
+
|
|
956
961
|
---
|
|
957
962
|
|
|
958
963
|
#### `get-unread-count`
|
package/build/index.js
CHANGED
|
@@ -78980,7 +78980,7 @@ function describeMailboxOpError(op, raw) {
|
|
|
78980
78980
|
const trimmed = (raw || "").trim();
|
|
78981
78981
|
if (UNSUPPORTED_APPLESCRIPT_OP.test(trimmed)) {
|
|
78982
78982
|
const verb = op.charAt(0).toUpperCase() + op.slice(1);
|
|
78983
|
-
return `Mail.app
|
|
78983
|
+
return `Mail.app's scripting bridge will not ${op} this mailbox. That covers server-side (IMAP / Gmail / Workspace / iCloud / Exchange) mailboxes, and on current macOS it covers local "On My Mac" mailboxes too \u2014 measured 2026-08-16, see #193. ${verb} it in Mail.app directly; for an IMAP-configured account the IMAP path can do it instead. (Mail.app error: ${trimmed})`;
|
|
78984
78984
|
}
|
|
78985
78985
|
return trimmed || `Failed to ${op} mailbox`;
|
|
78986
78986
|
}
|
|
@@ -80227,7 +80227,9 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80227
80227
|
}
|
|
80228
80228
|
return { messages: allMessages.slice(0, limit), diagnostics };
|
|
80229
80229
|
}
|
|
80230
|
-
const
|
|
80230
|
+
const local = isLocalStoreLabel(account);
|
|
80231
|
+
const targetAccount = local ? LOCAL_STORE_LABEL : this.resolveAccount(account);
|
|
80232
|
+
const mbIter = local ? "_mbs" : "mailboxes";
|
|
80231
80233
|
const searchCondition = buildSearchCondition({ query, from, subject, isRead, isFlagged });
|
|
80232
80234
|
let dateSetup = "";
|
|
80233
80235
|
let dateFilter = "";
|
|
@@ -80259,7 +80261,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80259
80261
|
set _wantNames to ${nameList}
|
|
80260
80262
|
set msgCount to 0
|
|
80261
80263
|
set seenIds to {}
|
|
80262
|
-
repeat with mb in
|
|
80264
|
+
repeat with mb in ${mbIter}
|
|
80263
80265
|
if msgCount >= ${limit} then exit repeat
|
|
80264
80266
|
set mbName to ""
|
|
80265
80267
|
try
|
|
@@ -80304,7 +80306,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80304
80306
|
set _skipped to ""
|
|
80305
80307
|
set _notSearched to ""
|
|
80306
80308
|
set _startedAt to current date
|
|
80307
|
-
repeat with mb in
|
|
80309
|
+
repeat with mb in ${mbIter}
|
|
80308
80310
|
if msgCount >= ${limit} then exit repeat
|
|
80309
80311
|
set mbName to ""
|
|
80310
80312
|
try
|
|
@@ -80334,7 +80336,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80334
80336
|
return outputText & "${DIAG_MARKER}timedOut=" & (_timedOut as string) & "${DIAG_FIELD_SEP}skipped=" & _skipped & "${DIAG_FIELD_SEP}notSearched=" & _notSearched
|
|
80335
80337
|
`;
|
|
80336
80338
|
}
|
|
80337
|
-
const script = buildAccountScopedScript(targetAccount, searchCommand);
|
|
80339
|
+
const script = local ? buildAppLevelScript(`${localMailboxBindingFragment()}${searchCommand}`) : buildAccountScopedScript(targetAccount, searchCommand);
|
|
80338
80340
|
const result = executeAppleScript(script, { timeoutMs: SEARCH_ACCOUNT_TIMEOUT_MS });
|
|
80339
80341
|
if (!result.success) {
|
|
80340
80342
|
console.error(`Failed to search messages in "${targetAccount}": ${result.error}`);
|
|
@@ -80445,9 +80447,16 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80445
80447
|
*/
|
|
80446
80448
|
scopedByIdScript(account, mailbox, id, innerAction) {
|
|
80447
80449
|
const resolved = this.resolveMailbox(mailbox, account);
|
|
80448
|
-
|
|
80449
|
-
|
|
80450
|
-
|
|
80450
|
+
const bind = isLocalStoreLabel(account) ? `${localMailboxBindingFragment()}
|
|
80451
|
+
set targetMb to missing value
|
|
80452
|
+
ignoring case
|
|
80453
|
+
repeat with mb in _mbs
|
|
80454
|
+
if (name of mb) is "${escapeForAppleScript(resolved)}" then
|
|
80455
|
+
set targetMb to mb
|
|
80456
|
+
exit repeat
|
|
80457
|
+
end if
|
|
80458
|
+
end repeat
|
|
80459
|
+
end ignoring` : `set acct to (first account whose name is "${escapeForAppleScript(account)}")
|
|
80451
80460
|
set targetMb to missing value
|
|
80452
80461
|
ignoring case
|
|
80453
80462
|
repeat with mb in mailboxes of acct
|
|
@@ -80456,7 +80465,10 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80456
80465
|
exit repeat
|
|
80457
80466
|
end if
|
|
80458
80467
|
end repeat
|
|
80459
|
-
end ignoring
|
|
80468
|
+
end ignoring`;
|
|
80469
|
+
return buildAppLevelScript(`
|
|
80470
|
+
try
|
|
80471
|
+
${bind}
|
|
80460
80472
|
if targetMb is not missing value then
|
|
80461
80473
|
set matchingMsgs to (messages of targetMb whose id is ${Number(id)})
|
|
80462
80474
|
if (count of matchingMsgs) > 0 then
|
|
@@ -80520,6 +80532,19 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80520
80532
|
end try
|
|
80521
80533
|
end repeat
|
|
80522
80534
|
end repeat
|
|
80535
|
+
-- #183: local mailboxes belong to no account, so the walk above cannot
|
|
80536
|
+
-- reach them. Collect into the SAME _hits/_names, which means an id
|
|
80537
|
+
-- present both in an account and locally is now correctly reported as
|
|
80538
|
+
-- ambiguous rather than silently resolving to the account copy.${localMailboxBindingFragment()}
|
|
80539
|
+
repeat with mb in _mbs
|
|
80540
|
+
try
|
|
80541
|
+
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
80542
|
+
if (count of matchingMsgs) > 0 then
|
|
80543
|
+
set end of _hits to item 1 of matchingMsgs
|
|
80544
|
+
set _names to _names & "${LOCAL_STORE_LABEL}/" & (name of mb) & ", "
|
|
80545
|
+
end if
|
|
80546
|
+
end try
|
|
80547
|
+
end repeat
|
|
80523
80548
|
if (count of _hits) is 0 then return "${LOOKUP_ERROR_MARKER}Message not found"
|
|
80524
80549
|
if (count of _hits) > 1 then return "${LOOKUP_ERROR_MARKER}${AMBIGUOUS_ID_PREFIX}${Number(id)} is present in more than one mailbox (" & _names & "); list or search that mailbox first so the read targets the right copy"
|
|
80525
80550
|
if (count of _hits) is 1 then
|
|
@@ -80610,6 +80635,19 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80610
80635
|
end try
|
|
80611
80636
|
end repeat
|
|
80612
80637
|
end repeat
|
|
80638
|
+
-- #183: local mailboxes belong to no account, so the walk above cannot
|
|
80639
|
+
-- reach them. Collect into the SAME _hits/_names, which means an id
|
|
80640
|
+
-- present both in an account and locally is now correctly reported as
|
|
80641
|
+
-- ambiguous rather than silently resolving to the account copy.${localMailboxBindingFragment()}
|
|
80642
|
+
repeat with mb in _mbs
|
|
80643
|
+
try
|
|
80644
|
+
set matchingMsgs to (messages of mb whose id is ${Number(id)})
|
|
80645
|
+
if (count of matchingMsgs) > 0 then
|
|
80646
|
+
set end of _hits to item 1 of matchingMsgs
|
|
80647
|
+
set _names to _names & "${LOCAL_STORE_LABEL}/" & (name of mb) & ", "
|
|
80648
|
+
end if
|
|
80649
|
+
end try
|
|
80650
|
+
end repeat
|
|
80613
80651
|
if (count of _hits) is 0 then return "${LOOKUP_ERROR_MARKER}Message not found"
|
|
80614
80652
|
if (count of _hits) > 1 then return "${LOOKUP_ERROR_MARKER}${AMBIGUOUS_ID_PREFIX}${Number(id)} is present in more than one mailbox (" & _names & "); list or search that mailbox first so the read targets the right copy"
|
|
80615
80653
|
if (count of _hits) is 1 then
|
|
@@ -80673,10 +80711,12 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80673
80711
|
}
|
|
80674
80712
|
return { messages: allMessages.slice(0, limit), diagnostics };
|
|
80675
80713
|
}
|
|
80676
|
-
const
|
|
80714
|
+
const local = isLocalStoreLabel(account);
|
|
80715
|
+
const targetAccount = local ? LOCAL_STORE_LABEL : this.resolveAccount(account);
|
|
80677
80716
|
const safeFrom = from ? escapeForAppleScript(from) : "";
|
|
80678
80717
|
const fromFilter = from ? `whose sender contains "${safeFrom}"` : "";
|
|
80679
80718
|
const scanThreshold = getMailboxScanThreshold();
|
|
80719
|
+
const mbIter = local ? "_mbs" : "mailboxes";
|
|
80680
80720
|
let listCommand;
|
|
80681
80721
|
if (mailbox) {
|
|
80682
80722
|
const targetMailbox = this.resolveMailbox(mailbox, targetAccount);
|
|
@@ -80691,7 +80731,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80691
80731
|
set msgCount to 0
|
|
80692
80732
|
set skipped to 0
|
|
80693
80733
|
set seenIds to {}
|
|
80694
|
-
repeat with mb in
|
|
80734
|
+
repeat with mb in ${mbIter}
|
|
80695
80735
|
if msgCount >= ${limit} then exit repeat
|
|
80696
80736
|
set mbName to ""
|
|
80697
80737
|
try
|
|
@@ -80738,7 +80778,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80738
80778
|
set _skipped to ""
|
|
80739
80779
|
set _notSearched to ""
|
|
80740
80780
|
set _startedAt to current date
|
|
80741
|
-
repeat with mb in
|
|
80781
|
+
repeat with mb in ${mbIter}
|
|
80742
80782
|
if msgCount >= ${limit} then exit repeat
|
|
80743
80783
|
set mbName to ""
|
|
80744
80784
|
try
|
|
@@ -80768,7 +80808,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
|
|
|
80768
80808
|
return outputText & "${DIAG_MARKER}timedOut=" & (_timedOut as string) & "${DIAG_FIELD_SEP}skipped=" & _skipped & "${DIAG_FIELD_SEP}notSearched=" & _notSearched
|
|
80769
80809
|
`;
|
|
80770
80810
|
}
|
|
80771
|
-
const script = buildAccountScopedScript(targetAccount, listCommand);
|
|
80811
|
+
const script = local ? buildAppLevelScript(`${localMailboxBindingFragment()}${listCommand}`) : buildAccountScopedScript(targetAccount, listCommand);
|
|
80772
80812
|
const result = executeAppleScript(script, { timeoutMs: SEARCH_ACCOUNT_TIMEOUT_MS });
|
|
80773
80813
|
if (!result.success) {
|
|
80774
80814
|
console.error(`Failed to list messages in "${targetAccount}": ${result.error}`);
|
|
@@ -82736,16 +82776,14 @@ end tell`;
|
|
|
82736
82776
|
* Used internally by the cache; prefer getCachedMailboxNames().
|
|
82737
82777
|
*/
|
|
82738
82778
|
fetchMailboxNames(account) {
|
|
82739
|
-
const
|
|
82740
|
-
account,
|
|
82741
|
-
`
|
|
82779
|
+
const body = `
|
|
82742
82780
|
set mbNames to {}
|
|
82743
|
-
repeat with mb in mailboxes
|
|
82781
|
+
repeat with mb in ${isLocalStoreLabel(account) ? "_mbs" : "mailboxes"}
|
|
82744
82782
|
set end of mbNames to name of mb
|
|
82745
82783
|
end repeat
|
|
82746
82784
|
return mbNames
|
|
82747
|
-
|
|
82748
|
-
);
|
|
82785
|
+
`;
|
|
82786
|
+
const script = isLocalStoreLabel(account) ? buildAppLevelScript(`${localMailboxBindingFragment()}${body}`) : buildAccountScopedScript(account, body);
|
|
82749
82787
|
const result = executeAppleScript(script);
|
|
82750
82788
|
if (!result.success || !result.output) {
|
|
82751
82789
|
return [];
|
package/package.json
CHANGED