使用说明
苹果MCP服务器
一个MCP服务器,将macOS系统控件和Apple应用程序作为Claude的结构化工具公开。使用TypeScript和官方 @modelcontextprotocol/sdk.
31个工具,303个动作,4个资源。 每个苹果应用程序都是一个MCP工具 action 参数。
需求
- macOS(使用Apple Silicon在macOS 15上测试)
- Node.js 18+
- Claude CLI或任何兼容MCP的客户端
- 某些功能需要在Safari>开发中“允许来自Apple活动的JavaScript”
设置
git clone https://github.com/lacausecrypto/apple-mcp-server.git
cd apple-mcp-server
npm install
npm run build
在MCP配置中注册(~/.claude/.mcp.json 或项目 .mcp.json):
{
"mcpServers": {
"apple": {
"command": "node",
"args": ["/absolute/path/to/apple-mcp-server/dist/index.js"]
}
}
}
运作原理
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)"
权限系统
行动分为三个层次。 默认保守 --破坏性行为需要明确的确认。
打开(默认)
只读和安全操作立即执行。无需确认。
Claude: apple_volume.get → "Volume: 56%"
Claude: apple_music.now_playing → "Bohemian Rhapsody — Queen"
Claude: apple_sysinfo.battery → "95%; charging"
受保护(27项行动)
破坏性或不可逆的操作将返回预览并要求 confirm: true 执行。
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"
受保护的操作包括:文件删除/移动/重命名、发送电子邮件/iMessage、在推特上发帖/点赞/回复、删除联系人/笔记/提醒/事件、强制退出应用程序、系统睡眠。
已阻止(3个动作)
从未被处决。返回一个错误,并指示取消阻止。
Claude: apple_system.shutdown
→ "🚫 apple_system.shutdown is blocked.
Blocked by default (dangerous system action)."
默认情况下被阻止: shutdown, restart, logout.
配置
通过以下方式覆盖默认值 ~/.config/apple-mcp/permissions.json:
{
"blocked": ["empty_trash"],
"unprotected": ["like", "send"],
"unblocked": ["restart"],
"protected": ["play", "pause"]
}
| 关键 | 效果 |
|---|---|
blocked |
将操作添加到BLOCKED(默认值之上) |
unprotected |
从受保护状态转移→ 打开(跳过确认) |
unblocked |
从阻塞状态移动→ 受保护(确认后允许) |
protected |
从OPEN移动→ 受保护(添加确认) |
动作可以指定为 "actionName" (全球)或 "apple_tool.actionName" (具体)。
速率限制
防止垃圾邮件和滥用。两个独立的滑动窗口计数器:
- 全球:每分钟最多30次工具调用(所有操作)
- 受保护的:每分钟最多5次确认的破坏行为
超过此时间后,呼叫将被拒绝并等待一段时间。可配置:
{ "rate_limit": { "global_per_min": 60, "protected_per_min": 10 } }
干运行模式
预览每个操作而不执行。有助于测试Claude会做什么:
{ "dry_run": true }
Claude: apple_finder.delete(path: "~/old.pdf", confirm: true)
→ "[DRY RUN] Would execute apple_finder.delete (confirmed) — no action taken."
所有操作都返回预览。什么都没有被执行。审计日志记录 dry_run 事件。
审计日志
每个工具调用都以结构化JSON行的形式记录在 ~/.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}
可通过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)})'
工具
| 工具 | # | 操作 | 已保护/已阻止 |
|---|---|---|---|
apple_volume |
7 | get set up down mute unmute info |
— |
apple_brightness |
2 | up down |
— |
apple_clipboard |
3 | get set clear |
— |
apple_apps |
7 | open quit is_running list_running hide activate force_quit |
force_quit |
apple_sysinfo |
19 | battery disk uptime ip macos_version cpu memory top_processes hostname resolution summary bluetooth_devices audio_devices printers displays usb_devices network_interfaces serial_number model |
— |
apple_music |
26 | play pause stop next prev restart now_playing shuffle_on shuffle_off repeat_off repeat_one repeat_all play_playlist list_playlists set_volume love dislike search play_song queue_next add_to_playlist create_playlist get_lyrics radio remove_from_playlist delete_playlist |
delete_playlist remove_from_playlist |
apple_spotify |
17 | play pause next prev now_playing set_volume shuffle playpause play_playlist list_playlists like repeat_off repeat_on search play_track current_album current_artist |
— |
apple_safari |
17 | open_url current_url current_title list_tabs close_tab new_tab reload page_text reading_list js_execute back forward bookmarks history_recent private_window close_window tab_count |
— |
apple_chrome |
14 | open_url current_url current_title list_tabs close_tab reload js_execute back forward new_window new_incognito close_window tab_count new_tab |
— |
apple_mail |
10 | unread_count check unread_list read_body search draft mailboxes send mark_all_read move_to_trash |
send mark_all_read move_to_trash |
apple_calendar |
8 | list today tomorrow create_event week date_events delete_event modify_event |
delete_event modify_event |
apple_reminders |
10 | list_lists list add complete set_due set_priority add_note overdue create_list delete |
delete |
apple_notes |
9 | list create read search folders move append count delete |
delete |
apple_finder |
20 | open_folder reveal desktop_files trash_count create_folder file_info copy get_selection tags set_tag list_folder disk_info empty_trash delete move rename eject_disk eject_all set_wallpaper create_alias |
empty_trash delete move rename eject_disk eject_all set_wallpaper |
apple_windows |
14 | frontmost_app minimize minimize_all maximize left_half right_half fullscreen close hide_app hide_others center resize list_windows switch_to |
— |
apple_system |
30 | sleep_display lock dark_mode dnd_on dnd_off caffeinate decaffeinate wifi_status wifi_on wifi_off wifi_network bluetooth_on bluetooth_off run_shortcut list_shortcuts open_prefs display_settings sound_settings network_settings airdrop screen_saver login_items time_machine audio_output audio_input sleep eject_all_disks shutdown restart logout |
sleep eject_all_disks ·已阻止: shutdown restart logout |
apple_screenshot |
5 | full clipboard timed area window |
— |
apple_notification |
1 | send |
— |
apple_keyboard |
8 | type_text press_key copy paste undo redo save select_all |
— |
apple_tts |
3 | say list_voices stop |
— |
apple_twitter |
11 | draft save list_drafts feed notifications dm_check post post_draft reply like retweet |
post post_draft reply like retweet |
apple_facetime |
2 | call audio |
— |
apple_maps |
2 | open directions |
— |
apple_contacts |
9 | search get list create groups group_members delete update_phone update_email |
delete update_phone update_email |
apple_photos |
10 | albums recent search favorites album_contents export count create_album add_to_album import |
— |
apple_messages |
5 | recent unread conversation search send |
send |
apple_podcasts |
7 | now_playing play pause next shows episodes search |
— |
apple_books |
5 | library reading_now collections search open |
— |
apple_iwork |
11 | pages_create pages_open pages_export_pdf numbers_create numbers_open numbers_export_pdf keynote_create keynote_open keynote_export_pdf keynote_start_slideshow keynote_stop_slideshow |
— |
apple_preview |
4 | open list_open close close_all |
— |
apple_textedit |
7 | create open get_text set_text save close list_open |
— |
安全
这提供了什么
许可制度 --执行前执行三级访问控制(打开/保护/阻止)。受保护的行动需要 confirm: true.可通过JSON文件配置。
速率限制 --滑动窗口计数器:全局30次/分钟,保护5次/分钟。防止滥用循环。
干运行模式 --所有操作都会返回预览而不执行。安全测试克劳德会做什么。
结构化审计日志 --每个调用都记录为JSON行(工具、操作、权限、结果、持续时间)。可通过jq查询。
输入验证 --不是沙盒。服务器在将输入传递给AppleScript或shell之前对其进行验证:
| 功能 | 它的作用 |
|---|---|
safePath() |
允许名单:只允许以下路径 ~/, /tmp, /Volumes/nvme, /Applications其他都被拒绝了。 |
safeAS() |
逃跑 \ 和 " 用于AppleScript字符串插值。防止在引号字符串内注入脚本。 |
safeSQL() |
逃脱报价,条 ;, --, /* */、UNION、DDL关键字、十六进制文字。用于iMessage sqlite3查询。 |
safeAppName() |
从应用程序名称中删除shell元字符。 |
并发 — withLock() 序列化Safari和Chrome选项卡操作以防止竞争条件。
执行安全 --AppleScript通过temp运行 .scpt 文件(不是 -e 旗)。Shell命令使用 execFile 带数组参数(无shell插值)。
自动启动 --未运行的应用程序会自动启动 -600 错误,重试一次。
日志记录 --所有工具调用、权限检查和错误都记录到 ~/.local/occ/rag/apple-mcp.log.
这没有提供什么
- 没有沙盒。 Node进程以您的完全用户权限运行。它可以做任何你能做的事情。
- 无网络隔离。 服务器通过stdio(仅限本地)进行通信,但它执行的操作(电子邮件、推特等)会到达互联网。
- 没有加密。 日志文件和权限配置是纯文本的。
- MCP传输上没有身份验证。 任何可以连接到stdio的进程都可以调用工具。
- safePath是一个排外主义者,而不是监狱。 它阻止在系统路径上进行操作,但是
~/是允许的,包括~/Library,~/.ssh等等。
这适用于您自己的Mac上的个人使用。 它不是为多用户环境或对抗环境而设计的。
资源
| URI | 描述 |
|---|---|
apple://now-playing |
来自Apple Music或Spotify的当前曲目 |
apple://system-info |
电池、磁盘、正常运行时间、CPU负载、RAM |
apple://open-tabs/safari |
所有打开的Safari选项卡 |
apple://open-tabs/chrome |
所有打开的Chrome标签页 |
添加新域
- 创建
src/domains/myapp.ts(模式见现有域) - 导入并注册
src/registry.ts - 如果具有破坏性,请添加
DEFAULT_PROTECTED在src/permissions.ts npm run build && npm test
测试
npm run build
npm test # 135 tests (executor + registry + permissions)
已知限制
- 书籍和播客 AppleScript支持有限。某些操作返回通用错误。
- 声破天 不会通过AppleScript显示播放列表或“点赞”。使用URL方案作为回退。
- Safari JS执行 需要在Safari>开发中选择“允许来自Apple事件的JavaScript”。
- 推特/X 操作取决于当前的DOM结构,而DOM结构可能会发生变化。
- safePath 允许所有
~/--包括敏感目录,如~/.ssh和~/Library.
日志记录
~/.local/occ/rag/apple-mcp.log
项目结构
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 tests
许可证
麻省理工学院