Apple MCP Server
Provides tools for controlling various Apple ecosystem apps and macOS system functions, including Finder, Calendar, Reminders, Notes, Mail, Contacts, Photos, and more via AppleScript.
Allows control of Apple Music playback, playlists, search, and library management.
Enables sending and reading iMessages, as well as managing conversations.
Exposes macOS system controls such as volume, brightness, display settings, network, bluetooth, screenshots, keyboard input, text-to-speech, and system actions like sleep and lock.
Provides tools for browsing, opening URLs, managing tabs, and executing JavaScript in Safari.
Allows control of Spotify playback, playlists, search, and volume.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Apple MCP Servershow me the current song playing"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Apple MCP Server
An MCP server that exposes macOS system controls and Apple apps as structured tools for Claude. Built with TypeScript and the official @modelcontextprotocol/sdk.
31 tools, 303 actions, 4 resources. Each Apple app is a single MCP tool with an action parameter.
Requirements
macOS (tested on macOS 15 with Apple Silicon)
Node.js 18+
Claude CLI or any MCP-compatible client
Some features require "Allow JavaScript from Apple Events" in Safari > Develop
Setup
git clone https://github.com/lacausecrypto/apple-mcp-server.git
cd apple-mcp-server
npm install
npm run buildRegister in your MCP config (~/.claude/.mcp.json or project .mcp.json):
{
"mcpServers": {
"apple": {
"command": "node",
"args": ["/absolute/path/to/apple-mcp-server/dist/index.js"]
}
}
}How it works
Claude calls apple_music with {action: "now_playing"}
→ index.ts checks permissions (OPEN → proceed)
→ dispatches to domains/music.ts handler
→ handler calls runAppleScript() in executor.ts
→ AppleScript written to temp file, executed via osascript
→ result returned to Claude: "Bohemian Rhapsody — Queen (3:21/5min)"Permission System
Actions are classified into three levels. Conservative by default — destructive actions require explicit confirmation.
OPEN (default)
Read-only and safe actions execute immediately. No confirmation needed.
Claude: apple_volume.get → "Volume: 56%"
Claude: apple_music.now_playing → "Bohemian Rhapsody — Queen"
Claude: apple_sysinfo.battery → "95%; charging"PROTECTED (27 actions)
Destructive or irreversible actions return a preview and require confirm: true to execute.
Claude: apple_finder.empty_trash
→ "⚠️ apple_finder.empty_trash requires confirmation.
Reason: Permanently deletes all items in Trash
To proceed, call again with confirm: true."
Claude: apple_finder.empty_trash with confirm: true
→ "Trash emptied"Protected actions include: file delete/move/rename, send email/iMessage, post/like/reply on Twitter, delete contacts/notes/reminders/events, force quit apps, system sleep.
BLOCKED (3 actions)
Never executed. Returns an error with instructions to unblock.
Claude: apple_system.shutdown
→ "🚫 apple_system.shutdown is blocked.
Blocked by default (dangerous system action)."Blocked by default: shutdown, restart, logout.
Configuration
Override defaults via ~/.config/apple-mcp/permissions.json:
{
"blocked": ["empty_trash"],
"unprotected": ["like", "send"],
"unblocked": ["restart"],
"protected": ["play", "pause"]
}Key | Effect |
| Add actions to BLOCKED (on top of defaults) |
| Move from PROTECTED → OPEN (skip confirmation) |
| Move from BLOCKED → PROTECTED (allow with confirmation) |
| Move from OPEN → PROTECTED (add confirmation) |
Actions can be specified as "actionName" (global) or "apple_tool.actionName" (specific).
Rate Limiting
Prevents spam and abuse. Two independent sliding-window counters:
Global: max 30 tool calls per minute (all actions)
Protected: max 5 confirmed destructive actions per minute
When exceeded, the call is rejected with a wait time. Configurable:
{ "rate_limit": { "global_per_min": 60, "protected_per_min": 10 } }Dry-Run Mode
Preview every action without executing. Useful for testing what Claude would do:
{ "dry_run": true }Claude: apple_finder.delete(path: "~/old.pdf", confirm: true)
→ "[DRY RUN] Would execute apple_finder.delete (confirmed) — no action taken."All actions return previews. Nothing is executed. The audit log records dry_run events.
Audit Log
Every tool call is logged as a structured JSON line in ~/.local/occ/rag/apple-mcp-audit.jsonl:
{"ts":"2026-03-31T18:36:49Z","tool":"apple_volume","action":"get","permission":"open","confirmed":false,"dry_run":false,"result":"ok","duration_ms":104,"output":"Volume: 56%"}
{"ts":"2026-03-31T18:36:52Z","tool":"apple_finder","action":"empty_trash","permission":"protected","confirmed":false,"dry_run":false,"result":"protected_no_confirm","duration_ms":0}Queryable with jq:
# All blocked calls
cat apple-mcp-audit.jsonl | jq 'select(.result=="blocked")'
# Calls per tool
cat apple-mcp-audit.jsonl | jq -s 'group_by(.tool) | map({tool: .[0].tool, count: length})'
# Average duration per tool
cat apple-mcp-audit.jsonl | jq -s 'group_by(.tool) | map({tool: .[0].tool, avg_ms: (map(.duration_ms) | add / length)})'Tools
Tool | # | Actions | Protected/Blocked |
| 7 |
| — |
| 2 |
| — |
| 3 |
| — |
| 7 |
|
|
| 19 |
| — |
| 26 |
|
|
| 17 |
| — |
| 17 |
| — |
| 14 |
| — |
| 10 |
|
|
| 8 |
|
|
| 10 |
|
|
| 9 |
|
|
| 20 |
|
|
| 14 |
| — |
| 30 |
|
|
| 5 |
| — |
| 1 |
| — |
| 8 |
| — |
| 3 |
| — |
| 11 |
|
|
| 2 |
| — |
| 2 |
| — |
| 9 |
|
|
| 10 |
| — |
| 5 |
|
|
| 7 |
| — |
| 5 |
| — |
| 11 |
| — |
| 4 |
| — |
| 7 |
| — |
Security
What this provides
Permission system — Three-level access control (OPEN/PROTECTED/BLOCKED) enforced before execution. Protected actions require confirm: true. Configurable via JSON file.
Rate limiting — Sliding-window counters: 30 calls/min global, 5 protected/min. Prevents abuse loops.
Dry-run mode — All actions return previews without executing. Safe testing of what Claude would do.
Structured audit log — Every call logged as JSON line (tool, action, permission, result, duration). Queryable with jq.
Input validation — Not sandboxing. The server validates inputs before passing them to AppleScript or shell:
Function | What it does |
| Allowlist: only permits paths under |
| Escapes |
| Escapes quotes, strips |
| Strips shell metacharacters from app names. |
Concurrency — withLock() serializes Safari and Chrome tab operations to prevent race conditions.
Execution safety — AppleScript runs via temp .scpt files (not -e flag). Shell commands use execFile with array arguments (no shell interpolation).
Auto-launch — Apps that aren't running are launched automatically on -600 error and retried once.
Logging — All tool calls, permission checks, and errors logged to ~/.local/occ/rag/apple-mcp.log.
What this does NOT provide
No sandboxing. The Node process runs with your full user privileges. It can do anything you can do.
No network isolation. The server communicates via stdio (local only), but the actions it executes (email, tweets, etc.) reach the internet.
No encryption. Log files and the permission config are plain text.
No authentication on the MCP transport. Any process that can connect to stdio can call tools.
safePath is an allowlist, not a jail. It prevents operations on system paths, but
~/is allowed — which includes~/Library,~/.ssh, etc.
This is suitable for personal use on your own Mac. It is not designed for multi-user environments or adversarial contexts.
Resources
URI | Description |
| Current track from Apple Music or Spotify |
| Battery, disk, uptime, CPU load, RAM |
| All open Safari tabs |
| All open Chrome tabs |
Adding a new domain
Create
src/domains/myapp.ts(see existing domains for pattern)Import and register in
src/registry.tsIf destructive, add to
DEFAULT_PROTECTEDinsrc/permissions.tsnpm run build && npm test
Testing
npm run build
npm test # 135 tests (executor + registry + permissions)Known limitations
Books and Podcasts have limited AppleScript support. Some actions return generic errors.
Spotify doesn't expose playlists or "like" via AppleScript. Uses URL schemes as fallback.
Safari JS execution requires "Allow JavaScript from Apple Events" in Safari > Develop.
Twitter/X actions depend on the current DOM structure, which may change.
safePath allows all of
~/— including sensitive directories like~/.sshand~/Library.
Logging
~/.local/occ/rag/apple-mcp.log
Project structure
src/
index.ts Server entry, permission enforcement, tool dispatch
permissions.ts Three-level permission system with config file
types.ts Interfaces: ExecResult, DomainModule, DomainAction, ResourceDef
executor.ts Execution layer: AppleScript, shell, caching, locking, safety
registry.ts Domain registry and JSON Schema builder
domains/ 31 domain files (one per Apple app/category)
resources/ 4 MCP resource providers
tests/
executor.test.js Safety function tests
registry.test.js Domain registration tests
permissions.test.js Permission system testsLicense
MIT
This server cannot be installed
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/lacausecrypto/apple-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server