Skip to main content

Fast MCP server for Apple Mail via optimized JXA scripts

This project has been archived.

The maintainers of this project have marked this project as archived. No new releases are expected.

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jxa_mail_mcp-0.1.0.tar.gz (23.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jxa_mail_mcp-0.1.0-py3-none-any.whl (25.9 kB view details)

Uploaded Python 3

File details

Details for the file jxa_mail_mcp-0.1.0.tar.gz.

File metadata

  • Download URL: jxa_mail_mcp-0.1.0.tar.gz
  • Upload date:
  • Size: 23.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for jxa_mail_mcp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 aef82f08391750dd482e7d28e745931ad752cc7e51be2b15268d7722ada798a7
MD5 0bc1b338ae51c6cd55c460fd45c66033
BLAKE2b-256 f7ba78dc265327a5c24858fd3300ea992ac4c5f05fada1d313645ccf2e666daa

See more details on using hashes here.

File details

Details for the file jxa_mail_mcp-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: jxa_mail_mcp-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for jxa_mail_mcp-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d5af79b37d379c366e22717e5e252f8eb882ded3a9f3537cbf4b3f158f3a3891
MD5 183d03ed03d3fcff14c66b129b179e1a
BLAKE2b-256 688b410d8fb8e2f7f78b1b4a884e0968e5f1bbde9c9403fc1563029c75e0a65d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page