Skip to main content
ClaudeWave

MCP servers for the Apple apps on your Mac — one Full Disk Access grant, held by a signed app instead of your editor

MCP ServersRegistry oficial1 estrellas0 forksTypeScriptMITActualizado today
ClaudeWave Trust Score
95/100
Verified
Passed
  • Open-source license (MIT)
  • Actively maintained (<30d)
  • Clear description
  • Topics declared
  • Documented (README)
Last scanned: 9/8/2026
Install in Claude Code / Claude Desktop
Method: Manual
Claude Code CLI
git clone https://github.com/mgcrea/cupertino
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "cupertino": {
      "command": "node",
      "args": ["/path/to/cupertino/dist/index.js"]
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Clone https://github.com/mgcrea/cupertino and follow its README for install instructions.
Casos de uso

Resumen de MCP Servers

<p align="center">
  <img src="design/cupertino-lockup.svg" alt="Cupertino" width="560">
</p>

# Cupertino

**Put your agent to work in your everyday Apple apps.**

MCP servers for the Apple apps already on your Mac, and the signed app that grants them their
permissions once instead of once each — for any agent that speaks MCP, not for one host.

> **Unofficial.** Not affiliated with Apple. These drive the apps that are already on your Mac.

## In use

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

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

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

Every one of those carries a constraint — an account, a date bound, a filter. That is the part the
naive `osascript` path answers in 74 seconds or answers wrongly, and the reason a server earns its
place: it holds what the model would otherwise re-derive every session. The measurements are in
[docs/verify.md](docs/verify.md); what the alternatives cost is in
[docs/alternatives.md](docs/alternatives.md).

The last one needs the write gate open on Reminders. Writes are off per surface until you turn them
on, and the toggle decides whether the mutating tools are registered at all — an agent with writes
off cannot see that they exist.

## Surfaces

| Surface   | Package                                    | Status                                                                                         |
| --------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| Mail      | [`packages/mail`](packages/mail)           | implemented — 21 tools, search/read/attachments + gated writes                                 |
| Notes     | [`packages/notes`](packages/notes)         | implemented — 13 tools, search/read/attachments + gated writes                                 |
| Reminders | [`packages/reminders`](packages/reminders) | implemented — 11 tools, lists/search/dates + gated writes                                      |
| Calendar  | [`packages/calendar`](packages/calendar)   | implemented — 10 tools, ranges/search/free-time + gated writes                                 |
| Contacts  | [`packages/contacts`](packages/contacts)   | implemented — 7 tools, resolves handles to names + gated writes                                |
| Messages  | [`packages/messages`](packages/messages)   | implemented — 9 tools, chats/search/counts/decoded text + gated send and codes                 |
| Safari    | [`packages/safari`](packages/safari)       | implemented — 14 tools, history/tabs/reading list/page reads + gated writes and codes          |
| Maps      | [`packages/maps`](packages/maps)           | implemented — 13 tools, favourites/Guides/recents + gated writes                               |
| Screen    | —                                          | implemented — 3 tools, ScreenCaptureKit; served in-app, no npm package; off until switched on  |
| Sound     | —                                          | implemented — 10 tools, volume/routing/speech + gated recording; in-app; off until switched on |
| Desktop   | —                                          | implemented — 16 tools, AXUIElement natively; in-app, no npm package; off until switched on    |
| Simulator | —                                          | implemented — 10 tools, an iOS Simulator's screen in iOS points; in-app; off until switched on |
| —         | [`packages/core`](packages/core)           | shared: the osascript boundary, TCC-aware errors, ro SQLite                                    |

**Screen, Sound, Desktop and Simulator arrive switched off.** Every other surface that brokers an
Apple app is on when Cupertino is installed; those four are not, because Screen Recording, the
microphone and Accessibility are per-process grants that reach past the surface being brokered.
Desktop reaches furthest — Accessibility does not scope to a target at all, so the right to press a
button in Maps is the right to press one in anything, and it additionally arrives with writes off, so
it can only look until you say otherwise. Simulator holds the same grant and pins its own reach to
Simulator.app, with no switch that widens it. Switch them on in the surface list if you want them.

Each surface is its own server, so a host loads only the tools it wants. Every surface that brokers
an Apple app through its store or its scripting dictionary is also its own npm package; `screen`,
`sound`, `desktop` and `simulator` are not, and could not be — the first three broker a framework
rather than an app, `simulator` brokers an app through Accessibility, and in every case the grant
lives in the app, so the app serves them in-process and a published package could do nothing. See
[docs/screen.md](docs/screen.md), [docs/desktop.md](docs/desktop.md) and
[docs/simulator.md](docs/simulator.md).

`simulator` is the lane for an app you are building. Simulator.app bridges the simulated device's
accessibility tree into the Mac's, so an iOS app's own controls are readable and pressable here with
no WebDriverAgent and no runner process — and the surface answers in **iOS points**, the space
`ios_simulator_tap` and `ios_simulator_screenshot` use, with the window scale measured on every
call rather than assumed. It reads, finds and presses; behind writes it taps, swipes, types and
presses the device's buttons. Booting, installing, launching, screenshots and push need no grant
and stay with [`@mgcrea/mcp-ios-simulator`](https://github.com/mgcrea/mcp-ios-simulator), which
this complements rather than copies.

`desktop` is the one surface that drives an interface rather than reading a store, and it does it
through `AXUIElement` **natively** rather than through `osascript`. That distinction is the whole
surface: every Accessibility measurement this project took before 2026-09-05 went through System
Events, one Apple Event per attribute, which is where "33.6 ms a round trip" and "~14 s for a place
card" came from. Natively the same walks cost 1.24 ms a round trip and the same place card 0.177 s.
The transport was the cost, not the API — see [docs/desktop.md](docs/desktop.md).

They share one bundle and one Full Disk Access grant, which is the whole reason they live together
— see [docs/distribution.md](docs/distribution.md).

## Quick start

Every server that brokers an Apple app is on npm and runs straight from `npx` — for Claude Code, a
`.mcp.json` beside your project:

```json
{
  "mcpServers": {
    "apple-mail": {
      "command": "npx",
      "args": ["-y", "@mgcrea/mcp-apple-mail"]
    },
    "apple-notes": {
      "command": "npx",
      "args": ["-y", "@mgcrea/mcp-apple-notes"]
    }
  }
}
```

The packages are MIT and need no licence key. What they do need is a permission, and on npm you
grant it to whatever launches them — your editor, your terminal — which is the trade the signed
[`Cupertino.app`](https://cupertino.mgcrea.io) exists to avoid: one Full Disk Access grant held by a
notarized binary, instead of one per host. See [docs/licensing.md](docs/licensing.md).

```bash
brew install --cask mgcrea/tap/cupertino
```

Or run them from source:

```bash
git clone https://github.com/mgcrea/cupertino.git
cd cupertino
pnpm install
pnpm build
```

then point your host at `packages/<surface>/dist/cli.js` by absolute path.

Writes are off unless you ask for them — see [Configuration](#configuration).

Running through the menu bar app instead routes every server through the bridge, so Full Disk
Access is granted to Cupertino rather than to whichever editor spawned the server:

```bash
make run      # build Cupertino.app, point it at packages/*/dist, launch it
make smoke    # handshake every server through the bridge
```

`make surfaces` writes a gitignored `.mcp.json` at the repo root, wired for that path — it is a
developer's local working config rather than something to commit, because every entry is an
absolute path into one Mac's bundle. `make` on its own lists every target.

Note the different server names. Wired by hand as above, a server is `apple-mail` and runs under
whatever grant its host process has. Wired by Cupertino it is `cupertino-mail`, because that entry
points at the app's bridge and runs under the app's grant. Two names for two deployments, and you
can have both. The app only ever touches its own `cupertino-*` keys — an `apple-mail` entry
belonging to some other server is left alone.

Cupertino is machine configuration, not a project dependency, so it belongs in a per-user config:
one file each, and the equivalent of `--scope user` everywhere. Deliberately **not** `--scope
project`, which writes an `.mcp.json` meant to be committed — that entry is an absolute path into a
bundle on one Mac, backed by one person's Full Disk Access grant, and it would be useless to a
teammate and unwise to offer them.

All seven are written by the app, and nothing has to be pasted into a terminal. Six keep strict JSON
and are merged into as dictionaries — five under `mcpServers`, Visual Studio Code under `servers` in
`User/mcp.json`, which is a different file from the JSONC `settings.json` it was confused with for
two releases. The seventh, `~/.codex/config.toml`, is TOML full of hand-written prose and structure,
so it is never re-serialised: `ClientWiringTOML` replaces the lines that hold MCP servers and quotes
every other byte verbatim. ChatGPT has no row of its own because it is not a separate client — the
ChatGPT app, the Codex CLI and the Codex IDE extension all read that same file, which is the row
called "ChatGPT & Codex".

Claude Code's `~/.claude.json` is written directly, and it is the one config where that deserves a
paragraph: it holds this machine's credentials beside ninety-odd project blocks, and Claude Code
writes to it while it runs. So every write copies the
ai-agentsappleapple-calendarapple-mailapple-notesapple-remindersapplescriptclaudeimessagejxamacosmcpmcp-servermodel-context-protocolsafari

Lo que la gente pregunta sobre cupertino

¿Qué es mgcrea/cupertino?

+

mgcrea/cupertino es mcp servers para el ecosistema de Claude AI. MCP servers for the Apple apps on your Mac — one Full Disk Access grant, held by a signed app instead of your editor Tiene 1 estrellas en GitHub y su última actualización registrada es del 2026-09-07.

¿Cómo se instala cupertino?

+

Puedes instalar cupertino clonando el repositorio (https://github.com/mgcrea/cupertino) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.

¿Es seguro usar mgcrea/cupertino?

+

Nuestro agente de seguridad ha analizado mgcrea/cupertino y le ha asignado un Trust Score de 95/100 (tier: Verified). Revisa el desglose completo de comprobaciones superadas y flags en esta página.

¿Quién mantiene mgcrea/cupertino?

+

mgcrea/cupertino es mantenido por mgcrea. La última actividad registrada en GitHub es del 2026-09-07, con 0 issues abiertos.

¿Hay alternativas a cupertino?

+

Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.

Despliega cupertino en tu cloud

Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.

¿Mantienes este repo? Añade un badge a tu README

Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.

Featured on ClaudeWave: mgcrea/cupertino
[![Featured on ClaudeWave](https://claudewave.com/api/badge/mgcrea-cupertino)](https://claudewave.com/repo/mgcrea-cupertino)
<a href="https://claudewave.com/repo/mgcrea-cupertino"><img src="https://claudewave.com/api/badge/mgcrea-cupertino" alt="Featured on ClaudeWave: mgcrea/cupertino" width="320" height="64" /></a>

Más MCP Servers

Alternativas a cupertino