@zyx1121/apple-mail-mcp 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zyx1121
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # @zyx1121/apple-mail-mcp
2
+
3
+ MCP server for Apple Mail — read, search, and manage emails via Claude Code.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ claude mcp add apple-mail -- npx @zyx1121/apple-mail-mcp
9
+ ```
10
+
11
+ ## Prerequisites
12
+
13
+ - macOS with Apple Mail configured
14
+ - Node.js >= 18
15
+ - First run will prompt for Automation permission (System Settings > Privacy & Security > Automation)
16
+
17
+ ## Tools
18
+
19
+ | Tool | Description |
20
+ |------|-------------|
21
+ | `mail_get_accounts` | List all accounts and their mailboxes |
22
+ | `mail_count_unread` | Count unread messages per account/mailbox |
23
+ | `mail_list_messages` | List messages with filters (account, mailbox, date range, unread) |
24
+ | `mail_read_message` | Read full content of a message by ID |
25
+ | `mail_search` | Search by subject, sender, or both |
26
+ | `mail_mark_read` | Mark a message as read |
27
+
28
+ ## Examples
29
+
30
+ ```
31
+ "List my mail accounts" → mail_get_accounts
32
+ "Show unread count" → mail_count_unread
33
+ "Yesterday's emails" → mail_list_messages { date_from: "2026-03-26" }
34
+ "Search for GitHub emails" → mail_search { query: "GitHub" }
35
+ "Read message 12345" → mail_read_message { message_id: 12345 }
36
+ ```
37
+
38
+ ## Limitations
39
+
40
+ - macOS only (uses AppleScript via `osascript`)
41
+ - Subject search is case-sensitive (AppleScript limitation)
42
+ - Sender/body search fetches recent messages and filters in JS (last 30 days, max 500)
43
+ - Mail.app must be running
44
+
45
+ ## License
46
+
47
+ MIT
@@ -0,0 +1,5 @@
1
+ export declare class AppleMailError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare function runAppleScript(script: string): Promise<string>;
5
+ export declare function escapeForAppleScript(str: string): string;
@@ -0,0 +1,29 @@
1
+ import { execFile } from "node:child_process";
2
+ const TIMEOUT_MS = 15_000;
3
+ export class AppleMailError extends Error {
4
+ constructor(message) {
5
+ super(message);
6
+ this.name = "AppleMailError";
7
+ }
8
+ }
9
+ export async function runAppleScript(script) {
10
+ return new Promise((resolve, reject) => {
11
+ execFile("osascript", ["-e", script], { timeout: TIMEOUT_MS }, (err, stdout, stderr) => {
12
+ if (err) {
13
+ const msg = stderr || err.message;
14
+ if (msg.includes("not running") || msg.includes("-600"))
15
+ return reject(new AppleMailError("Apple Mail is not running. Please open Mail.app and try again."));
16
+ if (msg.includes("not allowed") || msg.includes("not permitted"))
17
+ return reject(new AppleMailError("Permission denied. Grant automation access in System Settings > Privacy & Security > Automation."));
18
+ if (msg.includes("timed out") || err.code === "ETIMEDOUT")
19
+ return reject(new AppleMailError("AppleScript execution timed out."));
20
+ return reject(new AppleMailError(msg.trim()));
21
+ }
22
+ resolve(stdout.trimEnd());
23
+ });
24
+ });
25
+ }
26
+ export function escapeForAppleScript(str) {
27
+ return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
28
+ }
29
+ //# sourceMappingURL=applescript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applescript.js","sourceRoot":"","sources":["../src/applescript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc;IACjD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACrF,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,GAAG,GAAG,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC;gBAClC,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;oBACrD,OAAO,MAAM,CAAC,IAAI,cAAc,CAAC,gEAAgE,CAAC,CAAC,CAAC;gBACtG,IAAI,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC;oBAC9D,OAAO,MAAM,CAAC,IAAI,cAAc,CAAC,kGAAkG,CAAC,CAAC,CAAC;gBACxI,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAK,GAA6B,CAAC,IAAI,KAAK,WAAW;oBAClF,OAAO,MAAM,CAAC,IAAI,cAAc,CAAC,kCAAkC,CAAC,CAAC,CAAC;gBACxE,OAAO,MAAM,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YAChD,CAAC;YACD,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,19 @@
1
+ export declare function success(data: unknown): {
2
+ content: {
3
+ type: "text";
4
+ text: string;
5
+ }[];
6
+ };
7
+ export declare function error(message: string): {
8
+ content: {
9
+ type: "text";
10
+ text: string;
11
+ }[];
12
+ isError: true;
13
+ };
14
+ export declare function withErrorHandling<T extends Record<string, unknown>>(fn: (args: T) => Promise<ReturnType<typeof success | typeof error>>): (args: T) => Promise<{
15
+ content: {
16
+ type: "text";
17
+ text: string;
18
+ }[];
19
+ }>;
@@ -0,0 +1,25 @@
1
+ import { AppleMailError } from "./applescript.js";
2
+ export function success(data) {
3
+ return {
4
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
5
+ };
6
+ }
7
+ export function error(message) {
8
+ return {
9
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }],
10
+ isError: true,
11
+ };
12
+ }
13
+ export function withErrorHandling(fn) {
14
+ return async (args) => {
15
+ try {
16
+ return await fn(args);
17
+ }
18
+ catch (e) {
19
+ if (e instanceof AppleMailError)
20
+ return error(e.message);
21
+ throw e;
22
+ }
23
+ };
24
+ }
25
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,UAAU,OAAO,CAAC,IAAa;IACnC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KAC1E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,OAAe;IACnC,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QAC9E,OAAO,EAAE,IAAa;KACvB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,EAAmE;IAEnE,OAAO,KAAK,EAAE,IAAO,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,cAAc;gBAAE,OAAO,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACzD,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { createServer } from "./server.js";
4
+ if (process.platform !== "darwin") {
5
+ console.error("apple-mail-mcp requires macOS with Apple Mail.");
6
+ process.exit(1);
7
+ }
8
+ const server = createServer();
9
+ const transport = new StdioServerTransport();
10
+ await server.connect(transport);
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;IAClC,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function createServer(): McpServer;
package/dist/server.js ADDED
@@ -0,0 +1,15 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { registerAccountTools } from "./tools/accounts.js";
3
+ import { registerMessageTools } from "./tools/messages.js";
4
+ import { registerSearchTools } from "./tools/search.js";
5
+ export function createServer() {
6
+ const server = new McpServer({
7
+ name: "apple-mail",
8
+ version: "0.1.0",
9
+ });
10
+ registerAccountTools(server);
11
+ registerMessageTools(server);
12
+ registerSearchTools(server);
13
+ return server;
14
+ }
15
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE5B,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerAccountTools(server: McpServer): void;
@@ -0,0 +1,62 @@
1
+ import { z } from "zod";
2
+ import { runAppleScript } from "../applescript.js";
3
+ import { success, withErrorHandling } from "../helpers.js";
4
+ export function registerAccountTools(server) {
5
+ server.tool("mail_get_accounts", "List all mail accounts and their mailboxes", {}, withErrorHandling(async () => {
6
+ const accountNames = await runAppleScript(`tell application "Mail" to get name of every account`);
7
+ if (!accountNames)
8
+ return success([]);
9
+ const names = accountNames.split(", ");
10
+ const accounts = [];
11
+ for (const name of names) {
12
+ const mailboxes = await runAppleScript(`tell application "Mail" to get name of every mailbox of account "${name}"`);
13
+ accounts.push({
14
+ name,
15
+ mailboxes: mailboxes ? mailboxes.split(", ") : [],
16
+ });
17
+ }
18
+ return success(accounts);
19
+ }));
20
+ server.tool("mail_count_unread", "Count unread messages in a mailbox", {
21
+ account: z.string().optional().describe("Account name (e.g. 'iCloud', 'Gmail'). Omit for all accounts."),
22
+ mailbox: z.string().optional().describe("Mailbox name (e.g. 'INBOX'). Omit for inbox."),
23
+ }, withErrorHandling(async ({ account, mailbox }) => {
24
+ if (account) {
25
+ const target = mailbox
26
+ ? `mailbox "${mailbox}" of account "${account}"`
27
+ : `inbox`;
28
+ const count = await runAppleScript(`tell application "Mail" to get unread count of ${target}`);
29
+ return success({ account, mailbox: mailbox || "INBOX", unread: parseInt(count, 10) });
30
+ }
31
+ // All accounts
32
+ const accountNames = await runAppleScript(`tell application "Mail" to get name of every account`);
33
+ if (!accountNames)
34
+ return success([]);
35
+ const results = [];
36
+ for (const name of accountNames.split(", ")) {
37
+ const script = `
38
+ tell application "Mail"
39
+ set acct to account "${name}"
40
+ set output to ""
41
+ repeat with mbox in every mailbox of acct
42
+ set cnt to unread count of mbox
43
+ if cnt > 0 then
44
+ set output to output & (name of mbox) & "\\t" & cnt & "\\n"
45
+ end if
46
+ end repeat
47
+ return output
48
+ end tell`;
49
+ const raw = await runAppleScript(script);
50
+ if (!raw)
51
+ continue;
52
+ for (const line of raw.split("\n")) {
53
+ if (!line)
54
+ continue;
55
+ const [mboxName, cnt] = line.split("\t");
56
+ results.push({ account: name, mailbox: mboxName, unread: parseInt(cnt, 10) });
57
+ }
58
+ }
59
+ return success(results);
60
+ }));
61
+ }
62
+ //# sourceMappingURL=accounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../src/tools/accounts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerMessageTools(server: McpServer): void;
@@ -0,0 +1,160 @@
1
+ import { z } from "zod";
2
+ import { runAppleScript, escapeForAppleScript } from "../applescript.js";
3
+ import { success, error, withErrorHandling } from "../helpers.js";
4
+ function buildMailboxTarget(account, mailbox) {
5
+ if (account && mailbox)
6
+ return `mailbox "${mailbox}" of account "${account}"`;
7
+ if (account)
8
+ return `inbox of account "${account}"`;
9
+ return "inbox";
10
+ }
11
+ function formatDate(isoDate) {
12
+ const d = new Date(isoDate);
13
+ return d.toLocaleDateString("en-US", {
14
+ weekday: "long", year: "numeric", month: "long", day: "numeric",
15
+ hour: "numeric", minute: "numeric", second: "numeric",
16
+ });
17
+ }
18
+ function parseMessages(raw) {
19
+ if (!raw)
20
+ return [];
21
+ const messages = [];
22
+ for (const line of raw.split("\n")) {
23
+ if (!line)
24
+ continue;
25
+ const parts = line.split("\t");
26
+ if (parts.length < 5)
27
+ continue;
28
+ messages.push({
29
+ id: parseInt(parts[0], 10),
30
+ subject: parts[1],
31
+ sender: parts[2],
32
+ date: parts[3],
33
+ read: parts[4] === "true",
34
+ });
35
+ }
36
+ return messages;
37
+ }
38
+ export function registerMessageTools(server) {
39
+ server.tool("mail_list_messages", "List messages in a mailbox with optional filters", {
40
+ account: z.string().optional().describe("Account name"),
41
+ mailbox: z.string().optional().describe("Mailbox name (default: INBOX)"),
42
+ limit: z.number().int().positive().max(100).default(20).describe("Max messages to return"),
43
+ unread_only: z.boolean().default(false).describe("Only show unread messages"),
44
+ date_from: z.string().optional().describe("ISO 8601 date, e.g. '2026-03-26'"),
45
+ date_to: z.string().optional().describe("ISO 8601 date, e.g. '2026-03-27'"),
46
+ }, withErrorHandling(async ({ account, mailbox, limit, unread_only, date_from, date_to }) => {
47
+ const target = buildMailboxTarget(account, mailbox);
48
+ const conditions = [];
49
+ if (unread_only)
50
+ conditions.push("read status is false");
51
+ if (date_from)
52
+ conditions.push(`date received >= date "${formatDate(date_from)}"`);
53
+ if (date_to)
54
+ conditions.push(`date received <= date "${formatDate(date_to)}"`);
55
+ const whereClause = conditions.length > 0
56
+ ? ` whose ${conditions.join(" and ")}`
57
+ : "";
58
+ const script = `
59
+ tell application "Mail"
60
+ set msgs to (every message of ${target}${whereClause})
61
+ set maxCount to ${limit}
62
+ if (count of msgs) < maxCount then set maxCount to (count of msgs)
63
+ set output to ""
64
+ repeat with i from 1 to maxCount
65
+ set m to item i of msgs
66
+ set output to output & (id of m) & "\\t" & (subject of m) & "\\t" & (sender of m) & "\\t" & (date received of m as string) & "\\t" & (read status of m) & "\\n"
67
+ end repeat
68
+ return output
69
+ end tell`;
70
+ const raw = await runAppleScript(script);
71
+ return success(parseMessages(raw));
72
+ }));
73
+ server.tool("mail_read_message", "Read the full content of a specific message", {
74
+ message_id: z.number().int().describe("Message ID"),
75
+ account: z.string().optional().describe("Account name (speeds up lookup)"),
76
+ mailbox: z.string().optional().describe("Mailbox name (speeds up lookup)"),
77
+ }, withErrorHandling(async ({ message_id, account, mailbox }) => {
78
+ // If account and mailbox provided, direct lookup
79
+ if (account) {
80
+ const target = mailbox
81
+ ? `mailbox "${escapeForAppleScript(mailbox)}" of account "${escapeForAppleScript(account)}"`
82
+ : `inbox of account "${escapeForAppleScript(account)}"`;
83
+ const script = `
84
+ tell application "Mail"
85
+ set m to message id ${message_id} of ${target}
86
+ set subj to subject of m
87
+ set sndr to sender of m
88
+ set rcvd to date received of m as string
89
+ set rd to read status of m
90
+ set cnt to content of m
91
+ set toList to address of every to recipient of m
92
+ set ccList to address of every cc recipient of m
93
+ return subj & "\\n===FIELD===\\n" & sndr & "\\n===FIELD===\\n" & rcvd & "\\n===FIELD===\\n" & rd & "\\n===FIELD===\\n" & cnt & "\\n===FIELD===\\n" & toList & "\\n===FIELD===\\n" & ccList
94
+ end tell`;
95
+ const raw = await runAppleScript(script);
96
+ const fields = raw.split("\n===FIELD===\n");
97
+ return success({
98
+ id: message_id,
99
+ subject: fields[0] || "",
100
+ sender: fields[1] || "",
101
+ date: fields[2] || "",
102
+ read: fields[3] === "true",
103
+ content: fields[4] || "",
104
+ to: fields[5] || "",
105
+ cc: fields[6] || "",
106
+ });
107
+ }
108
+ // Scan all accounts' inboxes
109
+ const accountNames = await runAppleScript(`tell application "Mail" to get name of every account`);
110
+ if (!accountNames)
111
+ return error(`Message ${message_id} not found.`);
112
+ for (const acctName of accountNames.split(", ")) {
113
+ try {
114
+ const script = `
115
+ tell application "Mail"
116
+ set m to message id ${message_id} of inbox of account "${acctName}"
117
+ set subj to subject of m
118
+ set sndr to sender of m
119
+ set rcvd to date received of m as string
120
+ set rd to read status of m
121
+ set cnt to content of m
122
+ set toList to address of every to recipient of m
123
+ set ccList to address of every cc recipient of m
124
+ return subj & "\\n===FIELD===\\n" & sndr & "\\n===FIELD===\\n" & rcvd & "\\n===FIELD===\\n" & rd & "\\n===FIELD===\\n" & cnt & "\\n===FIELD===\\n" & toList & "\\n===FIELD===\\n" & ccList
125
+ end tell`;
126
+ const raw = await runAppleScript(script);
127
+ const fields = raw.split("\n===FIELD===\n");
128
+ return success({
129
+ id: message_id,
130
+ account: acctName,
131
+ subject: fields[0] || "",
132
+ sender: fields[1] || "",
133
+ date: fields[2] || "",
134
+ read: fields[3] === "true",
135
+ content: fields[4] || "",
136
+ to: fields[5] || "",
137
+ cc: fields[6] || "",
138
+ });
139
+ }
140
+ catch {
141
+ continue; // Not in this account, try next
142
+ }
143
+ }
144
+ return error(`Message ${message_id} not found in any inbox.`);
145
+ }));
146
+ server.tool("mail_mark_read", "Mark a message as read", {
147
+ message_id: z.number().int().describe("Message ID"),
148
+ account: z.string().optional().describe("Account name"),
149
+ mailbox: z.string().optional().describe("Mailbox name"),
150
+ }, withErrorHandling(async ({ message_id, account, mailbox }) => {
151
+ const target = account
152
+ ? (mailbox
153
+ ? `mailbox "${escapeForAppleScript(mailbox)}" of account "${escapeForAppleScript(account)}"`
154
+ : `inbox of account "${escapeForAppleScript(account)}"`)
155
+ : "inbox";
156
+ await runAppleScript(`tell application "Mail" to set read status of message id ${message_id} of ${target} to true`);
157
+ return success({ message_id, marked_read: true });
158
+ }));
159
+ }
160
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/tools/messages.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElE,SAAS,kBAAkB,CAAC,OAAgB,EAAE,OAAgB;IAC5D,IAAI,OAAO,IAAI,OAAO;QAAE,OAAO,YAAY,OAAO,iBAAiB,OAAO,GAAG,CAAC;IAC9E,IAAI,OAAO;QAAE,OAAO,qBAAqB,OAAO,GAAG,CAAC;IACpD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,UAAU,CAAC,OAAe;IACjC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,CAAC,kBAAkB,CAAC,OAAO,EAAE;QACnC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS;QAC/D,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS;KACtD,CAAC,CAAC;AACL,CAAC;AAUD,SAAS,aAAa,CAAC,GAAW;IAChC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,QAAQ,GAAqB,EAAE,CAAC;IACtC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAC/B,QAAQ,CAAC,IAAI,CAAC;YACZ,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC1B,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;YACjB,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;YAChB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;YACd,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM;SAC1B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,kDAAkD,EAClD;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;QACvD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QACxE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QAC1F,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QAC7E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QAC7E,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;KAC5E,EACD,iBAAiB,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE;QACvF,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAEpD,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,IAAI,WAAW;YAAE,UAAU,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACzD,IAAI,SAAS;YAAE,UAAU,CAAC,IAAI,CAAC,0BAA0B,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnF,IAAI,OAAO;YAAE,UAAU,CAAC,IAAI,CAAC,0BAA0B,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAE/E,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC;YACvC,CAAC,CAAC,UAAU,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YACtC,CAAC,CAAC,EAAE,CAAC;QAEP,MAAM,MAAM,GAAG;;kCAEa,MAAM,GAAG,WAAW;oBAClC,KAAK;;;;;;;;SAQhB,CAAC;QAEJ,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;QACzC,OAAO,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;IACrC,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,6CAA6C,EAC7C;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;QACnD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;QAC1E,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;KAC3E,EACD,iBAAiB,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;QAC3D,iDAAiD;QACjD,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,MAAM,GAAG,OAAO;gBACpB,CAAC,CAAC,YAAY,oBAAoB,CAAC,OAAO,CAAC,iBAAiB,oBAAoB,CAAC,OAAO,CAAC,GAAG;gBAC5F,CAAC,CAAC,qBAAqB,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC;YAE1D,MAAM,MAAM,GAAG;;wBAEC,UAAU,OAAO,MAAM;;;;;;;;;SAStC,CAAC;YAEF,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;YACzC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;YAC5C,OAAO,OAAO,CAAC;gBACb,EAAE,EAAE,UAAU;gBACd,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;gBACxB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;gBACvB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;gBACrB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM;gBAC1B,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;gBACxB,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;gBACnB,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;aACpB,CAAC,CAAC;QACL,CAAC;QAED,6BAA6B;QAC7B,MAAM,YAAY,GAAG,MAAM,cAAc,CACvC,sDAAsD,CACvD,CAAC;QACF,IAAI,CAAC,YAAY;YAAE,OAAO,KAAK,CAAC,WAAW,UAAU,aAAa,CAAC,CAAC;QAEpE,KAAK,MAAM,QAAQ,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG;;wBAED,UAAU,yBAAyB,QAAQ;;;;;;;;;SAS1D,CAAC;gBACA,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;gBACzC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;gBAC5C,OAAO,OAAO,CAAC;oBACb,EAAE,EAAE,UAAU;oBACd,OAAO,EAAE,QAAQ;oBACjB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;oBACxB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;oBACvB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;oBACrB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM;oBAC1B,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;oBACxB,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;oBACnB,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;iBACpB,CAAC,CAAC;YACL,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,CAAC,gCAAgC;YAC5C,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,WAAW,UAAU,0BAA0B,CAAC,CAAC;IAChE,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,wBAAwB,EACxB;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;QACnD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;QACvD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;KACxD,EACD,iBAAiB,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;QAC3D,MAAM,MAAM,GAAG,OAAO;YACpB,CAAC,CAAC,CAAC,OAAO;gBACR,CAAC,CAAC,YAAY,oBAAoB,CAAC,OAAO,CAAC,iBAAiB,oBAAoB,CAAC,OAAO,CAAC,GAAG;gBAC5F,CAAC,CAAC,qBAAqB,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC;YAC1D,CAAC,CAAC,OAAO,CAAC;QAEZ,MAAM,cAAc,CAClB,4DAA4D,UAAU,OAAO,MAAM,UAAU,CAC9F,CAAC;QACF,OAAO,OAAO,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSearchTools(server: McpServer): void;
@@ -0,0 +1,80 @@
1
+ import { z } from "zod";
2
+ import { runAppleScript, escapeForAppleScript } from "../applescript.js";
3
+ import { success, withErrorHandling } from "../helpers.js";
4
+ function parseMessages(raw) {
5
+ if (!raw)
6
+ return [];
7
+ const messages = [];
8
+ for (const line of raw.split("\n")) {
9
+ if (!line)
10
+ continue;
11
+ const parts = line.split("\t");
12
+ if (parts.length < 5)
13
+ continue;
14
+ messages.push({
15
+ id: parseInt(parts[0], 10),
16
+ subject: parts[1],
17
+ sender: parts[2],
18
+ date: parts[3],
19
+ read: parts[4] === "true",
20
+ });
21
+ }
22
+ return messages;
23
+ }
24
+ export function registerSearchTools(server) {
25
+ server.tool("mail_search", "Search messages by subject or sender", {
26
+ query: z.string().min(1).describe("Search keyword"),
27
+ field: z.enum(["subject", "sender", "all"]).default("all").describe("Field to search"),
28
+ account: z.string().optional().describe("Account name"),
29
+ mailbox: z.string().optional().describe("Mailbox name (default: INBOX)"),
30
+ limit: z.number().int().positive().max(50).default(10).describe("Max results"),
31
+ }, withErrorHandling(async ({ query, field, account, mailbox, limit }) => {
32
+ const escaped = escapeForAppleScript(query);
33
+ const target = account
34
+ ? (mailbox
35
+ ? `mailbox "${escapeForAppleScript(mailbox)}" of account "${escapeForAppleScript(account)}"`
36
+ : `inbox of account "${escapeForAppleScript(account)}"`)
37
+ : "inbox";
38
+ // Subject search: use native AppleScript filter
39
+ if (field === "subject") {
40
+ const script = `
41
+ tell application "Mail"
42
+ set msgs to (every message of ${target} whose subject contains "${escaped}")
43
+ set maxCount to ${limit}
44
+ if (count of msgs) < maxCount then set maxCount to (count of msgs)
45
+ set output to ""
46
+ repeat with i from 1 to maxCount
47
+ set m to item i of msgs
48
+ set output to output & (id of m) & "\\t" & (subject of m) & "\\t" & (sender of m) & "\\t" & (date received of m as string) & "\\t" & (read status of m) & "\\n"
49
+ end repeat
50
+ return output
51
+ end tell`;
52
+ return success(parseMessages(await runAppleScript(script)));
53
+ }
54
+ // Sender or all: fetch recent messages, filter in JS
55
+ const fetchLimit = 500;
56
+ const script = `
57
+ tell application "Mail"
58
+ set thirtyDaysAgo to (current date) - 30 * days
59
+ set msgs to (every message of ${target} whose date received >= thirtyDaysAgo)
60
+ set maxCount to ${fetchLimit}
61
+ if (count of msgs) < maxCount then set maxCount to (count of msgs)
62
+ set output to ""
63
+ repeat with i from 1 to maxCount
64
+ set m to item i of msgs
65
+ set output to output & (id of m) & "\\t" & (subject of m) & "\\t" & (sender of m) & "\\t" & (date received of m as string) & "\\t" & (read status of m) & "\\n"
66
+ end repeat
67
+ return output
68
+ end tell`;
69
+ const all = parseMessages(await runAppleScript(script));
70
+ const q = query.toLowerCase();
71
+ const filtered = all.filter((m) => {
72
+ if (field === "sender")
73
+ return m.sender.toLowerCase().includes(q);
74
+ // "all" — match subject or sender
75
+ return m.subject.toLowerCase().includes(q) || m.sender.toLowerCase().includes(q);
76
+ });
77
+ return success(filtered.slice(0, limit));
78
+ }));
79
+ }
80
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAU3D,SAAS,aAAa,CAAC,GAAW;IAChC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,QAAQ,GAAqB,EAAE,CAAC;IACtC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAC/B,QAAQ,CAAC,IAAI,CAAC;YACZ,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC1B,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;YACjB,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;YAChB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;YACd,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM;SAC1B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,aAAa,EACb,sCAAsC,EACtC;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QACnD,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QACtF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;QACvD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QACxE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC;KAC/E,EACD,iBAAiB,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;QACpE,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,OAAO;YACpB,CAAC,CAAC,CAAC,OAAO;gBACR,CAAC,CAAC,YAAY,oBAAoB,CAAC,OAAO,CAAC,iBAAiB,oBAAoB,CAAC,OAAO,CAAC,GAAG;gBAC5F,CAAC,CAAC,qBAAqB,oBAAoB,CAAC,OAAO,CAAC,GAAG,CAAC;YAC1D,CAAC,CAAC,OAAO,CAAC;QAEZ,gDAAgD;QAChD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG;;kCAEW,MAAM,4BAA4B,OAAO;oBACvD,KAAK;;;;;;;;SAQhB,CAAC;YACF,OAAO,OAAO,CAAC,aAAa,CAAC,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;QAED,qDAAqD;QACrD,MAAM,UAAU,GAAG,GAAG,CAAC;QACvB,MAAM,MAAM,GAAG;;;kCAGa,MAAM;oBACpB,UAAU;;;;;;;;SAQrB,CAAC;QAEJ,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QAE9B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YAChC,IAAI,KAAK,KAAK,QAAQ;gBAAE,OAAO,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAClE,kCAAkC;YAClC,OAAO,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACnF,CAAC,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@zyx1121/apple-mail-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Apple Mail — read, search, and manage emails via Claude Code",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "apple-mail-mcp": "./dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "mcp",
20
+ "apple-mail",
21
+ "claude",
22
+ "email",
23
+ "macos"
24
+ ],
25
+ "author": "zyx1121",
26
+ "license": "MIT",
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.12.1",
32
+ "zod": "^3.25.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^20.0.0",
36
+ "typescript": "^5.0.0"
37
+ }
38
+ }