Skip to main content
Glama
README.md
# apple-suite-mcp

One small Python file that gives Claude (or any MCP client) access to the
built-in Apple apps on your Mac: **Mail, Contacts, Calendar, Notes, and
Reminders.**

Because it talks to the Mail *app* rather than any one email service, it sees
every account you've added to Mail — iCloud plus any number of Gmail, Google
Workspace, and Exchange accounts side by side — with no OAuth setup and no
extra logins.

## Why this one

There are several Apple MCPs out there. This one optimizes for four things:

- **Multi-account by nature.** Google-API MCPs authenticate one account per
  OAuth grant — five Google accounts means five connector setups and five
  token refreshes. This server gets every account at once (five Gmails, an
  iCloud, an Exchange — whatever Mail and Calendar are signed into),
  because your Mac already did the logging in.

- **Minimal.** One readable `server.py`, three dependencies, no Node, no app
  to install. If you want to know what it does, you can just read it.
- **Fast where it matters.** Calendar and Reminders use EventKit (Apple's
  native database API) instead of scripting the Calendar app — hundreds of
  times faster on real calendars. Mail listing and search read Mail's local
  SQLite index directly when Full Disk Access is granted (milliseconds even
  on giant mailboxes), and fall back to AppleScript automatically when it
  isn't.
- **Self-diagnosing.** macOS permissions are the hard part of every Apple
  MCP. `python server.py check` (or the `check_access` tool) tells you
  exactly what's granted, what's missing, and which System Settings pane
  fixes it.

## Setup

### Easy mode — let your AI install it

If you use Claude Code (or any coding agent), paste this and let it drive:

> Read https://github.com/travisthetrashpanda/apple-suite-mcp and install it
> for me: clone it, register it with my MCP client, then run its `check`
> command and walk me through fixing any macOS permissions it reports
> missing.

The agent handles cloning and registration, and `check` tells it exactly
which System Settings pane to point you at; you just click Allow when macOS
asks. (Sensible to read what you're installing first — it's one Python file.)

### Manual mode

Requires macOS and [uv](https://docs.astral.sh/uv/) (`brew install uv`).

```sh
git clone https://github.com/travisthetrashpanda/apple-suite-mcp.git ~/apple-suite-mcp
```

**Claude Code:**

```sh
claude mcp add --scope user apple -- uv run --directory ~/apple-suite-mcp python server.py
```

**Claude Desktop / any MCP client** — add to your MCP config (e.g.
`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "apple": {
      "command": "uv",
      "args": ["run", "--directory", "/Users/YOU/apple-suite-mcp", "python", "server.py"]
    }
  }
}
```

Use the full path to `uv` (usually `/opt/homebrew/bin/uv`) if your client
doesn't inherit your shell's PATH.

### Permissions (one-time)

Run the diagnosis and follow what it tells you:

```sh
cd ~/apple-suite-mcp && uv run python server.py check
```

- **Automation** (Mail, Contacts, Notes): macOS prompts on first use — click
  Allow.
- **Calendars & Reminders**: set the host app (e.g. Claude) to **Full
  Access** in System Settings → Privacy & Security.
- **Full Disk Access** (optional): enables the fast mail path. Without it,
  everything still works — large mailboxes are just slow (~30s per query).
  This is a broad grant; read the code and decide for yourself. **Note that
  this one takes two grants — see below.**

> **Gotcha: Full Disk Access needs two entries, not one.** In System
> Settings → Privacy & Security → Full Disk Access, enable both your host
> app (e.g. "Claude") **and "uv"**. macOS grants this permission per
> executable, and the server runs as a `uv`-launched subprocess with its own
> permission identity — so granting the app alone isn't enough.
>
> Symptom of the missing grant: `mail_search` and `mail_messages` time out
> while `check` keeps reporting `full_disk_access: "no access"`, no matter
> how many times you toggle the app or restart the machine. Switching on
> "uv" flips it to `"ok — fast mail path active"` immediately, with no
> relaunch needed.

## Try it

> what's unread across my inboxes?
>
> search all my accounts for emails from the DMV
>
> what's on my calendar this week?
>
> remind me Thursday at 9am to renew the registration
>
> find my note about the wifi setup

## Scoping access (optional)

macOS permissions are per-*app*, not per-account — once the host app can
control Mail, it can see every account on the Mac. If you want tighter
control (say, a shared work/personal machine), copy `config.example.json`
to `config.json` and list what the server is allowed to see:

```json
{
  "mail_accounts": ["Personal"],
  "calendars": ["Home", "Family"],
  "reminder_lists": ["Reminders"],
  "note_folders": ["Notes"],
  "disabled_tools": ["mail_send"]
}
```

Anything not listed is invisible to every tool — it can't be listed, read,
searched, or modified. Omit a key (or the whole file) to allow everything
of that kind. `disabled_tools` removes tools entirely (they're never even
registered with the MCP client). `check_access` reports the active scoping.

## Tools

| App | Tools |
|---|---|
| Mail | `mail_accounts`, `mail_unread_counts`, `mail_messages`, `mail_search`, `mail_read_message`, `mail_send`, `mail_mark_read`, `mail_move`, `mail_trash` |
| Contacts | `contacts_search` |
| Calendar | `calendar_list`, `calendar_events`, `calendar_create_event` |
| Notes | `notes_folders`, `notes_search`, `notes_read`, `notes_create` |
| Reminders | `reminders_list`, `reminders_create`, `reminders_complete` |
| — | `check_access` |

Test any tool from the command line without an MCP client:

```sh
uv run python server.py test mail_unread_counts
uv run python server.py test mail_messages '{"account": "Work", "limit": 5}'
```

## Safety notes

- `mail_trash` uses Mail's normal reversible delete (messages go to the
  account's Trash). There is deliberately **no permanent-delete tool**.
- `mail_send` sends real email through your accounts; MCP clients should
  confirm with the user before calling it.
- Everything runs locally — nothing is sent anywhere except by `mail_send`.

## Limitations

- macOS only; the target apps must be configured (Mail needs at least one
  account).
- The first Mail query right after Mail launches can time out while it
  syncs — retry after a minute.
- Without Full Disk Access, very large mailboxes take ~30s per query and
  cross-account search (`mail_search` with no account) is unavailable.
- Nested mail folders are addressed by their full path (e.g.
  `"[Gmail]/All Mail"`).

## Credits

- [sweetrb/apple-mail-mcp](https://github.com/sweetrb/apple-mail-mcp) — the
  project that proved the scripted-Mail approach and inspired this one.
- [krmj22/macos-mcp](https://github.com/krmj22/macos-mcp) — the idea of
  reading Mail's Envelope Index directly instead of fighting slow
  AppleScript reads.

## Say thanks

This project is free to use, no strings attached. If it's useful to you, a ⭐
on this repo or a shout-out to
[@travisthetrashpanda](https://github.com/travisthetrashpanda) is always
appreciated — and if you build something on top of it, a link back here
helps others find it.

## License

MIT