Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Apple Music integration via AppleScript (macOS) or MusicKit API
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 132% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 198% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 226% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 74% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 769% | 0% |
Guide for integrating with Apple Music. Covers AppleScript (macOS), MusicKit API (cross-platform), and the critical library-first requirement.
Invoke when users ask to:
You CANNOT add catalog songs directly to playlists.
Songs must be in the user's library first:
Why: Playlists use library IDs (i.abc123), not catalog IDs (1234567890).
This applies to both AppleScript and API approaches.
| Feature | AppleScript (macOS) | MusicKit API | |---------|:-------------------:|:------------:| | Setup required | None | Dev account + tokens | | Playlist management | Full | API-created only | | Playback control | Full | None | | Catalog search | No | Yes | | Library access | Instant | With tokens | | Cross-platform | No | Yes |
Zero setup. Works immediately with the Music app.
Run via Bash:
bashosascript -e 'tell application "Music" to playpause' osascript -e 'tell application "Music" to return name of current track'
Multi-line scripts:
bashosascript <<'EOF' tell application "Music" set t to current track return {name of t, artist of t} end tell EOF
| Category | Operations | |----------|------------| | Playback | play, pause, stop, resume, next track, previous track, fast forward, rewind | | Player State | player position, player state, sound volume, mute, shuffle enabled/mode, song repeat | | Current Track | name, artist, album, duration, time, rating, loved, disliked, genre, year, track number | | Library | search, list tracks, get track properties, set ratings | | Playlists | list, create, delete, rename, add tracks, remove tracks, get tracks | | AirPlay | list devices, select device, current device |
applescripttell application "Music" set t to current track -- Basic info name of t -- "Hey Jude" artist of t -- "The Beatles" album of t -- "1 (Remastered)" album artist of t -- "The Beatles" composer of t -- "Lennon-McCartney" genre of t -- "Rock" year of t -- 1968 -- Timing duration of t -- 431.0 (seconds) time of t -- "7:11" (formatted) start of t -- start time in seconds finish of t -- end time in seconds -- Track info track number of t -- 21 track count of t -- 27 disc number of t -- 1 disc count of t -- 1 -- Ratings rating of t -- 0-100 (20 per star) loved of t -- true/false disliked of t -- true/false -- Playback played count of t -- 42 played date of t -- date last played skipped count of t -- 3 skipped date of t -- date last skipped -- IDs persistent ID of t -- "ABC123DEF456" database ID of t -- 12345 end tell
applescripttell application "Music" set t to current track set rating of t to 80 -- 4 stars set loved of t to true set disliked of t to false set name of t to "New Name" -- rename track set genre of t to "Alternative" set year of t to 1995 end tell
applescripttell application "Music" player state -- stopped, playing, paused, fast forwarding, rewinding player position -- current position in seconds (read/write) sound volume -- 0-100 (read/write) mute -- true/false (read/write) shuffle enabled -- true/false (read/write) shuffle mode -- songs, albums, groupings song repeat -- off, one, all (read/write) current track -- track object current playlist -- playlist object current stream URL -- URL if streaming end tell
applescripttell application "Music" -- Play controls play -- play current selection pause stop resume playpause -- toggle play/pause next track previous track fast forward rewind -- Play specific content play (first track of library playlist 1 whose name contains "Hey Jude") play user playlist "Road Trip" -- Settings set player position to 60 -- seek to 1:00 set sound volume to 50 -- 0-100 set mute to true set shuffle enabled to true set song repeat to all -- off, one, all end tell
applescripttell application "Music" -- All library tracks every track of library playlist 1 -- Search by name tracks of library playlist 1 whose name contains "Beatles" -- Search by artist tracks of library playlist 1 whose artist contains "Beatles" -- Search by album tracks of library playlist 1 whose album contains "Abbey Road" -- Combined search tracks of library playlist 1 whose name contains "Hey" and artist contains "Beatles" -- By genre tracks of library playlist 1 whose genre is "Rock" -- By year tracks of library playlist 1 whose year is 1969 -- By rating tracks of library playlist 1 whose rating > 60 -- 3+ stars -- Loved tracks tracks of library playlist 1 whose loved is true -- Recently played (sort by played date) tracks of library playlist 1 whose played date > (current date) - 7 * days end tell
applescripttell application "Music" -- List all playlists name of every user playlist -- Get playlist user playlist "Road Trip" first user playlist whose name contains "Road" -- Create playlist make new user playlist with properties {name:"New Playlist", description:"My playlist"} -- Delete playlist delete user playlist "Old Playlist" -- Rename playlist set name of user playlist "Old Name" to "New Name" -- Get playlist tracks every track of user playlist "Road Trip" name of every track of user playlist "Road Trip" -- Add track to playlist (must be library track) set targetPlaylist to user playlist "Road Trip" set targetTrack to first track of library playlist 1 whose name contains "Hey Jude" duplicate targetTrack to targetPlaylist -- Remove track from playlist delete (first track of user playlist "Road Trip" whose name contains "Hey Jude") -- Playlist properties duration of user playlist "Road Trip" -- total duration time of user playlist "Road Trip" -- formatted duration count of tracks of user playlist "Road Trip" end tell
applescripttell application "Music" -- List AirPlay devices name of every AirPlay device -- Get current device current AirPlay devices -- Set output device set current AirPlay devices to {AirPlay device "Living Room"} -- Multiple devices set current AirPlay devices to {AirPlay device "Living Room", AirPlay device "Kitchen"} -- Device properties set d to AirPlay device "Living Room" name of d kind of d -- computer, AirPort Express, Apple TV, AirPlay device, Bluetooth device active of d -- true if playing available of d -- true if reachable selected of d -- true if in current devices sound volume of d -- 0-100 end tell
Always escape user input:
pythondef escape_applescript(s): return s.replace('\\', '\\\\').replace('"', '\\"') safe_name = escape_applescript(user_input) script = f'tell application "Music" to play user playlist "{safe_name}"'
Cross-platform but requires Apple Developer account ($99/year) and token setup.
Requirements:
Generate developer token:
pythonimport jwt, datetime with open('AuthKey_XXXXXXXXXX.p8') as f: private_key = f.read() token = jwt.encode( { 'iss': 'TEAM_ID', 'iat': int(datetime.datetime.now().timestamp()), 'exp': int((datetime.datetime.now() + datetime.timedelta(days=180)).timestamp()) }, private_key, algorithm='ES256', headers={'alg': 'ES256', 'kid': 'KEY_ID'} )
Get user token: Browser OAuth to https://authorize.music.apple.com/woa
Headers for all requests:
Authorization: Bearer {developer_token}
Music-User-Token: {user_music_token}Base URL: https://api.music.apple.com/v1
| Endpoint | Method | Description | |----------|--------|-------------| | /catalog/{storefront}/search | GET | Search songs, albums, artists, playlists | | /catalog/{storefront}/songs/{id} | GET | Song details | | /catalog/{storefront}/albums/{id} | GET | Album details | | /catalog/{storefront}/albums/{id}/tracks | GET | Album tracks | | /catalog/{storefront}/artists/{id} | GET | Artist details | | /catalog/{storefront}/artists/{id}/albums | GET | Artist's albums | | /catalog/{storefront}/artists/{id}/songs | GET | Artist's top songs | | /catalog/{storefront}/artists/{id}/related-artists | GET | Similar artists | | /catalog/{storefront}/playlists/{id} | GET | Playlist details | | /catalog/{storefront}/charts | GET | Top charts | | /catalog/{storefront}/genres | GET | All genres | | /catalog/{storefront}/search/suggestions | GET | Search autocomplete | | /catalog/{storefront}/stations/{id} | GET | Radio station |
| Endpoint | Method | Description | |----------|--------|-------------| | /me/library/songs | GET | All library songs | | /me/library/albums | GET | All library albums | | /me/library/artists | GET | All library artists | | /me/library/playlists | GET | All library playlists | | /me/library/playlists/{id} | GET | Playlist details | | /me/library/playlists/{id}/tracks | GET | Playlist tracks | | /me/library/search | GET | Search library | | /me/library | POST | Add to library | | /catalog/{sf}/songs/{id}/library | GET | Get library ID from catalog ID |
| Endpoint | Method | Description | |----------|--------|-------------| | /me/library/playlists | POST | Create playlist | | /me/library/playlists/{id}/tracks | POST | Add tracks to playlist |
| Endpoint | Method | Description | |----------|--------|-------------| | /me/recommendations | GET | Personalized recommendations | | /me/history/heavy-rotation | GET | Frequently played | | /me/recent/played | GET | Recently played | | /me/recent/added | GET | Recently added |
| Endpoint | Method | Description | |----------|--------|-------------| | /me/ratings/songs/{id} | GET | Get song rating | | /me/ratings/songs/{id} | PUT | Set song rating | | /me/ratings/songs/{id} | DELETE | Remove rating | | /me/ratings/albums/{id} | GET/PUT/DELETE | Album ratings | | /me/ratings/playlists/{id} | GET/PUT/DELETE | Playlist ratings |
| Endpoint | Method | Description | |----------|--------|-------------| | /storefronts | GET | All storefronts | | /storefronts/{id} | GET | Storefront details | | /me/storefront | GET | User's storefront |
| Parameter | Description | Example | |-----------|-------------|---------| | term | Search query | term=beatles | | types | Resource types | types=songs,albums | | limit | Results per page (max 25) | limit=10 | | offset | Pagination offset | offset=25 | | include | Related resources | include=artists,albums | | extend | Additional attributes | extend=editorialNotes | | l | Language code | l=en-US |
bashGET /v1/catalog/us/search?term=wonderwall&types=songs&limit=10 Response: { "results": { "songs": { "data": [{ "id": "1234567890", "type": "songs", "attributes": { "name": "Wonderwall", "artistName": "Oasis", "albumName": "(What's the Story) Morning Glory?", "durationInMillis": 258773, "releaseDate": "1995-10-02", "genreNames": ["Alternative", "Music"] } }] } } }
Adding a catalog song to a playlist requires 4 API calls:
pythonimport requests headers = { "Authorization": f"Bearer {dev_token}", "Music-User-Token": user_token } # 1. Search catalog r = requests.get( "https://api.music.apple.com/v1/catalog/us/search", headers=headers, params={"term": "Wonderwall Oasis", "types": "songs", "limit": 1} ) catalog_id = r.json()['results']['songs']['data'][0]['id'] # 2. Add to library requests.post( "https://api.music.apple.com/v1/me/library", headers=headers, params={"ids[songs]": catalog_id} ) # 3. Get library ID (catalog ID → library ID) r = requests.get( f"https://api.music.apple.com/v1/catalog/us/songs/{catalog_id}/library", headers=headers ) library_id = r.json()['data'][0]['id'] # 4. Add to playlist (library IDs only!) requests.post( f"https://api.music.apple.com/v1/me/library/playlists/{playlist_id}/tracks", headers={**headers, "Content-Type": "application/json"}, json={"data": [{"id": library_id, "type": "library-songs"}]} )
bashPOST /v1/me/library/playlists Content-Type: application/json { "attributes": { "name": "Road Trip", "description": "Summer vibes" }, "relationships": { "tracks": { "data": [] } } }
bash# Love a song (value: 1 = love, -1 = dislike) PUT /v1/me/ratings/songs/{id} Content-Type: application/json {"attributes": {"value": 1}}
❌ Using catalog IDs in playlists:
python# WRONG json={"data": [{"id": "1234567890", "type": "songs"}]}
Fix: Add to library first, get library ID, then add.
❌ Playing catalog songs via AppleScript:
applescript# WRONG play track id "1234567890"
Fix: Song must be in library.
❌ Unescaped AppleScript strings:
python# WRONG name = "Rock 'n Roll" script = f'tell application "Music" to play playlist "{name}"'
Fix: Escape quotes.
❌ Expired tokens: Dev tokens last 180 days max. Fix: Check expiration, handle 401 errors.
The mcp-applemusic MCP server handles all this complexity automatically: AppleScript escaping, token management, library-first workflow, ID conversions.
Install:
bashgit clone https://github.com/epheterson/mcp-applemusic.git cd mcp-applemusic && python3 -m venv venv && source venv/bin/activate pip install -e .
Configure Claude Desktop:
json{ "mcpServers": { "Apple Music": { "command": "/path/to/mcp-applemusic/venv/bin/python", "args": ["-m", "applemusic_mcp"] } } }
On macOS, most features work immediately. For catalog features or Windows/Linux, see the repo README.
| Manual | mcp-applemusic | |--------|----------------| | 4 API calls to add song | playlist(action="add", auto_search=True) | | AppleScript escaping | Automatic | | Token management | Automatic with warnings |
Other measured skills in the registry, with their headline benchmark lift.