An open API service indexing awesome lists of open source software.

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

Awesome Lists containing this project

README

          

# Rusty Apple Mail MCP Server

![Rust 2024](https://img.shields.io/badge/rust-2024-orange?style=flat-square&logo=rust)
![Protocol MCP](https://img.shields.io/badge/protocol-MCP-6f42c1?style=flat-square)
![Transport stdio](https://img.shields.io/badge/transport-stdio-0a7ea4?style=flat-square)
![Platform macOS](https://img.shields.io/badge/platform-macOS-111827?style=flat-square&logo=apple)
![Access read-only](https://img.shields.io/badge/access-read--only-15803d?style=flat-square)

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.