Put your agent to work
in your everyday Apple apps.

Cupertino puts the Apple apps on your Mac behind MCP, for any agent that speaks it. One Full Disk Access grant, held by a signed menu-bar app you can watch — instead of one for every editor that happens to spawn a server.

macOS 26 or later · 30-minute trial, no account · 30-day refund

MIT servers · unofficial, not affiliated with Apple

What did I promise Marie last week, and is any of it on my calendar?

What your agent called

  • Contactsapple_contacts_search_contactsread
  • Mailapple_mail_search_messagesread
  • Mailapple_mail_get_threadread
  • Calendarapple_calendar_list_eventsread

reads only · one grant · nothing left the Mac

In use

What you actually
ask for.

Every one of these carries a constraint — an account, a date bound, a filter. That is the part a shell script gets slowly or gets wrong, and the reason a server earns its place: it holds what the model would otherwise have to re-derive every session.

Look at how I write in my work inbox, then draft this reply in the same voice.

Mail

Scoped to one account. APPLE_MAIL_ACCOUNTS bounds what can be read, not just what can be written.

Pull together everything about the Atlas launch from my mail, my notes and my calendar. What do I still owe people?

MailNotesCalendar

Three surfaces, one grant — the payoff of shipping them in one bundle.

Find every unread message from my accountant this quarter.

Mail

A filter. This query shape costs 74 seconds over Apple Events; the index lane answers it in milliseconds.

What is actually on my calendar next week once the repeating meetings are expanded? Block two hours before the release.

Calendarneeds the write gate

Repeats expanded, and the window the answer covers reported with it — a short list is otherwise indistinguishable from a free afternoon.

Turn the action items from yesterday's client thread into reminders, due Friday.

MailRemindersneeds the write gate

Reads one surface, writes another. Both write gates off by default.

Did anyone ever reply to the invoice I sent on the 3rd?

Mail

The whole pitch, for someone who has never edited a config file.

Writes are off until you turn them on, per surface — and the toggle decides whether the mutating tools are registered at all, so an agent with writes off is never told they exist.

Claude
CupertinoThu 09:41
Cupertino5 servers running
  • Mailautomation allowed
  • Notesautomation allowed
  • Remindersautomation allowed
  • Calendarautomation allowed
  • Contactsautomation allowed
  • Full Disk Accessgranted
  • Writesoff
  • Claude Desktopconfigured
  • Cursorconfigured
  • Claude Codecopy command
  • Open Cupertino
  • Settings…
  • Quit
claude

“What did Anna send me about the lease, and is it in my notes?”

apple_mail_search_messagesread · index · 97 ms
apple_notes_search_notesread · events · 97 ms

Two different lanes, and it does not matter which. Mail came off the Envelope Index, because asking Mail.app the same thing takes 74 seconds. Notes came off Apple Events, because below roughly 5k notes the grant buys nothing there — so it is not asked for.

The grant

One key to the
whole house.

Full Disk Access is indivisible, and it lands on whatever process launched the server — your editor, your terminal, never Mail itself. A grant for mail is already a grant for Messages, Safari history and SSH keys. Granting it to Mail.app does nothing: the reader needs the permission, not Mail.

Every host asks for its own4 grants
  • Cursorwhole disk
  • Claude Desktopwhole disk
  • Visual Studio Codewhole disk
  • Terminalwhole disk
One signed app holds it1 grant
  • Cursor
  • Claude Desktop
  • Visual Studio Code
  • Terminal
Cupertino.app
whole disk
granted once

Automation is prompted separately, one row per target app. The bundle identifier io.mgcrea.cupertino is the TCC identity, so the grant survives every update.

Tool registration

The list gets shorter,
not greyer.

The tool list is a pure function of allowWrites and nothing else, because MCP clients cache it. With writes off the mutating tools are never registered — the host cannot call what it was never told about, so there is nothing to refuse.

APPLE_MAIL_ALLOW_WRITES=
always registered · 10
  • apple_mail_search_messages
  • apple_mail_list_messages
  • apple_mail_count_messages
  • apple_mail_get_thread
  • apple_mail_get_message
  • apple_mail_get_message_source
  • apple_mail_list_attachments
  • apple_mail_list_accounts
  • apple_mail_list_mailboxes
  • apple_mail_diagnostics
write-gated · 8
  • apple_mail_send_message
  • apple_mail_reply_to_message
  • apple_mail_forward_message
  • apple_mail_set_message_flags
  • apple_mail_move_messages
  • apple_mail_delete_messages
  • apple_mail_check_for_new_mail
  • apple_mail_save_attachment
  • not registered · the host never sees these names

Mutation is one control. On Mail the larger blast radius is reading an entire archive — that is what *_ACCOUNTS is for, and it is enforced in exactly one place so no query path escapes it.

Activity

You can watch it
the whole time.

Every tool call, live, grouped by the client that made it. It is the answer to “what did the assistant just do with my mail?” — and the reason the servers run under an app you can see rather than inside whichever editor happened to spawn them.

Activity
  • 09:41:02Claude Desktopapple_mail_search_messagesread
  • 09:41:02Claude Desktopapple_mail_get_threadread
  • 09:41:03Claude Desktopapple_notes_search_notesread
  • 09:40:55Cursorapple_reminders_list_remindersread
  • 09:40:12Cursorapple_mail_list_accountsread
tool names only · no arguments, no contents, no results

The menu bar shows the same thing one level up: which client is talking to which server right now, and how many tools it has called. None of it is sent anywhere. The one connection Cupertino can make is the update check, it is off until you turn it on, and it carries no identifier — which CI checks against the built binary rather than the source.

The app

A window, not
a background process.

Cupertino runs as a menu-bar app you can open. That is the point of holding the servers in one signed process rather than spawning them inside whichever editor asked first: there is something to look at, and it tells you what happened.

Cupertino's Mail pane: automation allowed, the Envelope Index readable, writes enabled, and five connected clients.

One pane per surface

Whether the app can be driven, whether its store can be read, and who is talking to it — one surface at a time.

Cupertino's log showing one turn: a Contacts search, two Mail calls and a Calendar range query, all reads.

One question, end to end

The same pane as below, seeded with a single turn: “What did I promise Marie last week, and is any of it on my calendar?” Contacts leads, because the question names a person and every other surface is addressed by handle.

Cupertino's activity log: timestamped calls across mail, notes, reminders and calendar, with a refused write to Reminders in red.

The log, live

The same pane again, this time across everything a working day sends at it. Tool names only — never arguments, message contents or results — and a refused write shows up as a refusal.

Cupertino's connections pane: eighteen live sessions from claude-ai, claude-code and cursor-vscode across mail, notes, reminders and calendar.

Every session, ungrouped

One row per connection, because each client opens one per server it is wired to — and a client you have run several times over opens several. Three clients is eighteen rows here, and this is the pane that shows them.

Cupertino's Permissions settings: Full Disk Access granted, automation allowed for Mail, Notes, Reminders, Calendar and Contacts, and write toggles on for Mail only.

The gate, per surface

Automation is asked for one app at a time, and writes are a separate switch again. With one off, that surface's mutating tools are never registered — so an agent is not refused, it is never told they exist.

Latency

Read the index.
Then say how fresh it was.

Same query, same mailbox. Apple Events makes Mail.app do the work one message at a time; the index lane reads the Envelope Index directly. Reading the index is the easy half — Mail owns that file and is still writing to it, so every result carries how old the index was and whether the read could see the write-ahead log at all.

Apple Events search74,000 ms
Indexed search97 ms

drawn to scale — 0.13% of the bar above

A search result carries indexAgeSeconds, and a warning when the index could only be opened immutable — which skips the write-ahead log, so the newest mail is exactly the mail most likely to be missing. A fast wrong answer is the failure mode every indexed reader shares; saying so is the part that is optional.

Without the grant, Notes still works fully below roughly 5k notes; Mail search falls back to the 74-second path. Tools that need the index never disappear — the tool list is a pure function of allowWrites and nothing else, so they return a structured degraded result naming what is absent.

Surfaces

Five surfaces.
One bundle.

Each surface is its own npm package, so a host loads only the tools it wants — and write tools against Mail and against Reminders are not the same risk. They share one bundle and one grant, which is the whole reason they live together.

Mail

18 tools

The deep one. Search, read, threads, attachments and message source across accounts and mailboxes; eight mutating tools behind the write gate.

10 always registered·8 write-gated
@mgcrea/mcp-apple-mail

Notes

12 tools

Search, read and attachments across every folder and account, with five mutating tools behind the write gate.

7 always registered·5 write-gated
@mgcrea/mcp-apple-notes

Reminders

11 tools

Lists, due dates and search across every account, with five mutating tools behind the write gate.

6 always registered·5 write-gated
@mgcrea/mcp-apple-reminders

Calendar

9 tools

Ranges, search and repeating events expanded properly, with three mutating tools behind the write gate.

6 always registered·3 write-gated
@mgcrea/mcp-apple-calendar

Contacts

7 tools

Turns a phone number into a name, and creates or edits a card. Reads need no Automation prompt at all; only the two write tools do.

5 always registered·2 write-gated
@mgcrea/mcp-apple-contacts

Mail without the grant — Accounts, mailboxes and writes only — search falls back to the 74-second path.

Notes without the grant — Fully usable below roughly 5k notes with no grant at all — only attachment bytes need it.

Reminders without the grant — Workable over Apple Events — the file lane is what makes search scale.

Calendar without the grant — Nothing — the only surface with no Apple Events read path fast enough to be a fallback.

Contacts without the grant — Nothing — but it asks for the Contacts permission rather than the whole disk, and unlike Full Disk Access that one prompts.

Messages is not started — no read API exists without the file lane, so it is the one surface that cannot ship without Full Disk Access at all.

Status
Servers
Open source, MIT. All five run from source today.
App
Source-available, Developer ID signed, notarized and stapled, hardened runtime throughout.
Network
Makes one network connection, and only if you ask for it: the update check. No analytics, no licence server, no phone-home. Verified in CI against the built binary, not the source.
Platform
macOS only. It drives the apps on your Mac; there is nothing to port.
Distribution
Not on the App Store — the sandbox denies ~/Library/Mail whatever you grant. A stapled zip and a Homebrew cask instead.
Release
The signed app ships from GitHub releases. The MCP servers are MIT but not on npm yet — the app carries them.
Price

Pay once.
Then it is yours.

One Full Disk Access grant, held by a notarized binary from an identifiable developer, instead of four grants handed out to whichever editors happened to spawn a server. The servers themselves stay MIT and free forever.

$14.99
One time, for all of 1.x. Not a subscription.
€14.99 in the EU, VAT included.
Buy a licenceor try it free for 30 minutes
30-day refund · no account
  • A 30-minute trial, every surface at full function. Press the button; nothing arms itself.
  • Every 1.x release, free. 2.0 is a new purchase; nothing lapses in between.
  • Every Mac you own or control. No activation limit and nothing counts your installs.
  • 30 days to change your mind, for any reason or none.
  • No account, no login, no phone-home. The key verifies on your Mac and nowhere else.
The ladder, published in advance
$14.99
At launch
Mail, Notes, Reminders, Calendar, Contacts
$24.99
When Messages ships
+ Messages
$34.99
When Safari ships
+ Safari

The price rises when a surface lands, never because time passed — and once risen it does not come back down. Buying early is the whole of the discount.

Run the servers on their own and pay nothing. Theservers are MIT and always were — they need no key, and they do the work. What a licence buys is the app: the signed and notarized binary that holds one Full Disk Access grant on their behalf, and the work of keeping it working. Its source is public for a reason that has nothing to do with price: nobody should grant Full Disk Access to software they cannot read. Read it, build it, run your own — thelicence is explicit that any build asks for a key, rather than leaving you to find out at the first run.

The trial is held in memory and never written to disk, so quitting Cupertino and opening it again starts another one. Nothing stops you and nothing pretends to. When the window closes it closes properly: the servers it started are stopped, and your assistant reports a dropped connection. A deadline named on the button that started it is not a window if it cannot shut.

One app. One grant.

Signed with a Developer ID and notarized by Apple. One payment covers every 1.x release, on every Mac you own — or run every surface for 30 minutes first and decide afterwards.

brew install --cask mgcrea/tap/cupertino

macOS 26 or later · 30-day refund · SHA-256 · release notes