apple-mail-mcp 2.10.24 → 2.10.25

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.
Files changed (2) hide show
  1. package/build/index.js +64 -49
  2. package/package.json +1 -1
package/build/index.js CHANGED
@@ -78300,6 +78300,7 @@ var DIAG_ITEM_SEP = "M";
78300
78300
  var CONTENT_MARKER = "CONTENT";
78301
78301
  var MSGID_MARKER = "MSGID";
78302
78302
  var HTML_MARKER = "HTML";
78303
+ var LOOKUP_ERROR_MARKER = "ERR";
78303
78304
  var BATCH_FATAL = "FATAL";
78304
78305
  var RECON_TAG = "RECON";
78305
78306
  var SNAP_TAG = "SNAP";
@@ -78653,6 +78654,8 @@ var AppleMailManager = class {
78653
78654
  * misses and falls back to the full scan, so it can never wedge a lookup.
78654
78655
  */
78655
78656
  idLocationIndex = /* @__PURE__ */ new Map();
78657
+ /** Error from the most recent numeric message read, if it was refused. */
78658
+ lastMessageLookupError;
78656
78659
  /** Cap on the id→location index so a long-lived process can't grow unbounded. */
78657
78660
  ID_LOCATION_MAX = 5e3;
78658
78661
  /** Record (or refresh) where a message id lives, evicting oldest when full. */
@@ -78681,6 +78684,12 @@ var AppleMailManager = class {
78681
78684
  noteMessageLocation(id, account, mailbox) {
78682
78685
  this.rememberLocation(id, account, mailbox);
78683
78686
  }
78687
+ /** Consume the most recent read refusal so the tool layer can preserve it. */
78688
+ consumeLastMessageLookupError() {
78689
+ const error2 = this.lastMessageLookupError;
78690
+ this.lastMessageLookupError = void 0;
78691
+ return error2;
78692
+ }
78684
78693
  /**
78685
78694
  * AppleScript fragment resolving `account` + `mailbox` into `_tmb`, leaving
78686
78695
  * `_tmb` as `missing value` when it can't be pinned down. Exact-name match
@@ -79699,6 +79708,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
79699
79708
  * returned the entire raw MIME blob mislabeled as HTML (#32).
79700
79709
  */
79701
79710
  getMessageContent(id, includeHtml = false, hint) {
79711
+ this.lastMessageLookupError = void 0;
79702
79712
  const sourceFetch = includeHtml ? `set htmlSource to ""
79703
79713
  try
79704
79714
  set htmlSource to source of msg
@@ -79724,17 +79734,25 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
79724
79734
  }
79725
79735
  const script = buildAppLevelScript(`
79726
79736
  try
79737
+ set _hits to {}
79738
+ set _names to ""
79727
79739
  repeat with acct in accounts
79728
79740
  repeat with mb in mailboxes of acct
79729
79741
  try
79730
79742
  set matchingMsgs to (messages of mb whose id is ${Number(id)})
79731
79743
  if (count of matchingMsgs) > 0 then
79732
- set msg to item 1 of matchingMsgs
79733
- ${innerFetch}
79744
+ set end of _hits to item 1 of matchingMsgs
79745
+ set _names to _names & (name of acct) & "/" & (name of mb) & ", "
79734
79746
  end if
79735
79747
  end try
79736
79748
  end repeat
79737
79749
  end repeat
79750
+ if (count of _hits) is 0 then return "${LOOKUP_ERROR_MARKER}Message not found"
79751
+ 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"
79752
+ if (count of _hits) is 1 then
79753
+ set msg to item 1 of _hits
79754
+ ${innerFetch}
79755
+ end if
79738
79756
  return ""
79739
79757
  on error errMsg
79740
79758
  return ""
@@ -79756,6 +79774,10 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
79756
79774
  if (!result.success) console.error(`Failed to get message content: ${result.error}`);
79757
79775
  return null;
79758
79776
  }
79777
+ if (result.output.startsWith(LOOKUP_ERROR_MARKER)) {
79778
+ this.lastMessageLookupError = result.output.slice(LOOKUP_ERROR_MARKER.length).trim();
79779
+ return null;
79780
+ }
79759
79781
  const htmlSplit = result.output.split(HTML_MARKER);
79760
79782
  const contentPart = htmlSplit[0];
79761
79783
  const rawSource = htmlSplit.length > 1 ? htmlSplit[1] : "";
@@ -79783,6 +79805,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
79783
79805
  * a 20MB attachment can take several seconds over Exchange/IMAP.
79784
79806
  */
79785
79807
  getRawSource(id, hint) {
79808
+ this.lastMessageLookupError = void 0;
79786
79809
  const loc = hint?.account && hint?.mailbox ? { account: hint.account, mailbox: hint.mailbox } : this.idLocationIndex.get(id.toString());
79787
79810
  if (loc) {
79788
79811
  const scopedScript = this.scopedByIdScript(
@@ -79792,21 +79815,34 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
79792
79815
  "return source of msg"
79793
79816
  );
79794
79817
  const scoped = executeAppleScript(scopedScript, { timeoutMs: 12e4 });
79795
- if (scoped.success && scoped.output.trim()) return scoped.output;
79818
+ if (scoped.success && scoped.output.trim() && !scoped.output.startsWith(LOOKUP_ERROR_MARKER)) {
79819
+ return scoped.output;
79820
+ }
79821
+ if (scoped.success && scoped.output.startsWith(LOOKUP_ERROR_MARKER)) {
79822
+ this.lastMessageLookupError = scoped.output.slice(LOOKUP_ERROR_MARKER.length).trim();
79823
+ }
79796
79824
  }
79797
79825
  const script = buildAppLevelScript(`
79798
79826
  try
79827
+ set _hits to {}
79828
+ set _names to ""
79799
79829
  repeat with acct in accounts
79800
79830
  repeat with mb in mailboxes of acct
79801
79831
  try
79802
79832
  set matchingMsgs to (messages of mb whose id is ${Number(id)})
79803
79833
  if (count of matchingMsgs) > 0 then
79804
- set msg to item 1 of matchingMsgs
79805
- return source of msg
79834
+ set end of _hits to item 1 of matchingMsgs
79835
+ set _names to _names & (name of acct) & "/" & (name of mb) & ", "
79806
79836
  end if
79807
79837
  end try
79808
79838
  end repeat
79809
79839
  end repeat
79840
+ if (count of _hits) is 0 then return "${LOOKUP_ERROR_MARKER}Message not found"
79841
+ 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"
79842
+ if (count of _hits) is 1 then
79843
+ set msg to item 1 of _hits
79844
+ return source of msg
79845
+ end if
79810
79846
  return ""
79811
79847
  on error errMsg
79812
79848
  return ""
@@ -79816,6 +79852,10 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
79816
79852
  if (!result.success || !result.output.trim()) {
79817
79853
  return null;
79818
79854
  }
79855
+ if (result.output.startsWith(LOOKUP_ERROR_MARKER)) {
79856
+ this.lastMessageLookupError = result.output.slice(LOOKUP_ERROR_MARKER.length).trim();
79857
+ return null;
79858
+ }
79819
79859
  return result.output;
79820
79860
  }
79821
79861
  /**
@@ -80256,27 +80296,13 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
80256
80296
  const safeBody = escapeForAppleScriptBody(body);
80257
80297
  const replyAllClause = replyAll ? " with reply to all" : "";
80258
80298
  const sendAction = send ? "send theReply" : "";
80259
- const script = buildAppLevelScript(`
80260
- try
80261
- repeat with acct in accounts
80262
- repeat with mb in mailboxes of acct
80263
- try
80264
- set matchingMsgs to (messages of mb whose id is ${Number(id)})
80265
- if (count of matchingMsgs) > 0 then
80266
- set msg to item 1 of matchingMsgs
80267
- set theReply to reply msg without opening window${replyAllClause}
80268
- set content of theReply to "${safeBody}"
80269
- ${sendAction}
80270
- return "ok"
80271
- end if
80272
- end try
80273
- end repeat
80274
- end repeat
80275
- return "error:Message not found"
80276
- on error errMsg
80277
- return "error:" & errMsg
80278
- end try
80279
- `);
80299
+ const script = this.findMessageScript(
80300
+ id,
80301
+ `
80302
+ set theReply to reply msg without opening window${replyAllClause}
80303
+ set content of theReply to "${safeBody}"
80304
+ ${sendAction}`
80305
+ );
80280
80306
  const result = executeAppleScript(script, { timeoutMs: 6e4 });
80281
80307
  if (!result.success || result.output.startsWith("error:")) {
80282
80308
  console.error(`Failed to reply to message: ${result.error || result.output}`);
@@ -80301,28 +80327,14 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
80301
80327
  recipientCommands += `make new to recipient at end of to recipients of theForward with properties {address:"${escapeForAppleScript(addr)}"}
80302
80328
  `;
80303
80329
  }
80304
- const script = buildAppLevelScript(`
80305
- try
80306
- repeat with acct in accounts
80307
- repeat with mb in mailboxes of acct
80308
- try
80309
- set matchingMsgs to (messages of mb whose id is ${Number(id)})
80310
- if (count of matchingMsgs) > 0 then
80311
- set msg to item 1 of matchingMsgs
80312
- set theForward to forward msg without opening window
80313
- ${recipientCommands}
80314
- ${safeBody ? `set content of theForward to "${safeBody}"` : ""}
80315
- ${sendAction}
80316
- return "ok"
80317
- end if
80318
- end try
80319
- end repeat
80320
- end repeat
80321
- return "error:Message not found"
80322
- on error errMsg
80323
- return "error:" & errMsg
80324
- end try
80325
- `);
80330
+ const script = this.findMessageScript(
80331
+ id,
80332
+ `
80333
+ set theForward to forward msg without opening window
80334
+ ${recipientCommands}
80335
+ ${safeBody ? `set content of theForward to "${safeBody}"` : ""}
80336
+ ${sendAction}`
80337
+ );
80326
80338
  const result = executeAppleScript(script, { timeoutMs: 6e4 });
80327
80339
  if (!result.success || result.output.startsWith("error:")) {
80328
80340
  console.error(`Failed to forward message: ${result.error || result.output}`);
@@ -84735,7 +84747,10 @@ Do not use when: you don't yet have an id (use search-messages or list-messages
84735
84747
  account,
84736
84748
  mailbox
84737
84749
  });
84738
- if (!content) return errorResponse(`Message with ID "${id}" not found`);
84750
+ if (!content) {
84751
+ const lookupError = mailManager.consumeLastMessageLookupError();
84752
+ return errorResponse(lookupError ?? `Message with ID "${id}" not found`);
84753
+ }
84739
84754
  const isHtml = preferHtml === true && !!content.htmlContent;
84740
84755
  const body = isHtml ? content.htmlContent : content.plainText;
84741
84756
  return successResponse(`Subject: ${content.subject}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.10.24",
3
+ "version": "2.10.25",
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",