imail-mcp
by nurked
README.md
# imail-mcp
> π·πΊ **ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ Π½Π° ΡΡΡΡΠΊΠΎΠΌ:** [README.ru.md](README.ru.md)
An [MCP](https://modelcontextprotocol.io) server that connects Claude
(Cowork / Claude Code / Claude Desktop) to your email so it can
**read, search, send, and organize** your mail β directly from a conversation.
Runs as a **resident background service** (launchd) with a **web admin UI**,
serving all your Claude clients over one Streamable HTTP endpoint β or as a
classic per-client stdio server. **iCloud Mail** is the first supported
provider; the internals are written against a provider-agnostic interface, so
Gmail / Microsoft 365 adapters can be added later without touching a single
tool.
---
## Highlights
- π₯οΈ **Runs as a service** β one long-lived process (launchd LaunchAgent,
auto-start at login, auto-restart) shared by every MCP client over
Streamable HTTP; stdio mode still works for per-client setups.
- π **Web admin UI** β connect/disconnect Apple accounts, check live
connection status, copy ready-made client configs, tail the service log β
all at `http://127.0.0.1:4577`, localhost-only.
- π₯ **Multiple accounts** β connect several iCloud accounts; every tool takes
an optional `account` parameter.
- π₯ **Read & search** β folders, search with paging, full messages and whole
threads, bulk fetch up to 20 full messages per call, attachments.
- βοΈ **Send & reply** β compose, reply, reply-all, forward with correct
threading headers.
- ποΈ **Organize, in bulk** β move / archive / delete / flag up to 200 messages
per call as a **single IMAP command**.
- π **Credentials stay local** β account passwords and the service's access
token live in the **macOS Keychain**, never in a plaintext file or env var.
- π **Never sends silently** β Claude must preview an email and get your
approval first; on clients that support MCP **elicitation**, the server
additionally asks *you* to confirm in-app before anything is sent.
---
## The Mac app
The nicest way to run imail-mcp is the **menu-bar app** in [`app/`](app/README.md):
a signed, notarizable `iMail MCP.app` that bundles the whole service as a
self-contained binary (no Node required), shows live status in the menu bar,
opens the control panel in its own window, and starts at login. Build it with
`cd app && npm install && npm run tauri build`, then drag the `.app` from
`app/src-tauri/target/release/bundle/macos/` into /Applications. On first
launch it takes over from the CLI-installed launchd service automatically.
Everything below β the CLI service, stdio mode, tools, security model β works
the same with or without the app; the app is just a shell that owns the
service process.
## Quick start (CLI, no app)
Requires **Node.js β₯ 18** and macOS.
```bash
git clone git@github.com:nurked/icloud-mail-mcp.git
cd icloud-mail-mcp
npm install
npm run build
node dist/index.js service install # register + start the background service
node dist/index.js ui # open the admin UI in your browser
```
In the admin UI:
1. **Accounts tab** β connect your iCloud account (see the app-specific
password note below). The login is verified live over IMAP, then stored in
your Keychain.
2. **Clients tab** β copy the ready-made one-liner for Claude Code, or the
JSON block for Claude Desktop. Done.
> Installing globally (`npm link` or `npm i -g .`) gives you the `imail-mcp`
> command used in the examples below; otherwise use
> `node dist/index.js <command>`.
### CLI reference
```
imail-mcp stdio MCP server (for per-client mcpServers configs)
imail-mcp serve [--port N] run the HTTP service in the foreground
imail-mcp ui open the admin UI (authenticated) in your browser
imail-mcp service install install + start the launchd LaunchAgent
imail-mcp service status show whether the service is installed/running
imail-mcp service uninstall stop and remove the LaunchAgent
```
Default port: **4577**. Logs: `~/Library/Logs/imail-mcp/imail-mcp.log`.
### Generating the app-specific password
Apple does **not** offer OAuth for iCloud Mail β the only supported path is
IMAP/SMTP with an app-specific password (every iCloud account has 2FA):
1. Open [appleid.apple.com](https://appleid.apple.com/account/manage) β
**Sign-In and Security β App-Specific Passwords**.
2. Click **Generate an app-specific password**, name it `imail-mcp`.
3. Paste the 16-character password into the admin UI.
---
## Wire it into Claude
**Preferred β the shared service** (copy the exact command, with your token
filled in, from the admin UI's *Clients* tab):
```bash
claude mcp add --transport http imail http://127.0.0.1:4577/mcp \
--header "Authorization: Bearer <token>"
```
Claude Desktop (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"imail": {
"type": "http",
"url": "http://127.0.0.1:4577/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}
```
**Fallback β per-client stdio** (each client spawns its own process; no
service needed):
```json
{
"mcpServers": {
"imail": { "command": "node", "args": ["/absolute/path/to/dist/index.js"] }
}
}
```
---
## Security model
- The HTTP service binds to **127.0.0.1 only** and validates the `Host`
header (DNS-rebinding protection, plus the MCP SDK's own check).
- The `/mcp` endpoint requires a **bearer token**, generated on first run and
stored in the Keychain β without it, other local processes can't read or
send your mail through the service.
- The admin UI uses a one-time token URL (`imail-mcp ui`) exchanged for an
HttpOnly, SameSite=Strict session cookie; mutating API calls additionally
require a custom header (CSRF).
- Sending tools are gated three ways: prompt discipline (preview first), tool
annotations (`destructiveHint` on sends/deletes), and **elicitation** β on
supporting clients the server asks you to confirm each send in-app, and a
declined confirmation returns `sent: false`.
---
## Tools
| Tool | What it does |
| --- | --- |
| `list_accounts` | Connected accounts and their live connection status |
| `list_mailboxes` | Folders with IMAP paths and special-use roles |
| `search_messages` | Search by from / to / subject / text / date / unread, with `limit` + `offset` paging |
| `get_message` | Full headers, text + HTML body, attachment metadata |
| `get_messages` | **Bulk fetch** up to 20 full messages in one call (missing UIDs reported, not fatal) |
| `get_thread` | The whole conversation, oldest β newest |
| `download_attachment` | Save an attachment to a temp file; returns path + resource link |
| `compose_preview` | Build an email for review β **does not send** |
| `send_email` | Send now (after your approval; elicitation-confirmed where supported) |
| `save_draft` | Put it in Drafts for you to send yourself |
| `reply` | Reply / reply-all, threading headers set from the original |
| `forward` | Forward to new recipients with a quoted header |
| `move_message` / `bulk_move` | Move one / up to 200 messages |
| `set_flags` / `bulk_set_flags` | Read/unread, flag/unflag β one / up to 200 |
| `archive_message` / `bulk_archive` | Move to Archive β one / up to 200 |
| `delete_message` / `bulk_delete` | Move to Trash (expunge if already there) β one / up to 200 |
Every tool takes an optional `account` parameter (omit when only one account
is connected). Bulk operations execute as a **single IMAP command** (UID
set), not N round-trips. All tools declare MCP **tool annotations**
(read-only / destructive / idempotent hints) and **output schemas**
(structured content), per the 2025-06-18+ MCP spec.
---
## How it works
```
Claude Code ββ
Claude Desktop ββ€ Streamable HTTP (127.0.0.1:4577/mcp, bearer token)
Cowork ββ β
βΌ
imail-mcp service (launchd) ββIMAP (imap.mail.me.com:993)βββΆ iCloud
β admin UI at / ββSMTP (smtp.mail.me.com:587)βββΆ iCloud
ββ credentials + token βββ macOS Keychain
account registry βββ ~/Library/Application Support/imail-mcp/
```
- **IMAP** ([imapflow](https://www.npmjs.com/package/imapflow)) reads and
organizes; **SMTP** ([nodemailer](https://nodemailer.com)) sends; bodies are
parsed with [mailparser](https://www.npmjs.com/package/mailparser).
- A shared **provider pool** keeps one live IMAP connection per account, with
keepalive and transparent reconnect (dead sockets retry once).
- Connections are **lazy** β adding the server to Claude doesn't touch your
mailbox until you actually use it.
- Built on MCP SDK 1.x (spec line 2025-06-18 / 2025-11-25). The transport
layer is isolated in `src/http/`, so migrating to the stateless 2026-07-28
spec / SDK v2 is a contained change.
### Project layout
```
src/
index.ts CLI: stdio server, serve, ui, service subcommands
mcp.ts MCP server factory: tools, schemas, annotations, elicitation
bin/setup.ts `imail-mcp-setup` β foreground service + admin UI (legacy entry)
accounts/
registry.ts non-secret account registry (accounts.json)
pool.ts provider pool: lazy connect, keepalive, add/remove accounts
auth/
keychain.ts Keychain storage: per-account credentials + HTTP token
http/
server.ts HTTP service: /mcp (session map), /auth, /api, admin UI
ui.ts admin UI page (no framework, no build step)
service/
launchd.ts LaunchAgent install/uninstall/status
providers/
types.ts provider-agnostic MailProvider contract
icloud.ts iCloud IMAP/SMTP implementation (incl. bulk ops)
```
---
## Adding another provider
The tools only ever talk to the `MailProvider` interface, so a new backend is
one new file:
1. Implement `MailProvider` (see
[`src/providers/types.ts`](src/providers/types.ts)) in a new file under
`src/providers/`.
2. Wire it up in [`src/accounts/pool.ts`](src/accounts/pool.ts).
The tools stay unchanged.
---
## Troubleshooting
- **"No mail accounts are connected"** β open the admin UI (`imail-mcp ui`)
and connect an account on the *Accounts* tab.
- **"Login failed"** when connecting β make sure you used an **app-specific
password**, not your normal Apple ID password.
- **`imail-mcp ui` says the service isn't answering** β start it:
`imail-mcp service install` (persistent) or `imail-mcp serve` (foreground).
- **Port already in use** β pass `--port N` to `serve` / `service install`,
and update your client configs accordingly.
- **Upgrading from β€0.1** β the old single-account Keychain entry is migrated
automatically on first run; existing stdio client configs keep working.
- **Service logs** β `~/Library/Logs/imail-mcp/imail-mcp.log` (also shown in
the admin UI's *Service* tab).
---
## License
**[PolyForm Noncommercial License 1.0.0](LICENSE.md)** β this is *source-available*,
not OSI open source.
- β
**Free** for any **noncommercial** purpose β personal use, study, research,
hobby projects, and use by nonprofits, schools, and government bodies.
- β
You may read, modify, and redistribute it; the **copyright notice must stay
intact**, so your work is always credited.
- πΌ **Commercial use requires a separate license.** If you want to use imail-mcp
to make money β in a product, a paid service, or inside a for-profit company β
contact Investment Fidelity Company at **ceo@investmentfidelity.company** to
arrange a commercial license.
See [LICENSE.md](LICENSE.md) for the full terms.
TDQS
B3.4/5.0
Scored across 14 tools
Disambiguation5/5
Each tool targets a distinct email operation (e.g., archive vs delete vs move, compose vs send vs save draft, forward vs reply). No two tools have overlapping purposes.
Naming Consistency4/5
Most tools follow verb_noun pattern (e.g., archive_message, delete_message). 'forward' and 'reply' are just verbs, which is a minor inconsistency but still clear.
Tool Count5/5
14 tools cover essential email operations (send, receive, manage folders, flags, attachments, threads) without being excessive.
Completeness4/5
Covers major email lifecycle (send, receive, delete, move, flag, search, thread). Minor gaps: no direct edit draft or empty trash, but key workflows are supported.
Maintenance
ActivitySlowing
ResponsivenessNo issues