手头有一份《音乐天堂》老合辑《穿过骨头抚摸你》的 28 首歌单,想原样搬进 Apple Music。听起来是个小事:建个歌单、逐首加歌、搞定。结果这一路踩的坑,值得单独写一篇。

第一回合:AppleScript 全线超时

macOS 上操作 Music.app 最正统的方式是 AppleScript:

tell application "Music" to make new playlist with properties {name:"穿过骨头抚摸你"}

结果等来的是:

execution error: Music got an error: AppleEvent timed out. (-1712)

不只是建歌单——get count of playlists、get name of every window,所有需要读写库的操作全部超时,而 GUI 完全正常:主页加载完整、账号已登录、还能正常播放。这是典型的"引擎活着、库通道死了"。

排查:真凶是 AMPLibraryAgent

用 lsof 顺着打开的文件摸,发现 AMPLibraryAgent(Apple Music 云库引擎)正锁着 Library.musicdb,进程状态 sleeping、0% CPU,已经挂机 30+ 小时。它持有写锁不释放,Music.app 的任何库写入都在等它——等不到,就超时。

试过的手段:

# 1. 重启 Music.app
killall Music && open -a Music
# 2. 杀 AMPLibraryAgent(launchd 会自动拉起新的)
kill 89124
# 3. 连辅助进程一起清 + 清缓存
killall -9 Music AMPLibraryAgent MediaLibraryService AMPArtworkAgent
rm -rf ~/Library/Caches/com.apple.AMP*
# 4. sudo 清系统级守护域
sudo launchctl kill -9 gui/$(id -u)/com.apple.AMPLibraryAgent

全都不解。新拉起的 AMPLibraryAgent 继续锁库,AppleScript 继续超时。Gemini 的建议也只是确认了这是 macOS 14/15 上 AMPLibraryAgent 与本地 SQLite 死锁的已知问题,常规 kill 无效是因为 IPC 通道没释放。

换路:网页版 MusicKit API 也不行

本地库走不通,那就走云端——music.apple.com 网页版登录后,页面里有现成的 MusicKit 实例(devToken + media-user-token 都在)。直接在浏览器控制台调:

const music = MusicKit.getInstance();
await music.api.post('/v1/me/library/playlists', {
  attributes: { name: '穿过骨头抚摸你' }
});

返回 400 Missing Request Body——新版 MusicKit 的参数格式跟文档对不上。换成原生 fetch 带 token 直接打 amp-api,又撞 403 Invalid authentication。网页版这条路也堵死。

正解:applemusic-mcp 走 web API 模式

朋友推荐了 applemusic-mcp——一个专门管 Apple Music 的 MCP Server,支持建歌单、加歌、改名、移动、播放控制全套操作。

uv tool install 'applemusic-mcp[browser]'

登录用的是 web 授权路径(不需要 Apple Developer 账号)。login --chrome 会在浏览器里走授权流程;如果卡住,把已登录 Chrome 的 Cookies 复制到它的 profile 再重跑,直接认账:

Already signed in to Apple Music. Media-user-token saved.

关键一步:强制它走 web API 而不是本机 AppleScript。这个 MCP 在 macOS 上默认检测到 osascript 就优先用本地 Music.app——但我们的本地库恰恰是死的。解法很朴素:启动 serve 时把 PATH 设为 /bin:/sbin(不含 /usr/bin,osascript 在那里),它就判定"AppleScript 不可用",自动切到 web API:

sp = StdioServerParameters(
    command="/Users/camac/.local/bin/applemusic-mcp",
    args=["serve"],
    env={"PATH": "/bin:/sbin", "HOME": os.environ.get("HOME","")}
)

一试就通,536 个歌单秒列出来。

加歌:catalog id 锁版本 + 国区坑

28 首里 24 首顺利入库,全部匹配到原始正式专辑版本:

Eraser (Polite) - Nine Inch Nails - Further Down The Spiral [1994]
Something In the Way - Nirvana - Nevermind [1991]
Over - Portishead - Portishead [1997]
The Eternal - Joy Division - Closer [1980]

用 catalog 搜索拿数字 id 传给 add,能锁定精确版本,避免歌名撞车。中间踩了个典型的坑——storefront:账号是 CN 区但 MCP 默认走 us 目录,部分歌曲报 not found in catalog。切到 cn 区重新搜 id 就通了:

config(action='set-pref', preference='storefront', string_value='cn')

最终 4 首确认国区版权缺失(Björk《It’s Not Up to You》、Suede《The Next Life》、Black Tape《A Teardrop Left Behind》、久石譲《少年の日の夕暮れ》),写进了歌单简介说明。

复盘

  • 本地 Music.app 的 AppleScript 通道:AMPLibraryAgent WAL 死锁后无解,重启/杀进程/清缓存/sudo 全试过
  • 网页版 MusicKit:token 齐全但新版 API 参数格式不兼容
  • applemusic-mcp web 模式:PATH 藏 osascript 强制走 web API,一次成功

以后遇到"Mac 上想自动操作 Apple Music",别从 AppleScript 起步——直接上 applemusic-mcp 的 web 模式。本地库是地雷,云端 API 是路。