reply_to_email
Reply to a specific email by providing its message ID and your response. Optionally reply to all recipients.
Instructions
Reply to an existing message identified by RFC message-id.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes | RFC message-id from search/list results | |
| body | Yes | ||
| reply_all | No |
Implementation Reference
- src/tools/reply.ts:29-46 (handler)Handler function that executes the reply logic. It calls findMessageAndAct with the AppleScript ACTION to reply (optionally reply-all), set the body content, send the reply, and return the result.
async ({ message_id, body, reply_all }) => { const result = await findMessageAndAct({ messageId: message_id, action: ACTION, extraArgs: { theBody: body, replyAllStr: reply_all ? "true" : "false", }, }); if (result === MESSAGE_NOT_FOUND) { return { content: [{ type: "text", text: `No message found with id ${message_id}` }], isError: true, }; } return { content: [{ type: "text", text: result }] }; }, ); - src/tools/reply.ts:5-9 (schema)Zod schema defining the three input parameters: message_id (string), body (string), and reply_all (boolean, defaults to false).
const schema = { message_id: z.string().describe("RFC message-id from search/list results"), body: z.string(), reply_all: z.boolean().default(false), }; - src/tools/reply.ts:23-47 (registration)Registration of the 'reply_to_email' tool on the MCP server with its description, schema, metadata, and handler callback.
export function register(server: McpServer): void { server.tool( "reply_to_email", "Reply to an existing message identified by RFC message-id.", schema, { title: "Reply to Email", readOnlyHint: false, destructiveHint: true }, async ({ message_id, body, reply_all }) => { const result = await findMessageAndAct({ messageId: message_id, action: ACTION, extraArgs: { theBody: body, replyAllStr: reply_all ? "true" : "false", }, }); if (result === MESSAGE_NOT_FOUND) { return { content: [{ type: "text", text: `No message found with id ${message_id}` }], isError: true, }; } return { content: [{ type: "text", text: result }] }; }, ); } - src/server.ts:10-38 (registration)Server-level registration: imports the register function from reply.ts and invokes it to register the reply_to_email tool on the MCP server.
import { register as registerReply } from "./tools/reply.js"; import { register as registerFlags } from "./tools/flags.js"; import { register as registerMove } from "./tools/move.js"; import { register as registerTrash } from "./tools/trash.js"; import { register as registerCreateMailbox } from "./tools/create_mailbox.js"; import { register as registerBulkMarkRead } from "./tools/bulk_mark_read.js"; import { register as registerGetUnsubscribeLink } from "./tools/get_unsubscribe_link.js"; import { register as registerListSenders } from "./tools/list_senders.js"; import { register as registerEmptyMailbox } from "./tools/empty_mailbox.js"; const server = new McpServer({ name: "mail-app-mcp", version: "1.0.0", }); registerSearch(server); registerRead(server); registerAccounts(server); registerListRecent(server); registerSend(server); registerReply(server); registerFlags(server); registerMove(server); registerTrash(server); registerCreateMailbox(server); registerBulkMarkRead(server); registerGetUnsubscribeLink(server); registerListSenders(server); registerEmptyMailbox(server); - src/lib/find-message.ts:33-94 (helper)Helper utility that finds a message by RFC ID (via locateMessage) and executes the provided AppleScript action against it, with fallback to brute-force scanning all mailboxes.
export async function findMessageAndAct(opts: FindAndActOptions): Promise<string> { const bareId = opts.messageId.replace(/^<|>$/g, ""); const extraArgs = opts.extraArgs ?? {}; const location = await locateMessage(opts.messageId); if (location) { const targetedScript = ` tell application "Mail" set acctMatches to (every account whose user name is theUser) if (count of acctMatches) = 0 then return "${NOT_FOUND_MARKER}" set acct to item 1 of acctMatches try set mb to mailbox theMbox of acct on error return "${NOT_FOUND_MARKER}" end try set candidates to (messages of mb whose message id is theMsgId) if (count of candidates) = 0 then return "${NOT_FOUND_MARKER}" set foundMsg to item 1 of candidates ${opts.action} end tell `; const baseArgs: Record<string, string> = { theMsgId: bareId, theUser: location.userName, theMbox: location.mailboxPath, }; const targetedRunArgs: { script: string; args: Record<string, string>; timeoutMs?: number } = { script: targetedScript, args: { ...baseArgs, ...extraArgs }, }; if (opts.timeoutMs !== undefined) targetedRunArgs.timeoutMs = opts.timeoutMs; const result = await runAppleScript(targetedRunArgs); if (result !== NOT_FOUND_MARKER) return result; // Fall through to brute-force on miss. } const fallbackScript = ` tell application "Mail" set foundMsg to missing value repeat with acct in accounts repeat with mb in mailboxes of acct set candidates to (messages of mb whose message id is theMsgId) if (count of candidates) > 0 then set foundMsg to item 1 of candidates exit repeat end if end repeat if foundMsg is not missing value then exit repeat end repeat if foundMsg is missing value then return "${NOT_FOUND_MARKER}" ${opts.action} end tell `; const fallbackRunArgs: { script: string; args: Record<string, string>; timeoutMs?: number } = { script: fallbackScript, args: { theMsgId: bareId, ...extraArgs }, }; if (opts.timeoutMs !== undefined) fallbackRunArgs.timeoutMs = opts.timeoutMs; return runAppleScript(fallbackRunArgs); }