apple-mail-mcp 1.7.0 → 1.8.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 CHANGED
@@ -279,9 +279,15 @@ an account is configured for IMAP, `search-messages` and `list-messages` instead
279
279
  run a **server-side IMAP search** ([#43](https://github.com/sweetrb/apple-mail-mcp/issues/43)) —
280
280
  typically sub-second and correct on the same mailbox where AppleScript times out.
281
281
  This is **opt-in and additive**: any account without IMAP configured behaves
282
- exactly as before (AppleScript). Read-only for now `get-message` and all
283
- mutations stay on AppleScript (the IMAP rows report message **UIDs**, noted in
284
- the output).
282
+ exactly as before (AppleScript). When an account is IMAP-configured,
283
+ `search-messages`/`list-messages` (read) and `create-mailbox`/`rename-mailbox`/
284
+ `delete-mailbox` (folder ops) route to IMAP. The folder ops are the key win for
285
+ server accounts: IMAP's `CREATE`/`RENAME`/`DELETE` succeed on exactly the
286
+ iCloud/Gmail/Workspace/Exchange mailboxes where Mail.app's AppleScript bridge
287
+ can't (#42). `get-message` and message-level mutations (mark/flag/move/delete-
288
+ message) stay on AppleScript for now — they key off a message id, and the IMAP
289
+ read rows report **UIDs** (a different, per-mailbox namespace), so routing them
290
+ safely needs a UID-aware design (tracked on #43).
285
291
 
286
292
  Routing is conservative: only a call whose explicit `account` matches the
287
293
  configured IMAP account goes to IMAP; everything else falls through to
@@ -303,9 +309,15 @@ config. Gmail label semantics: common names (`All Mail`, `Sent`, `Trash`,
303
309
  `Spam`, `Important`, …) map to their `[Gmail]/…` IMAP paths automatically.
304
310
 
305
311
  > Note: each call currently opens its own IMAP connection (no pooling yet), so
306
- > expect a few seconds of connection overhead per call. Phase 2 (IMAP-backed
307
- > mutations + folder ops, which would also resolve the IMAP slice of
308
- > [#42](https://github.com/sweetrb/apple-mail-mcp/issues/42)) is not yet implemented.
312
+ > expect a few seconds of connection overhead per call. Phase 2 added the folder
313
+ > ops (create/rename/delete-mailbox) resolving the IMAP slice of
314
+ > [#42](https://github.com/sweetrb/apple-mail-mcp/issues/42). IMAP-backed
315
+ > message-level mutations are still future work (see #43).
316
+ >
317
+ > **iCloud:** set `APPLE_MAIL_MCP_IMAP_HOST=imap.mail.me.com`, `APPLE_MAIL_MCP_IMAP_USER`
318
+ > to your iCloud address, `APPLE_MAIL_MCP_IMAP_ACCOUNT` to the Mail account name
319
+ > (e.g. `iCloud`), and use an **app-specific password** (from appleid.apple.com)
320
+ > stored in the Keychain.
309
321
 
310
322
  ---
311
323
 
package/build/index.js CHANGED
@@ -25,7 +25,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
25
25
  import { z } from "zod";
26
26
  import { AppleMailManager } from "./services/appleMailManager.js";
27
27
  import { sendViaSmtp } from "./services/smtpMailer.js";
28
- import { isImapAccount, imapSearchMessages, imapListMessages } from "./services/imapClient.js";
28
+ import { isImapAccount, imapSearchMessages, imapListMessages, imapCreateMailbox, imapDeleteMailbox, imapRenameMailbox, } from "./services/imapClient.js";
29
29
  import { createSerialGate } from "./utils/serialize.js";
30
30
  // =============================================================================
31
31
  // Shared Validation Schemas
@@ -582,7 +582,15 @@ server.tool("get-unread-count", {
582
582
  server.tool("create-mailbox", {
583
583
  name: z.string().min(1, "Mailbox name is required"),
584
584
  account: z.string().optional().describe("Account to create the mailbox in"),
585
- }, withErrorHandling(({ name, account }) => {
585
+ }, withErrorHandling(async ({ name, account }) => {
586
+ // IMAP backend (issue #43, Phase 2): server-side folder op when this account
587
+ // is IMAP-configured; otherwise AppleScript.
588
+ if (isImapAccount(account)) {
589
+ const r = await imapCreateMailbox(name);
590
+ if (!r.success)
591
+ return errorResponse(r.error || `Failed to create mailbox "${name}"`);
592
+ return successResponse(r.info || `Mailbox "${name}" created`);
593
+ }
586
594
  const success = mailManager.createMailbox(name, account);
587
595
  if (!success) {
588
596
  return errorResponse(`Failed to create mailbox "${name}"`);
@@ -593,7 +601,13 @@ server.tool("create-mailbox", {
593
601
  server.tool("delete-mailbox", {
594
602
  name: z.string().min(1, "Mailbox name is required"),
595
603
  account: z.string().optional().describe("Account containing the mailbox"),
596
- }, withErrorHandling(({ name, account }) => {
604
+ }, withErrorHandling(async ({ name, account }) => {
605
+ if (isImapAccount(account)) {
606
+ const r = await imapDeleteMailbox(name);
607
+ if (!r.success)
608
+ return errorResponse(r.error || `Failed to delete mailbox "${name}"`);
609
+ return successResponse(r.info || `Mailbox "${name}" deleted`);
610
+ }
597
611
  const { success, error } = mailManager.deleteMailbox(name, account);
598
612
  if (!success) {
599
613
  return errorResponse(error || `Failed to delete mailbox "${name}"`);
@@ -605,7 +619,14 @@ server.tool("rename-mailbox", {
605
619
  oldName: z.string().min(1, "Current mailbox name is required"),
606
620
  newName: z.string().min(1, "New mailbox name is required"),
607
621
  account: z.string().optional().describe("Account containing the mailbox"),
608
- }, withErrorHandling(({ oldName, newName, account }) => {
622
+ }, withErrorHandling(async ({ oldName, newName, account }) => {
623
+ if (isImapAccount(account)) {
624
+ const r = await imapRenameMailbox(oldName, newName);
625
+ if (!r.success) {
626
+ return errorResponse(r.error || `Failed to rename mailbox "${oldName}" to "${newName}"`);
627
+ }
628
+ return successResponse(r.info || `Mailbox renamed from "${oldName}" to "${newName}"`);
629
+ }
609
630
  const { success, error } = mailManager.renameMailbox(oldName, newName, account);
610
631
  if (!success) {
611
632
  return errorResponse(error || `Failed to rename mailbox "${oldName}" to "${newName}"`);
@@ -46,6 +46,10 @@ interface ImapMessage {
46
46
  interface MailboxLock {
47
47
  release: () => void;
48
48
  }
49
+ interface ImapMailboxListing {
50
+ path: string;
51
+ name: string;
52
+ }
49
53
  export interface ImapClientLike {
50
54
  connect(): Promise<void>;
51
55
  getMailboxLock(path: string): Promise<MailboxLock>;
@@ -55,6 +59,18 @@ export interface ImapClientLike {
55
59
  fetch(range: string, query: Record<string, unknown>, opts: {
56
60
  uid: true;
57
61
  }): AsyncIterable<ImapMessage>;
62
+ list(): Promise<ImapMailboxListing[]>;
63
+ mailboxCreate(path: string): Promise<{
64
+ path: string;
65
+ created: boolean;
66
+ }>;
67
+ mailboxRename(path: string, newPath: string): Promise<{
68
+ path: string;
69
+ newPath: string;
70
+ }>;
71
+ mailboxDelete(path: string): Promise<{
72
+ path: string;
73
+ }>;
58
74
  logout(): Promise<void>;
59
75
  }
60
76
  export type ImapConnect = (cfg: ImapConfig) => Promise<ImapClientLike>;
@@ -71,5 +87,22 @@ export declare function imapListMessages(args: ImapSearchArgs, deps?: {
71
87
  connect?: ImapConnect;
72
88
  config?: ImapConfig;
73
89
  }): Promise<string>;
90
+ export interface ImapOpResult {
91
+ success: boolean;
92
+ error?: string;
93
+ info?: string;
94
+ }
95
+ export declare function imapCreateMailbox(name: string, deps?: {
96
+ connect?: ImapConnect;
97
+ config?: ImapConfig;
98
+ }): Promise<ImapOpResult>;
99
+ export declare function imapDeleteMailbox(name: string, deps?: {
100
+ connect?: ImapConnect;
101
+ config?: ImapConfig;
102
+ }): Promise<ImapOpResult>;
103
+ export declare function imapRenameMailbox(oldName: string, newName: string, deps?: {
104
+ connect?: ImapConnect;
105
+ config?: ImapConfig;
106
+ }): Promise<ImapOpResult>;
74
107
  export {};
75
108
  //# sourceMappingURL=imapClient.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"imapClient.d.ts","sourceRoot":"","sources":["../../src/services/imapClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"imapClient.d.ts","sourceRoot":"","sources":["../../src/services/imapClient.ts"],"names":[],"mappings":"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"}
@@ -175,3 +175,86 @@ export function imapSearchMessages(args, deps = {}) {
175
175
  export function imapListMessages(args, deps = {}) {
176
176
  return run(args, true, deps);
177
177
  }
178
+ function errText(e) {
179
+ return e instanceof Error ? e.message : String(e);
180
+ }
181
+ /** Connect, run `fn`, always log out. */
182
+ async function withClient(deps, fn) {
183
+ const cfg = deps.config ?? resolveImapConfig();
184
+ const client = await (deps.connect ?? defaultConnect)(cfg);
185
+ try {
186
+ return await fn(client, cfg);
187
+ }
188
+ finally {
189
+ await client.logout().catch(() => undefined);
190
+ }
191
+ }
192
+ /**
193
+ * Resolve a user-supplied mailbox name to an actual server path by listing the
194
+ * mailboxes and matching on full path, then leaf name (case-insensitive).
195
+ * Returns null when no such mailbox exists.
196
+ */
197
+ async function findMailboxPath(client, name) {
198
+ const wanted = name.trim().toLowerCase();
199
+ const boxes = await client.list();
200
+ const byPath = boxes.find((b) => b.path.toLowerCase() === wanted);
201
+ if (byPath)
202
+ return byPath.path;
203
+ const byName = boxes.find((b) => b.name.toLowerCase() === wanted);
204
+ return byName ? byName.path : null;
205
+ }
206
+ export function imapCreateMailbox(name, deps = {}) {
207
+ return withClient(deps, async (client) => {
208
+ try {
209
+ const res = await client.mailboxCreate(name);
210
+ return res.created
211
+ ? { success: true, info: `Created mailbox "${res.path}".` }
212
+ : { success: true, info: `Mailbox "${res.path}" already existed.` };
213
+ }
214
+ catch (e) {
215
+ return { success: false, error: `IMAP create failed for "${name}": ${errText(e)}` };
216
+ }
217
+ });
218
+ }
219
+ export function imapDeleteMailbox(name, deps = {}) {
220
+ return withClient(deps, async (client, cfg) => {
221
+ const path = await findMailboxPath(client, name);
222
+ if (!path) {
223
+ return {
224
+ success: false,
225
+ error: `Mailbox "${name}" not found on IMAP account ${cfg.accountLabel}.`,
226
+ };
227
+ }
228
+ try {
229
+ await client.mailboxDelete(path);
230
+ return {
231
+ success: true,
232
+ info: `Deleted mailbox "${path}" via IMAP (account ${cfg.accountLabel}).`,
233
+ };
234
+ }
235
+ catch (e) {
236
+ return { success: false, error: `IMAP delete failed for "${path}": ${errText(e)}` };
237
+ }
238
+ });
239
+ }
240
+ export function imapRenameMailbox(oldName, newName, deps = {}) {
241
+ return withClient(deps, async (client, cfg) => {
242
+ const path = await findMailboxPath(client, oldName);
243
+ if (!path) {
244
+ return {
245
+ success: false,
246
+ error: `Mailbox "${oldName}" not found on IMAP account ${cfg.accountLabel}.`,
247
+ };
248
+ }
249
+ try {
250
+ const res = await client.mailboxRename(path, newName);
251
+ return { success: true, info: `Renamed "${res.path}" to "${res.newPath}" via IMAP.` };
252
+ }
253
+ catch (e) {
254
+ return {
255
+ success: false,
256
+ error: `IMAP rename failed for "${path}" -> "${newName}": ${errText(e)}`,
257
+ };
258
+ }
259
+ });
260
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apple-mail-mcp",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "MCP server for Apple Mail - read, search, send, and manage emails via Claude",
5
5
  "type": "module",
6
6
  "main": "build/index.js",