apple-mail-mcp 2.20.2 → 2.20.3

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 +41 -14
  2. package/package.json +1 -1
package/build/index.js CHANGED
@@ -82325,7 +82325,8 @@ function executeAppleScript(script, options = {}) {
82325
82325
  lastError = {
82326
82326
  success: false,
82327
82327
  output: "",
82328
- error: errorMessage
82328
+ error: errorMessage,
82329
+ ...isTimeout ? { timedOut: true } : {}
82329
82330
  };
82330
82331
  const canRetry = isTimeout || isRetryableError(errorMessage);
82331
82332
  const hasAttemptsLeft = attempt < maxRetries;
@@ -82598,6 +82599,10 @@ function getMailboxScanThreshold() {
82598
82599
  }
82599
82600
  var SEARCH_ACCOUNT_BUDGET_SECONDS = 30;
82600
82601
  var SEARCH_ACCOUNT_TIMEOUT_MS = 45e3;
82602
+ var READ_ONLY_BYID_TIMEOUT_MS = 15e3;
82603
+ function timedOutResolvingId(id) {
82604
+ return `AppleScript timed out resolving id ${Number(id)} \u2014 Mail.app's scripting bridge may be wedged; try health-check.`;
82605
+ }
82601
82606
  var GROUP_SEP = "";
82602
82607
  var FIELD_SEP = "";
82603
82608
  var RECORD_SEP = "";
@@ -84208,6 +84213,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84208
84213
  * all mailboxes in all accounts to find the message.
84209
84214
  */
84210
84215
  getMessageById(id, deepAttachmentCheck = false) {
84216
+ this.lastMessageLookupError = void 0;
84211
84217
  const deepScan = deepAttachmentCheck ? `if hasAtt is "false" then
84212
84218
  try
84213
84219
  set rawSrc to source of msg
@@ -84249,8 +84255,9 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84249
84255
  return ""
84250
84256
  end try
84251
84257
  `);
84252
- const result = executeAppleScript(script, { timeoutMs: 6e4 });
84258
+ const result = executeAppleScript(script, { timeoutMs: READ_ONLY_BYID_TIMEOUT_MS });
84253
84259
  if (!result.success || !result.output.trim()) {
84260
+ if (result.timedOut) this.lastMessageLookupError = timedOutResolvingId(id);
84254
84261
  console.error(`Failed to get message ${id}: ${result.error}`);
84255
84262
  return null;
84256
84263
  }
@@ -84407,7 +84414,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84407
84414
  const scopedScript = this.scopedByIdScript(loc.account, loc.mailbox, id, innerFetch);
84408
84415
  const scoped = this.parseMessageContent(
84409
84416
  id,
84410
- executeAppleScript(scopedScript, { timeoutMs: 6e4 }),
84417
+ executeAppleScript(scopedScript, { timeoutMs: READ_ONLY_BYID_TIMEOUT_MS }),
84411
84418
  includeHtml
84412
84419
  );
84413
84420
  if (scoped) return scoped;
@@ -84415,7 +84422,7 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84415
84422
  const script = this.unscopedByIdScript(id, innerFetch);
84416
84423
  return this.parseMessageContent(
84417
84424
  id,
84418
- executeAppleScript(script, { timeoutMs: 6e4 }),
84425
+ executeAppleScript(script, { timeoutMs: READ_ONLY_BYID_TIMEOUT_MS }),
84419
84426
  includeHtml
84420
84427
  );
84421
84428
  }
@@ -84426,7 +84433,10 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84426
84433
  */
84427
84434
  parseMessageContent(id, result, includeHtml) {
84428
84435
  if (!result.success || !result.output.trim()) {
84429
- if (!result.success) console.error(`Failed to get message content: ${result.error}`);
84436
+ if (!result.success) {
84437
+ if (result.timedOut) this.lastMessageLookupError = timedOutResolvingId(id);
84438
+ console.error(`Failed to get message content: ${result.error}`);
84439
+ }
84430
84440
  return null;
84431
84441
  }
84432
84442
  if (result.output.startsWith(LOOKUP_ERROR_MARKER)) {
@@ -84473,7 +84483,10 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84473
84483
  return msgDates & "${DATES_MARKER}" & msgHeaders`;
84474
84484
  const parse4 = (result) => {
84475
84485
  if (!result.success || !result.output.trim()) {
84476
- if (!result.success) console.error(`Failed to get message headers: ${result.error}`);
84486
+ if (!result.success) {
84487
+ if (result.timedOut) this.lastMessageLookupError = timedOutResolvingId(id);
84488
+ console.error(`Failed to get message headers: ${result.error}`);
84489
+ }
84477
84490
  return null;
84478
84491
  }
84479
84492
  if (result.output.startsWith(LOOKUP_ERROR_MARKER)) {
@@ -84491,21 +84504,29 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84491
84504
  if (loc) {
84492
84505
  const scoped = parse4(
84493
84506
  executeAppleScript(this.scopedByIdScript(loc.account, loc.mailbox, id, innerFetch), {
84494
- timeoutMs: 6e4
84507
+ timeoutMs: READ_ONLY_BYID_TIMEOUT_MS
84495
84508
  })
84496
84509
  );
84497
84510
  if (scoped) return scoped;
84498
84511
  }
84499
- return parse4(executeAppleScript(this.unscopedByIdScript(id, innerFetch), { timeoutMs: 6e4 }));
84512
+ return parse4(
84513
+ executeAppleScript(this.unscopedByIdScript(id, innerFetch), {
84514
+ timeoutMs: READ_ONLY_BYID_TIMEOUT_MS
84515
+ })
84516
+ );
84500
84517
  }
84501
84518
  /**
84502
84519
  * Get the raw MIME source of a message.
84503
84520
  * Used as fallback for attachment extraction when AppleScript
84504
84521
  * mail attachments returns empty.
84505
84522
  *
84506
- * Timeout is 2x the default (120s) because `source of msg` returns
84507
- * the entire raw message including base64-encoded attachments —
84508
- * a 20MB attachment can take several seconds over Exchange/IMAP.
84523
+ * Uses the same short `READ_ONLY_BYID_TIMEOUT_MS` as the other by-id reads
84524
+ * (#270) — `source of msg` returning the entire raw message, base64
84525
+ * attachments included, is documented elsewhere as taking "several
84526
+ * seconds" for a 20MB attachment over Exchange/IMAP, comfortably inside
84527
+ * that budget; a call still running past it is a wedged scripting bridge,
84528
+ * not legitimate transfer time, so there is no case where the old 120s
84529
+ * ceiling was buying a real result a shorter one would have missed.
84509
84530
  */
84510
84531
  getRawSource(id, hint) {
84511
84532
  this.lastMessageLookupError = void 0;
@@ -84517,17 +84538,20 @@ ${indent}end try${this.sanitizeFragment("_uacct", indent)}${this.sanitizeFragmen
84517
84538
  id,
84518
84539
  "return source of msg"
84519
84540
  );
84520
- const scoped = executeAppleScript(scopedScript, { timeoutMs: 12e4 });
84541
+ const scoped = executeAppleScript(scopedScript, { timeoutMs: READ_ONLY_BYID_TIMEOUT_MS });
84521
84542
  if (scoped.success && scoped.output.trim() && !scoped.output.startsWith(LOOKUP_ERROR_MARKER)) {
84522
84543
  return scoped.output;
84523
84544
  }
84524
84545
  if (scoped.success && scoped.output.startsWith(LOOKUP_ERROR_MARKER)) {
84525
84546
  this.lastMessageLookupError = scoped.output.slice(LOOKUP_ERROR_MARKER.length).trim();
84547
+ } else if (!scoped.success && scoped.timedOut) {
84548
+ this.lastMessageLookupError = timedOutResolvingId(id);
84526
84549
  }
84527
84550
  }
84528
84551
  const script = this.unscopedByIdScript(id, "return source of msg");
84529
- const result = executeAppleScript(script, { timeoutMs: 12e4 });
84552
+ const result = executeAppleScript(script, { timeoutMs: READ_ONLY_BYID_TIMEOUT_MS });
84530
84553
  if (!result.success || !result.output.trim()) {
84554
+ if (result.timedOut) this.lastMessageLookupError = timedOutResolvingId(id);
84531
84555
  return null;
84532
84556
  }
84533
84557
  if (result.output.startsWith(LOOKUP_ERROR_MARKER)) {
@@ -89151,7 +89175,10 @@ registerTool(
89151
89175
  seedSubject = subjectFromGetMessage(r.info);
89152
89176
  } else {
89153
89177
  const msg = mailManager.getMessageById(id);
89154
- if (!msg) return errorResponse(`Message with ID "${id}" not found`);
89178
+ if (!msg) {
89179
+ const lookupError = mailManager.consumeLastMessageLookupError();
89180
+ return errorResponse(lookupError ?? `Message with ID "${id}" not found`);
89181
+ }
89155
89182
  seedSubject = msg.subject;
89156
89183
  }
89157
89184
  if (!seedSubject) return errorResponse(`Could not determine the subject of message "${id}"`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "2.20.2",
3
+ "version": "2.20.3",
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",