apple-mail-mcp 2.9.1 → 2.10.1
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 +19 -4
- package/build/index.js +81 -17
- 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
|
|
@@ -731,7 +746,7 @@ Flag or unflag a message. `flag-message` optionally takes a flag **color**; `unf
|
|
|
731
746
|
| `id` | string | Yes | Message ID |
|
|
732
747
|
| `color` | string | No | (`flag-message` only) Flag color: `red`, `orange`, `yellow`, `green`, `blue`, `purple`, `gray` (`grey` accepted). Omit for Mail's default flag. |
|
|
733
748
|
|
|
734
|
-
**Flag colors** are an Apple Mail feature
|
|
749
|
+
**Flag colors** are an Apple Mail feature — the message's `flag index` (0 red, 1 orange, 2 yellow, 3 green, 4 blue, 5 purple, 6 gray), which is the property a Mail smart mailbox can match on. **The color is applied on both routes** (since 2.10.0): AppleScript sets the flag index directly, and for an **IMAP-routed** id (`imap:…`) the color is written as Mail.app's `$MailFlagBit0/1/2` keywords — a 3-bit field holding the same palette index. `\Flagged` on its own really is colorless, but those keywords ride alongside it in an ordinary `UID STORE`, so a smart mailbox keyed on flag color matches an IMAP-flagged message too. You do **not** need to resolve to a numeric id just to color a flag.
|
|
735
750
|
|
|
736
751
|
---
|
|
737
752
|
|
|
@@ -814,7 +829,7 @@ All batch operations accept an array of message IDs (max 100 per batch) and retu
|
|
|
814
829
|
| Parameter | Type | Required | Description |
|
|
815
830
|
|-----------|------|----------|-------------|
|
|
816
831
|
| `ids` | string[] | Yes | Message IDs (max 100) |
|
|
817
|
-
| `color` | string | No | (`batch-flag-messages` only) Flag color
|
|
832
|
+
| `color` | string | No | (`batch-flag-messages` only) Flag color — see [`flag-message`](#flag-message--unflag-message). Applied on both routes, so a mixed batch of numeric and `imap:` ids all end up colored. |
|
|
818
833
|
|
|
819
834
|
---
|
|
820
835
|
|
package/build/index.js
CHANGED
|
@@ -78120,9 +78120,13 @@ var AppleMailManager = class {
|
|
|
78120
78120
|
/**
|
|
78121
78121
|
* Resolve a message's numeric Mail.app id from its RFC822 Message-ID (the
|
|
78122
78122
|
* backend-independent join key). This bridges an `imap:` id to the numeric id
|
|
78123
|
-
* required
|
|
78124
|
-
*
|
|
78125
|
-
*
|
|
78123
|
+
* required by the AppleScript-only tools — `reply-to-message` and
|
|
78124
|
+
* `forward-message`.
|
|
78125
|
+
*
|
|
78126
|
+
* Note: flag *color* no longer needs this (since 2.10.0). Mail.app stores the
|
|
78127
|
+
* color as the `$MailFlagBit0/1/2` keywords, which ride alongside `\Flagged`
|
|
78128
|
+
* in an ordinary `UID STORE`, so flag-message/batch-flag-messages color an
|
|
78129
|
+
* `imap:` id directly and a smart mailbox keyed on flag color matches it.
|
|
78126
78130
|
*
|
|
78127
78131
|
* The Message-ID is matched both bracketless and `<bracketed>` (Mail returns
|
|
78128
78132
|
* it bracketless; IMAP envelopes carry the brackets). When `accountName` is
|
|
@@ -80234,6 +80238,7 @@ function structuredRow(m, account, path) {
|
|
|
80234
80238
|
dateReceived: env.date ? new Date(env.date).toISOString() : "",
|
|
80235
80239
|
isRead: m.flags?.has("\\Seen") ?? false,
|
|
80236
80240
|
isFlagged: m.flags?.has("\\Flagged") ?? false,
|
|
80241
|
+
flagColorIndex: mailFlagColorIndex(m.flags),
|
|
80237
80242
|
mailbox: path,
|
|
80238
80243
|
account,
|
|
80239
80244
|
hasAttachments: false,
|
|
@@ -80594,6 +80599,28 @@ async function imapFetchMessageId(id, deps = {}) {
|
|
|
80594
80599
|
return null;
|
|
80595
80600
|
}
|
|
80596
80601
|
}
|
|
80602
|
+
var MAIL_FLAG_BITS = ["$MailFlagBit0", "$MailFlagBit1", "$MailFlagBit2"];
|
|
80603
|
+
function mailFlagBitsFor(colorIndex) {
|
|
80604
|
+
const set = [];
|
|
80605
|
+
const clear = [];
|
|
80606
|
+
for (let b = 0; b < MAIL_FLAG_BITS.length; b++) {
|
|
80607
|
+
(colorIndex >> b & 1 ? set : clear).push(MAIL_FLAG_BITS[b]);
|
|
80608
|
+
}
|
|
80609
|
+
return { set, clear };
|
|
80610
|
+
}
|
|
80611
|
+
function mailFlagColorIndex(flags) {
|
|
80612
|
+
if (!flags) return void 0;
|
|
80613
|
+
const have = new Set(flags);
|
|
80614
|
+
let idx = 0;
|
|
80615
|
+
let any = false;
|
|
80616
|
+
for (let b = 0; b < MAIL_FLAG_BITS.length; b++) {
|
|
80617
|
+
if (have.has(MAIL_FLAG_BITS[b])) {
|
|
80618
|
+
idx |= 1 << b;
|
|
80619
|
+
any = true;
|
|
80620
|
+
}
|
|
80621
|
+
}
|
|
80622
|
+
return any ? idx : void 0;
|
|
80623
|
+
}
|
|
80597
80624
|
function flagOp(id, flag, add, deps) {
|
|
80598
80625
|
const ref = decodeImapId(id);
|
|
80599
80626
|
if (!ref) return Promise.resolve({ success: false, error: `Not an IMAP message id: "${id}".` });
|
|
@@ -80613,8 +80640,38 @@ function flagOp(id, flag, add, deps) {
|
|
|
80613
80640
|
}
|
|
80614
80641
|
var imapMarkRead = (id, deps = {}) => flagOp(id, "\\Seen", true, deps);
|
|
80615
80642
|
var imapMarkUnread = (id, deps = {}) => flagOp(id, "\\Seen", false, deps);
|
|
80616
|
-
|
|
80617
|
-
|
|
80643
|
+
function imapFlagMessage(id, colorIndex, deps = {}) {
|
|
80644
|
+
if (colorIndex === void 0) return flagOp(id, "\\Flagged", true, deps);
|
|
80645
|
+
const ref = decodeImapId(id);
|
|
80646
|
+
if (!ref) return Promise.resolve({ success: false, error: `Not an IMAP message id: "${id}".` });
|
|
80647
|
+
const { set, clear } = mailFlagBitsFor(colorIndex);
|
|
80648
|
+
return withMailbox(ref.path, depsForMessageRef(ref, deps), async (client) => {
|
|
80649
|
+
try {
|
|
80650
|
+
const ok = await client.messageFlagsAdd([ref.uid], ["\\Flagged", ...set], { uid: true });
|
|
80651
|
+
if (!ok)
|
|
80652
|
+
return { success: false, error: `IMAP flag update returned false for UID ${ref.uid}.` };
|
|
80653
|
+
if (clear.length) await client.messageFlagsRemove([ref.uid], clear, { uid: true });
|
|
80654
|
+
return { success: true };
|
|
80655
|
+
} catch (e) {
|
|
80656
|
+
return { success: false, error: `IMAP flag update failed for UID ${ref.uid}: ${errText(e)}` };
|
|
80657
|
+
}
|
|
80658
|
+
});
|
|
80659
|
+
}
|
|
80660
|
+
function imapUnflagMessage(id, deps = {}) {
|
|
80661
|
+
const ref = decodeImapId(id);
|
|
80662
|
+
if (!ref) return Promise.resolve({ success: false, error: `Not an IMAP message id: "${id}".` });
|
|
80663
|
+
return withMailbox(ref.path, depsForMessageRef(ref, deps), async (client) => {
|
|
80664
|
+
try {
|
|
80665
|
+
const ok = await client.messageFlagsRemove([ref.uid], ["\\Flagged", ...MAIL_FLAG_BITS], {
|
|
80666
|
+
uid: true
|
|
80667
|
+
});
|
|
80668
|
+
if (!ok) return { success: false, error: `IMAP unflag returned false for UID ${ref.uid}.` };
|
|
80669
|
+
return { success: true };
|
|
80670
|
+
} catch (e) {
|
|
80671
|
+
return { success: false, error: `IMAP unflag failed for UID ${ref.uid}: ${errText(e)}` };
|
|
80672
|
+
}
|
|
80673
|
+
});
|
|
80674
|
+
}
|
|
80618
80675
|
async function imapMoveMessageById(id, destMailbox, deps = {}) {
|
|
80619
80676
|
const ref = decodeImapId(id);
|
|
80620
80677
|
if (!ref) return { success: false, error: `Not an IMAP message id: "${id}".` };
|
|
@@ -80777,11 +80834,17 @@ var imapBatchMarkRead = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids)
|
|
|
80777
80834
|
var imapBatchMarkUnread = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
80778
80835
|
await c.messageFlagsRemove(uids, ["\\Seen"], { uid: true });
|
|
80779
80836
|
});
|
|
80780
|
-
var imapBatchFlag = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
80781
|
-
|
|
80837
|
+
var imapBatchFlag = (ids, colorIndex, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
80838
|
+
if (colorIndex === void 0) {
|
|
80839
|
+
await c.messageFlagsAdd(uids, ["\\Flagged"], { uid: true });
|
|
80840
|
+
return;
|
|
80841
|
+
}
|
|
80842
|
+
const { set, clear } = mailFlagBitsFor(colorIndex);
|
|
80843
|
+
await c.messageFlagsAdd(uids, ["\\Flagged", ...set], { uid: true });
|
|
80844
|
+
if (clear.length) await c.messageFlagsRemove(uids, clear, { uid: true });
|
|
80782
80845
|
});
|
|
80783
80846
|
var imapBatchUnflag = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids) => {
|
|
80784
|
-
await c.messageFlagsRemove(uids, ["\\Flagged"], { uid: true });
|
|
80847
|
+
await c.messageFlagsRemove(uids, ["\\Flagged", ...MAIL_FLAG_BITS], { uid: true });
|
|
80785
80848
|
});
|
|
80786
80849
|
var imapBatchDelete = (ids, deps = {}) => imapBatch(ids, deps, async (c, uids, path) => {
|
|
80787
80850
|
await trashUids(c, uids, path);
|
|
@@ -81431,7 +81494,7 @@ var FLAG_COLOR_INDEX = {
|
|
|
81431
81494
|
grey: 6
|
|
81432
81495
|
};
|
|
81433
81496
|
var FLAG_COLOR_SCHEMA = external_exports.enum(["red", "orange", "yellow", "green", "blue", "purple", "gray", "grey"]).optional().describe(
|
|
81434
|
-
"Optional flag color (Apple Mail palette: red, orange, yellow, green, blue, purple, gray \u2014 'grey' accepted). Omit for Mail's default flag.
|
|
81497
|
+
"Optional flag color (Apple Mail palette: red, orange, yellow, green, blue, purple, gray \u2014 'grey' accepted). Omit for Mail's default flag. The color is applied on both routes: AppleScript sets the flag index, and IMAP writes the equivalent $MailFlagBit0/1/2 keywords Mail.app reads \u2014 so a smart mailbox keyed on flag color matches either way."
|
|
81435
81498
|
);
|
|
81436
81499
|
var DATE_FILTER_SCHEMA = external_exports.string().regex(
|
|
81437
81500
|
/^[a-zA-Z0-9 ,/\-:]+$/,
|
|
@@ -82235,7 +82298,7 @@ server.registerTool(
|
|
|
82235
82298
|
server.registerTool(
|
|
82236
82299
|
"flag-message",
|
|
82237
82300
|
{
|
|
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:
|
|
82301
|
+
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
82302
|
inputSchema: {
|
|
82240
82303
|
id: MESSAGE_ID_SCHEMA,
|
|
82241
82304
|
color: FLAG_COLOR_SCHEMA
|
|
@@ -82250,16 +82313,17 @@ server.registerTool(
|
|
|
82250
82313
|
withErrorHandling(({ id, color }) => {
|
|
82251
82314
|
const colorIndex = color ? FLAG_COLOR_INDEX[color] : void 0;
|
|
82252
82315
|
return routeMessage(id, {
|
|
82253
|
-
imap: () => imapFlagMessage(id),
|
|
82316
|
+
imap: () => imapFlagMessage(id, colorIndex),
|
|
82254
82317
|
apple: () => mailManager.flagMessage(id, colorIndex) ? successResponse(color ? `Message flagged (${color})` : "Message flagged", {
|
|
82255
82318
|
ok: true,
|
|
82256
82319
|
id,
|
|
82257
82320
|
...color ? { color, colorApplied: true } : {}
|
|
82258
82321
|
}) : errorResponse(`Failed to flag message "${id}"`),
|
|
82259
|
-
// IMAP path:
|
|
82260
|
-
|
|
82322
|
+
// IMAP path: imapFlagMessage writes the color as $MailFlagBit0/1/2 keywords,
|
|
82323
|
+
// so the outcome matches the AppleScript route above.
|
|
82324
|
+
ok: color ? `Message flagged (${color})` : "Message flagged",
|
|
82261
82325
|
fail: `Failed to flag message "${id}"`,
|
|
82262
|
-
structured: color ? { ok: true, id, color, colorApplied:
|
|
82326
|
+
structured: color ? { ok: true, id, color, colorApplied: true } : { ok: true, id }
|
|
82263
82327
|
});
|
|
82264
82328
|
}, "Error flagging message")
|
|
82265
82329
|
);
|
|
@@ -82455,7 +82519,7 @@ server.registerTool(
|
|
|
82455
82519
|
server.registerTool(
|
|
82456
82520
|
"batch-flag-messages",
|
|
82457
82521
|
{
|
|
82458
|
-
description: "Use when: flagging multiple messages (1\u2013100 ids) in one call, optionally with a color (red/orange/yellow/green/blue/purple/gray).\nReturns: counts of how many were flagged and how many failed.\nDo not use when: flagging just one (use flag-message) or removing flags (use batch-unflag-messages). Get the ids from search-messages or list-messages first.\nNote:
|
|
82522
|
+
description: "Use when: flagging multiple messages (1\u2013100 ids) in one call, optionally with a color (red/orange/yellow/green/blue/purple/gray).\nReturns: counts of how many were flagged and how many failed.\nDo not use when: flagging just one (use flag-message) or removing flags (use batch-unflag-messages). Get the ids 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 \u2014 so a mixed batch of numeric and `imap:` ids all end up colored.",
|
|
82459
82523
|
inputSchema: {
|
|
82460
82524
|
ids: BATCH_IDS_SCHEMA,
|
|
82461
82525
|
color: FLAG_COLOR_SCHEMA
|
|
@@ -82467,7 +82531,7 @@ server.registerTool(
|
|
|
82467
82531
|
const { success: successCount, fail: failCount } = await hybridBatchCounts(
|
|
82468
82532
|
ids,
|
|
82469
82533
|
(n) => mailManager.batchFlagMessages(n, colorIndex),
|
|
82470
|
-
(im) => imapBatchFlag(im)
|
|
82534
|
+
(im) => imapBatchFlag(im, colorIndex)
|
|
82471
82535
|
);
|
|
82472
82536
|
const structured = { ok: failCount === 0, success: successCount, failed: failCount };
|
|
82473
82537
|
if (failCount === 0) {
|
|
@@ -82510,7 +82574,7 @@ server.registerTool(
|
|
|
82510
82574
|
server.registerTool(
|
|
82511
82575
|
"resolve-message-id",
|
|
82512
82576
|
{
|
|
82513
|
-
description: "Use when: you have `imap:` message id(s) and need the numeric Mail.app id(s) \u2014
|
|
82577
|
+
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
82578
|
inputSchema: {
|
|
82515
82579
|
ids: BATCH_IDS_SCHEMA
|
|
82516
82580
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apple-mail-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.1",
|
|
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
|
}
|