https://github.com/like-a-freedom/rusty_apple_mail_mcp
Local-first Apple Mail MCP
https://github.com/like-a-freedom/rusty_apple_mail_mcp
apple-mail claude email mcp mcp-server model-context-protocol rmcp rust vscode
Last synced: 3 months ago
JSON representation
Local-first Apple Mail MCP
- Host: GitHub
- URL: https://github.com/like-a-freedom/rusty_apple_mail_mcp
- Owner: like-a-freedom
- Created: 2026-03-22T08:34:44.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-04-10T11:57:54.000Z (4 months ago)
- Last Synced: 2026-04-10T13:12:02.702Z (4 months ago)
- Topics: apple-mail, claude, email, mcp, mcp-server, model-context-protocol, rmcp, rust, vscode
- Language: Rust
- Homepage:
- Size: 279 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Rusty Apple Mail MCP Server





Read-only MCP server for Apple Mail on macOS.
It gives an LLM or AI agent fast local access to Apple Mail metadata, message bodies, and attachment text **without AppleScript and without IMAP/POP/EWS network calls**.
## Why this matters
Apple Mail already contains the data an agent needs, but it is buried in a local SQLite index and scattered `.emlx` files.
This project exposes that storage through a small, intent-driven MCP interface so an agent can:
- locate messages by subject, date range, sender, participant, mailbox, or account;
- fetch a full message including metadata, recipients, body, and attachment summary;
- extract readable text from supported attachments;
- operate completely **locally** and **read-only**.
In practice, it empowers AI workflows to search and read your mail archive safely and quickly, without relying on Mail.app automation like AppleScript (which damn slow and throws timeouts regularly) or network protocols.
## What the server can do
The current tool set is intentionally compact:
| Tool | What it does |
|---|---|
| `search_messages` | Search by subject, dates, sender, participant, account, or mailbox |
| `list_accounts` | Discover account identifiers; set `include_mailboxes=true` for combined account+mailbox discovery |
| `get_message` | Read one message in full; recipients omitted by default (`include_recipients=true` to include) |
| `get_attachment_content` | Extract readable attachment content |
| `list_mailboxes` | List mailboxes/folders with message counts |
## Installation
### Prerequisites
- macOS
- Apple Mail installed and synced at least once
- Rust toolchain (`rustup`, `cargo`)
### Build from source
```bash
cargo build --release
```
### Install locally
```bash
cargo install --path .
```
This installs the binary under the name `rusty_apple_mail_mcp`.
## Running the server
To start from source:
```bash
cargo run --release
```
Or with the installed binary:
```bash
rusty_apple_mail_mcp
```
For interactive experimentation, use the MCP Inspector:
```bash
npx -y @modelcontextprotocol/inspector ./target/release/rusty_apple_mail_mcp
```
## Configuration
The server is configured **only** through environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
| `APPLE_MAIL_DIR` | no | `~/Library/Mail` | Root folder of the Mail data |
| `APPLE_MAIL_VERSION` | no | `V10` | Envelope Index version subdirectory |
| `APPLE_MAIL_ACCOUNT` | no | unset | Comma-separated account selectors such as `Work Email` or `user@example.com`; when set, the whole server is restricted to the resolved account(s) |
| `RUST_LOG` | no | unset | Standard Rust tracing filter used by `tracing_subscriber`; controls server logs written to stderr |
Example setup:
```bash
export APPLE_MAIL_DIR="$HOME/Library/Mail"
export APPLE_MAIL_VERSION="V10"
export APPLE_MAIL_ACCOUNT="Work Email"
export RUST_LOG="warn"
```
### `RUST_LOG` values
The server reads `RUST_LOG` through `tracing_subscriber::EnvFilter`, so it accepts the usual Rust tracing filter syntax.
Common values:
- `error` — only errors
- `warn` — warnings and errors
- `info` — startup and high-level operational logs
- `debug` — includes per-request debug logs
- `trace` — very verbose tracing
- `off` — disables logging
You can also scope logs per module/crate:
- `rusty_apple_mail_mcp=debug`
- `rusty_apple_mail_mcp=trace,rusqlite=warn`
- `info,rmcp=warn`
When `RUST_LOG` enables `debug` for this crate, `search_messages` logs timing breakdowns to stderr, including:
- total matched rows
- SQL query time
- metadata hydration time from SQLite
- body preview fallback time
- total request time
### Account scoping
If `APPLE_MAIL_ACCOUNT` is set, the server resolves each selector through macOS `~/Library/Accounts/Accounts4.sqlite` and then restricts **all** tools to the matched Mail account IDs.
- Matching is case-insensitive and trims whitespace.
- Supported selectors include human-friendly account names and email addresses.
- Startup fails fast if a selector matches zero accounts or multiple accounts.
- `list_accounts` returns `account_name` and `email` when available, so valid selector values are discoverable from the MCP interface itself.
## VS Code integration
Example minimum `.vscode/mcp.json` configuration:
```json
{
"servers": {
"mail_mcp": {
"command": "rusty_apple_mail_mcp",
"args": [],
"env": {
"APPLE_MAIL_DIR": "/Users/your-user/Library/Mail",
"APPLE_MAIL_VERSION": "V10",
"APPLE_MAIL_ACCOUNT": "Work Email",
"RUST_LOG": "warn"
}
}
}
}
```
## Usage
Typical usage pattern:
1. Call `list_accounts` (optionally with `include_mailboxes=true`) to discover accounts and mailboxes.
2. Use `search_messages` to build a shortlist of candidates.
3. Call `get_message` to fetch the full message you care about.
4. Use `get_attachment_content` when you need the text of a particular attachment.
### Token efficiency
The server is optimized to minimize token consumption:
- **Compact tool descriptions** — routing hints live in `ServerInfo.instructions` (loaded once), not repeated per-tool on every request.
- **HTML → plain text** — HTML email bodies are converted to clean text via DOM parsing (using `scraper`), typically 10–20× smaller than raw HTML.
- **`status: "success"` omitted** — the status field only appears on error/not_found/partial responses.
- **Recipients omitted by default** — `get_message` skips To/CC lists unless `include_recipients=true`.
- **Compact dates** — ISO 8601 without seconds (`2024-09-15T00:00Z`).
- **`has_body` removed** — always true for indexed messages; no longer wasting tokens.
### Sample search request
```json
{
"subject_query": "invoice",
"account": "imap://ACCOUNT-ID",
"limit": 10
}
```
### Sample message retrieval
```json
{
"message_id": "12345",
"include_body": true,
"include_attachments_summary": true,
"body_format": "text",
"include_recipients": false
}
```
`include_recipients` defaults to `false` — set it to `true` when you need the To/CC lists (saves tokens on corporate mail with 50+ recipients).
### Combined account + mailbox discovery
Instead of calling `list_accounts` then `list_mailboxes` separately, use `include_mailboxes=true`:
```json
{
"include_mailboxes": true
}
```
This returns accounts with their mailboxes grouped, saving one round-trip.
## How it works
The server draws from two local sources:
- **Envelope Index** – the SQLite database Apple Mail uses as a metadata index and relationship store
- **.emlx files** – the canonical bodies and attachments for individual messages
Search queries hit the lightweight index, keeping them fast; bodies and attachments are loaded on-demand from the `.emlx` files.
## Development
Handy commands while working on the codebase:
```bash
cargo test
cargo clippy --all-targets --all-features -- -D warnings
cargo doc --no-deps
```
## Limitations
- macOS only
- read-only access only
- stdio transport only
- requires Apple Mail storage to be present on disk
- some binary attachment formats may yield metadata instead of extracted text
## TL;DR
Need an AI agent to safely search and read Apple Mail on your Mac? This project provides a clean, read-only MCP layer over Apple Mail’s native storage — fast index-based searches, on‑demand body hydration from `.emlx`, and zero write access.