JXA Mail MCP MCP Server

$pipx install jxa-mail-mcp
README.md

A fast MCP server for Apple Mail, using optimized JXA scripts with batch property fetching for 87x faster performance.

JXA Mail MCP

A fast MCP (Model Context Protocol) server for Apple Mail, using optimized JXA (JavaScript for Automation) scripts with batch property fetching for 87x faster performance.

Features

  • list_accounts - List all configured email accounts
  • list_mailboxes - List mailboxes for an account
  • get_emails - Fetch emails from any mailbox with pagination
  • get_todays_emails - Fetch all emails received today
  • get_unread_emails - Fetch unread emails
  • get_flagged_emails - Fetch flagged emails
  • search_emails - Search emails by subject or sender
  • fuzzy_search_emails - Typo-tolerant search using trigram + Levenshtein matching

Installation

With pipx (recommended)

pipx install jxa-mail-mcp

From source

Requires Python 3.13+ and uv:

git clone https://github.com/imdinu/jxa-mail-mcp
cd jxa-mail-mcp
uv sync

Usage

Add to Claude Code

After installing with pipx:

{
  "mcpServers": {
    "mail": {
      "command": "jxa-mail-mcp"
    }
  }
}

Or from source:

{
  "mcpServers": {
    "mail": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/jxa-mail-mcp", "jxa-mail-mcp"]
    }
  }
}

Run directly

jxa-mail-mcp

Configuration

Set default account and mailbox via environment variables:

export JXA_MAIL_DEFAULT_ACCOUNT="Work"
export JXA_MAIL_DEFAULT_MAILBOX="Inbox"

Or in Claude Code config:

{
  "mcpServers": {
    "mail": {
      "command": "jxa-mail-mcp",
      "env": {
        "JXA_MAIL_DEFAULT_ACCOUNT": "Work"
      }
    }
  }
}

Test in Python

from jxa_mail_mcp.server import get_todays_emails, search_emails, fuzzy_search_emails

emails = get_todays_emails(account="iCloud", mailbox="Inbox")
results = search_emails("meeting", account="Work", limit=10)

# Fuzzy search - tolerates typos
results = fuzzy_search_emails("meetting nottes", limit=10)  # finds "meeting notes"

Architecture

src/jxa_mail_mcp/
├── __init__.py         # Exports mcp instance and main()
├── server.py           # FastMCP server and MCP tools
├── config.py           # Environment variable configuration
├── builders.py         # QueryBuilder for constructing JXA scripts
├── executor.py         # JXA script execution utilities
└── jxa/
    ├── __init__.py     # Exports MAIL_CORE_JS
    └── mail_core.js    # Shared JXA utilities library

Design Principles

  1. Separation of concerns: Python handles logic/types, JavaScript handles Mail.app interaction
  2. Builder pattern: QueryBuilder constructs optimized JXA scripts programmatically
  3. Shared JS library: mail_core.js provides reusable utilities injected into all scripts
  4. Type safety: Python type hints ensure correct usage

Performance

The Problem

Naive AppleScript/JXA iteration is extremely slow:

// SLOW: ~54 seconds for a few hundred messages
for (let msg of inbox.messages()) {
    results.push({
        from: msg.sender(),      // IPC call to Mail.app
        subject: msg.subject(),  // IPC call to Mail.app
    });
}

Each property access triggers a separate Apple Event IPC round-trip.

The Solution: Batch Property Fetching

JXA supports fetching a property from all elements at once:

// FAST: ~0.6 seconds (87x faster)
const msgs = inbox.messages;
const senders = msgs.sender();   // Single IPC call returns array
const subjects = msgs.subject(); // Single IPC call returns array

for (let i = 0; i < senders.length; i++) {
    results.push({ from: senders[i], subject: subjects[i] });
}

Benchmark Results

Method Time Speedup
AppleScript (per-message) 54.1s 1x
JXA (per-message) 53.9s 1x
JXA (batch fetching) 0.62s 87x

Fuzzy Search Performance

Fuzzy search uses trigrams for fast candidate selection and Levenshtein distance for accurate ranking. Tested on a mailbox with ~6,000 emails:

Search Type Time Overhead
Regular search ~360ms -
Fuzzy search ~480ms +33%

The trigram pre-filtering keeps fuzzy search fast by avoiding expensive Levenshtein calculations on non-matching words.

Example: Searching for "reserch studies" (typo) correctly finds "research studies" with 0.94 similarity score.

Development

uv sync
uv run ruff check src/
uv run ruff format src/

# Test
uv run python -c "
from jxa_mail_mcp.server import list_accounts, get_todays_emails
print('Accounts:', len(list_accounts()))
print('Today:', len(get_todays_emails()))
"

License

GPL-3.0-or-later

Tools (9)

list_accountsList all configured email accounts
list_mailboxesList mailboxes for an account
get_emailsFetch emails from any mailbox with pagination
get_todays_emailsFetch all emails received today
get_unread_emailsFetch unread emails
get_flagged_emailsFetch flagged emails
search_emailsSearch emails by subject or sender
fuzzy_search_emailsTypo-tolerant search using trigram + Levenshtein matching
get_todays_emailsFetch all emails received today

Environment Variables

JXA_MAIL_DEFAULT_ACCOUNTDefault email account to use
JXA_MAIL_DEFAULT_MAILBOXDefault mailbox to use

Configuration

claude_desktop_config.json
{
  "mcpServers": {
    "mail": {
      "command": "jxa-mail-mcp"
    }
  }
}

Try it

List all my email accounts using list_accounts.
Fetch today's emails from my iCloud Inbox with get_todays_emails.
Search for emails containing 'meeting' in Work account using search_emails.
Perform a fuzzy search for 'meetting nottes' with fuzzy_search_emails.
List mailboxes for my Work account using list_mailboxes.

Frequently Asked Questions

How do I install JXA Mail MCP?

Install JXA Mail MCP by running: pipx install jxa-mail-mcp

What MCP clients work with JXA Mail MCP?

JXA Mail MCP works with any MCP-compatible client including Claude Desktop, Claude Code, Cursor, and other editors with MCP support.

Use JXA Mail MCP with Conare

Manage MCP servers visually, upload persistent context, and never start from zero with Claude Code & Codex.

Try Free