apple-mail-mcp 2.9.1 → 2.10.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 +17 -2
- package/build/index.js +68 -9
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -78,9 +78,24 @@ The Codex package registers the same `apple-mail` MCP server through `npx -y app
|
|
|
78
78
|
|
|
79
79
|
### Other Hosts (Hermes, Antigravity)
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
Two more hosts can run the same `apple-mail` MCP server (`npx -y apple-mail-mcp`):
|
|
82
82
|
|
|
83
|
-
- **[Hermes Agent](https://hermes-agent.nousresearch.com/)** (NousResearch) — Hermes has no plugin/marketplace drop-in
|
|
83
|
+
- **[Hermes Agent](https://hermes-agent.nousresearch.com/)** (NousResearch) — Hermes has no plugin/marketplace drop-in, so there is nothing in this repo to install from. Register the server with the CLI:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
hermes mcp add apple-mail --command npx --args -y apple-mail-mcp
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Or add it to `~/.hermes/config.yaml` by hand:
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
mcp_servers:
|
|
93
|
+
apple-mail:
|
|
94
|
+
command: npx
|
|
95
|
+
args: ["-y", "apple-mail-mcp"]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Restart your Hermes session afterward so the tools load.
|
|
84
99
|
- **[Antigravity](https://antigravity.google/)** (Google) — add the server entry from [`.antigravity-plugin/mcp_config.json`](https://github.com/sweetrb/apple-mail-mcp/blob/main/.antigravity-plugin/mcp_config.json) to `~/.gemini/config/mcp_config.json` (or via Antigravity's MCP settings).
|
|
85
100
|
|
|
86
101
|
### Manual Installation
|
package/build/index.js
CHANGED
|
@@ -80234,6 +80234,7 @@ function structuredRow(m, account, path) {
|
|
|
80234
80234
|
dateReceived: env.date ? new Date(env.date).toISOString() : "",
|
|
80235
80235
|
isRead: m.flags?.has("\\Seen") ?? false,
|
|
80236
80236
|
isFlagged: m.flags?.has("\\Flagged") ?? false,
|
|
80237
|
+
flagColorIndex: mailFlagColorIndex(m.flags),
|
|
80237
80238
|
mailbox: path,
|
|
80238
80239
|
account,
|
|
80239
80240
|
hasAttachments: false,
|
|
@@ -80594,6 +80595,28 @@ async function imapFetchMessageId(id, deps = {}) {
|
|
|
80594
80595
|
return null;
|
|
80595
80596
|
}
|
|
80596
80597
|
}
|
|
80598
|
+
var MAIL_FLAG_BITS = ["$MailFlagBit0", "$MailFlagBit1", "$MailFlagBit2"];
|
|
80599
|
+
function mailFlagBitsFor(colorIndex) {
|
|
80600
|
+
const set = [];
|
|
80601
|
+
const clear = [];
|
|
80602
|
+
for (let b = 0; b < MAIL_FLAG_BITS.length; b++) {
|
|
80603
|
+
(colorIndex >> b & 1 ? set : clear).push(MAIL_FLAG_BITS[b]);
|
|
80604
|
+
}
|
|
80605
|
+
return { set, clear };
|
|
80606
|
+
}
|
|
80607
|
+
function mailFlagColorIndex(flags) {
|
|
80608
|
+
if (!flags) return void 0;
|
|
80609
|
+
const have = new Set(flags);
|
|
80610
|
+
let idx = 0;
|
|
80611
|
+
let any = false;
|
|
80612
|
+
for (let b = 0; b < MAIL_FLAG_BITS.length; b++) {
|
|
80613
|
+
if (have.has(MAIL_FLAG_BITS[b])) {
|
|
80614
|
+
idx |= 1 << b;
|
|
80615
|
+
any = true;
|
|
80616
|
+
}
|
|
80617
|
+
}
|
|
80618
|
+
return any ? idx : void 0;
|
|
80619
|
+
}
|
|
80597
80620
|
function flagOp(id, flag, add, deps) {
|
|
80598
80621
|
const ref = decodeImapId(id);
|
|
80599
80622
|
if (!ref) return Promise.resolve({ success: false, error: `Not an IMAP message id: "${id}".` });
|
|
@@ -80613,8 +80636,38 @@ function flagOp(id, flag, add, deps) {
|
|
|
80613
80636
|
}
|
|
80614
80637
|
var imapMarkRead = (id, deps = {}) => flagOp(id, "\\Seen", true, deps);
|
|
80615
80638
|
var imapMarkUnread = (id, deps = {}) => flagOp(id, "\\Seen", false, deps);
|
|
80616
|
-
|
|
80617
|
-
|
|
80639
|
+
function imapFlagMessage(id, colorIndex, deps = {}) {
|
|
80640
|
+
if (colorIndex === void 0) return flagOp(id, "\\Flagged", true, deps);
|
|
80641
|
+
const ref = decodeImapId(id);
|
|
80642
|
+
if (!ref) return Promise.resolve({ success: false, error: `Not an IMAP message id: "${id}".` });
|
|
80643
|
+
const { set, clear } = mailFlagBitsFor(colorIndex);
|
|
80644
|
+
return withMailbox(ref.path, depsForMessageRef(ref, deps), async (client) => {
|
|
80645
|
+
try {
|
|
80646
|
+
const ok = await client.messageFlagsAdd([ref.uid], ["\\Flagged", ...set], { uid: true });
|
|
80647
|
+
if (!ok)
|
|
80648
|
+
return { success: false, error: `IMAP flag update returned false for UID ${ref.uid}.` };
|
|
80649
|
+
if (clear.length) await client.messageFlagsRemove([ref.uid], clear, { uid: true });
|
|
80650
|
+
return { success: true };
|
|
80651
|
+
} catch (e) {
|
|
80652
|
+
return { success: false, error: `IMAP flag update failed for UID ${ref.uid}: ${errText(e)}` };
|
|
80653
|
+
}
|
|
80654
|
+
});
|
|
80655
|
+
}
|
|
80656
|
+
function imapUnflagMessage(id, deps = {}) {
|
|
80657
|
+
const ref = decodeImapId(id);
|
|
80658
|
+
if (!ref) return Promise.resolve({ success: false, error: `Not an IMAP message id: "${id}".` });
|
|
80659
|
+
return withMailbox(ref.path, depsForMessageRef(ref, deps), async (client) => {
|
|
80660
|
+
try {
|
|
80661
|
+
const ok = await client.messageFlagsRemove([ref.uid], ["\\Flagged", ...MAIL_FLAG_BITS], {
|
|
80662
|
+
uid: true
|
|
80663
|
+
});
|
|
80664
|
+
if (!ok) return { success: false, error: `IMAP unflag returned false for UID ${ref.uid}.` };
|
|
80665
|
+
return { success: true };
|
|
80666
|
+
} catch (e) {
|
|
80667
|
+
return { success: false, error: `IMAP unflag failed for UID ${ref.uid}: ${errText(e)}` };
|
|
80668
|
+
}
|
|
80669
|
+
});
|
|
80670
|
+
}
|
|
80618
80671
|
async function imapMoveMessageById(id, destMailbox, deps = {}) {
|
|
80619
80672
|
const ref = decodeImapId(id);
|
|
80620
80673
|
if (!ref) return { success: false, error: `Not an IMAP message id: "${id}".` };
|
|
@@ -80777,11 +80830,17 @@ var imapBatchMarkRead = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids)
|
|
|
80777
80830
|
var imapBatchMarkUnread = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
80778
80831
|
await c.messageFlagsRemove(uids, ["\\Seen"], { uid: true });
|
|
80779
80832
|
});
|
|
80780
|
-
var imapBatchFlag = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
80781
|
-
|
|
80833
|
+
var imapBatchFlag = (ids, colorIndex, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
80834
|
+
if (colorIndex === void 0) {
|
|
80835
|
+
await c.messageFlagsAdd(uids, ["\\Flagged"], { uid: true });
|
|
80836
|
+
return;
|
|
80837
|
+
}
|
|
80838
|
+
const { set, clear } = mailFlagBitsFor(colorIndex);
|
|
80839
|
+
await c.messageFlagsAdd(uids, ["\\Flagged", ...set], { uid: true });
|
|
80840
|
+
if (clear.length) await c.messageFlagsRemove(uids, clear, { uid: true });
|
|
80782
80841
|
});
|
|
80783
80842
|
var imapBatchUnflag = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
80784
|
-
await c.messageFlagsRemove(uids, ["\\Flagged"], { uid: true });
|
|
80843
|
+
await c.messageFlagsRemove(uids, ["\\Flagged", ...MAIL_FLAG_BITS], { uid: true });
|
|
80785
80844
|
});
|
|
80786
80845
|
var imapBatchDelete = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids, path) => {
|
|
80787
80846
|
await trashUids(c, uids, path);
|
|
@@ -82235,7 +82294,7 @@ server.registerTool(
|
|
|
82235
82294
|
server.registerTool(
|
|
82236
82295
|
"flag-message",
|
|
82237
82296
|
{
|
|
82238
|
-
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:
|
|
82297
|
+
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.",
|
|
82239
82298
|
inputSchema: {
|
|
82240
82299
|
id: MESSAGE_ID_SCHEMA,
|
|
82241
82300
|
color: FLAG_COLOR_SCHEMA
|
|
@@ -82250,7 +82309,7 @@ server.registerTool(
|
|
|
82250
82309
|
withErrorHandling(({ id, color }) => {
|
|
82251
82310
|
const colorIndex = color ? FLAG_COLOR_INDEX[color] : void 0;
|
|
82252
82311
|
return routeMessage(id, {
|
|
82253
|
-
imap: () => imapFlagMessage(id),
|
|
82312
|
+
imap: () => imapFlagMessage(id, colorIndex),
|
|
82254
82313
|
apple: () => mailManager.flagMessage(id, colorIndex) ? successResponse(color ? `Message flagged (${color})` : "Message flagged", {
|
|
82255
82314
|
ok: true,
|
|
82256
82315
|
id,
|
|
@@ -82467,7 +82526,7 @@ server.registerTool(
|
|
|
82467
82526
|
const { success: successCount, fail: failCount } = await hybridBatchCounts(
|
|
82468
82527
|
ids,
|
|
82469
82528
|
(n) => mailManager.batchFlagMessages(n, colorIndex),
|
|
82470
|
-
(im) => imapBatchFlag(im)
|
|
82529
|
+
(im) => imapBatchFlag(im, colorIndex)
|
|
82471
82530
|
);
|
|
82472
82531
|
const structured = { ok: failCount === 0, success: successCount, failed: failCount };
|
|
82473
82532
|
if (failCount === 0) {
|
|
@@ -82510,7 +82569,7 @@ server.registerTool(
|
|
|
82510
82569
|
server.registerTool(
|
|
82511
82570
|
"resolve-message-id",
|
|
82512
82571
|
{
|
|
82513
|
-
description: "Use when: you have `imap:` message id(s) and need the numeric Mail.app id(s) \u2014
|
|
82572
|
+
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.",
|
|
82514
82573
|
inputSchema: {
|
|
82515
82574
|
ids: BATCH_IDS_SCHEMA
|
|
82516
82575
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apple-mail-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
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",
|
|
@@ -91,6 +91,6 @@
|
|
|
91
91
|
"format:check": "prettier --check src",
|
|
92
92
|
"typecheck": "tsc --noEmit",
|
|
93
93
|
"sync:skills": "node scripts/sync-skills.mjs",
|
|
94
|
-
"version": "node scripts/sync-plugin-version.mjs && git add .claude-plugin .agents/plugins codex .
|
|
94
|
+
"version": "node scripts/sync-plugin-version.mjs && git add .claude-plugin .agents/plugins codex .antigravity-plugin"
|
|
95
95
|
}
|
|
96
96
|
}
|