{
  "schemaVersion": "1.0",
  "item": {
    "slug": "mcp-applemusic",
    "name": "Apple Music",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/epheterson/mcp-applemusic",
    "canonicalUrl": "https://clawhub.ai/epheterson/mcp-applemusic",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/mcp-applemusic",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=mcp-applemusic",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "SKILL.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/mcp-applemusic"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/mcp-applemusic",
    "agentPageUrl": "https://openagent3.xyz/skills/mcp-applemusic/agent",
    "manifestUrl": "https://openagent3.xyz/skills/mcp-applemusic/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/mcp-applemusic/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Apple Music Integration",
        "body": "Guide for integrating with Apple Music. Covers AppleScript (macOS), MusicKit API (cross-platform), and the critical library-first requirement."
      },
      {
        "title": "When to Use",
        "body": "Invoke when users ask to:\n\nManage playlists (create, add/remove tracks, list)\nControl playback (play, pause, skip, volume)\nSearch catalog or library\nAdd songs to library\nAccess listening history or recommendations"
      },
      {
        "title": "Critical Rule: Library-First Workflow",
        "body": "You CANNOT add catalog songs directly to playlists.\n\nSongs must be in the user's library first:\n\n❌ Catalog ID → Playlist (fails)\n✅ Catalog ID → Library → Playlist (works)\n\nWhy: Playlists use library IDs (i.abc123), not catalog IDs (1234567890).\n\nThis applies to both AppleScript and API approaches."
      },
      {
        "title": "Platform Comparison",
        "body": "FeatureAppleScript (macOS)MusicKit APISetup requiredNoneDev account + tokensPlaylist managementFullAPI-created onlyPlayback controlFullNoneCatalog searchNoYesLibrary accessInstantWith tokensCross-platformNoYes"
      },
      {
        "title": "AppleScript (macOS)",
        "body": "Zero setup. Works immediately with the Music app.\n\nRun via Bash:\n\nosascript -e 'tell application \"Music\" to playpause'\nosascript -e 'tell application \"Music\" to return name of current track'\n\nMulti-line scripts:\n\nosascript <<'EOF'\ntell application \"Music\"\n    set t to current track\n    return {name of t, artist of t}\nend tell\nEOF"
      },
      {
        "title": "Available Operations",
        "body": "CategoryOperationsPlaybackplay, pause, stop, resume, next track, previous track, fast forward, rewindPlayer Stateplayer position, player state, sound volume, mute, shuffle enabled/mode, song repeatCurrent Trackname, artist, album, duration, time, rating, loved, disliked, genre, year, track numberLibrarysearch, list tracks, get track properties, set ratingsPlaylistslist, create, delete, rename, add tracks, remove tracks, get tracksAirPlaylist devices, select device, current device"
      },
      {
        "title": "Track Properties (Read)",
        "body": "tell application \"Music\"\n    set t to current track\n    -- Basic info\n    name of t           -- \"Hey Jude\"\n    artist of t         -- \"The Beatles\"\n    album of t          -- \"1 (Remastered)\"\n    album artist of t   -- \"The Beatles\"\n    composer of t       -- \"Lennon-McCartney\"\n    genre of t          -- \"Rock\"\n    year of t           -- 1968\n\n    -- Timing\n    duration of t       -- 431.0 (seconds)\n    time of t           -- \"7:11\" (formatted)\n    start of t          -- start time in seconds\n    finish of t         -- end time in seconds\n\n    -- Track info\n    track number of t   -- 21\n    track count of t    -- 27\n    disc number of t    -- 1\n    disc count of t     -- 1\n\n    -- Ratings\n    rating of t         -- 0-100 (20 per star)\n    loved of t          -- true/false\n    disliked of t       -- true/false\n\n    -- Playback\n    played count of t   -- 42\n    played date of t    -- date last played\n    skipped count of t  -- 3\n    skipped date of t   -- date last skipped\n\n    -- IDs\n    persistent ID of t  -- \"ABC123DEF456\"\n    database ID of t    -- 12345\nend tell"
      },
      {
        "title": "Track Properties (Writable)",
        "body": "tell application \"Music\"\n    set t to current track\n    set rating of t to 80          -- 4 stars\n    set loved of t to true\n    set disliked of t to false\n    set name of t to \"New Name\"    -- rename track\n    set genre of t to \"Alternative\"\n    set year of t to 1995\nend tell"
      },
      {
        "title": "Player State Properties",
        "body": "tell application \"Music\"\n    player state          -- stopped, playing, paused, fast forwarding, rewinding\n    player position       -- current position in seconds (read/write)\n    sound volume          -- 0-100 (read/write)\n    mute                  -- true/false (read/write)\n    shuffle enabled       -- true/false (read/write)\n    shuffle mode          -- songs, albums, groupings\n    song repeat           -- off, one, all (read/write)\n    current track         -- track object\n    current playlist      -- playlist object\n    current stream URL    -- URL if streaming\nend tell"
      },
      {
        "title": "Playback Commands",
        "body": "tell application \"Music\"\n    -- Play controls\n    play                          -- play current selection\n    pause\n    stop\n    resume\n    playpause                     -- toggle play/pause\n    next track\n    previous track\n    fast forward\n    rewind\n\n    -- Play specific content\n    play (first track of library playlist 1 whose name contains \"Hey Jude\")\n    play user playlist \"Road Trip\"\n\n    -- Settings\n    set player position to 60     -- seek to 1:00\n    set sound volume to 50        -- 0-100\n    set mute to true\n    set shuffle enabled to true\n    set song repeat to all        -- off, one, all\nend tell"
      },
      {
        "title": "Library Queries",
        "body": "tell application \"Music\"\n    -- All library tracks\n    every track of library playlist 1\n\n    -- Search by name\n    tracks of library playlist 1 whose name contains \"Beatles\"\n\n    -- Search by artist\n    tracks of library playlist 1 whose artist contains \"Beatles\"\n\n    -- Search by album\n    tracks of library playlist 1 whose album contains \"Abbey Road\"\n\n    -- Combined search\n    tracks of library playlist 1 whose name contains \"Hey\" and artist contains \"Beatles\"\n\n    -- By genre\n    tracks of library playlist 1 whose genre is \"Rock\"\n\n    -- By year\n    tracks of library playlist 1 whose year is 1969\n\n    -- By rating\n    tracks of library playlist 1 whose rating > 60  -- 3+ stars\n\n    -- Loved tracks\n    tracks of library playlist 1 whose loved is true\n\n    -- Recently played (sort by played date)\n    tracks of library playlist 1 whose played date > (current date) - 7 * days\nend tell"
      },
      {
        "title": "Playlist Operations",
        "body": "tell application \"Music\"\n    -- List all playlists\n    name of every user playlist\n\n    -- Get playlist\n    user playlist \"Road Trip\"\n    first user playlist whose name contains \"Road\"\n\n    -- Create playlist\n    make new user playlist with properties {name:\"New Playlist\", description:\"My playlist\"}\n\n    -- Delete playlist\n    delete user playlist \"Old Playlist\"\n\n    -- Rename playlist\n    set name of user playlist \"Old Name\" to \"New Name\"\n\n    -- Get playlist tracks\n    every track of user playlist \"Road Trip\"\n    name of every track of user playlist \"Road Trip\"\n\n    -- Add track to playlist (must be library track)\n    set targetPlaylist to user playlist \"Road Trip\"\n    set targetTrack to first track of library playlist 1 whose name contains \"Hey Jude\"\n    duplicate targetTrack to targetPlaylist\n\n    -- Remove track from playlist\n    delete (first track of user playlist \"Road Trip\" whose name contains \"Hey Jude\")\n\n    -- Playlist properties\n    duration of user playlist \"Road Trip\"   -- total duration\n    time of user playlist \"Road Trip\"       -- formatted duration\n    count of tracks of user playlist \"Road Trip\"\nend tell"
      },
      {
        "title": "AirPlay",
        "body": "tell application \"Music\"\n    -- List AirPlay devices\n    name of every AirPlay device\n\n    -- Get current device\n    current AirPlay devices\n\n    -- Set output device\n    set current AirPlay devices to {AirPlay device \"Living Room\"}\n\n    -- Multiple devices\n    set current AirPlay devices to {AirPlay device \"Living Room\", AirPlay device \"Kitchen\"}\n\n    -- Device properties\n    set d to AirPlay device \"Living Room\"\n    name of d\n    kind of d           -- computer, AirPort Express, Apple TV, AirPlay device, Bluetooth device\n    active of d         -- true if playing\n    available of d      -- true if reachable\n    selected of d       -- true if in current devices\n    sound volume of d   -- 0-100\nend tell"
      },
      {
        "title": "String Escaping",
        "body": "Always escape user input:\n\ndef escape_applescript(s):\n    return s.replace('\\\\', '\\\\\\\\').replace('\"', '\\\\\"')\n\nsafe_name = escape_applescript(user_input)\nscript = f'tell application \"Music\" to play user playlist \"{safe_name}\"'"
      },
      {
        "title": "Limitations",
        "body": "No catalog access - only library content\nmacOS only - no Windows/Linux"
      },
      {
        "title": "MusicKit API",
        "body": "Cross-platform but requires Apple Developer account ($99/year) and token setup."
      },
      {
        "title": "Authentication",
        "body": "Requirements:\n\nApple Developer account\nMusicKit key (.p8 file) from developer portal\nDeveloper token (JWT, 180 day max)\nUser music token (browser OAuth)\n\nGenerate developer token:\n\nimport jwt, datetime\n\nwith open('AuthKey_XXXXXXXXXX.p8') as f:\n    private_key = f.read()\n\ntoken = jwt.encode(\n    {\n        'iss': 'TEAM_ID',\n        'iat': int(datetime.datetime.now().timestamp()),\n        'exp': int((datetime.datetime.now() + datetime.timedelta(days=180)).timestamp())\n    },\n    private_key,\n    algorithm='ES256',\n    headers={'alg': 'ES256', 'kid': 'KEY_ID'}\n)\n\nGet user token: Browser OAuth to https://authorize.music.apple.com/woa\n\nHeaders for all requests:\n\nAuthorization: Bearer {developer_token}\nMusic-User-Token: {user_music_token}\n\nBase URL: https://api.music.apple.com/v1"
      },
      {
        "title": "Catalog (Public - dev token only)",
        "body": "EndpointMethodDescription/catalog/{storefront}/searchGETSearch songs, albums, artists, playlists/catalog/{storefront}/songs/{id}GETSong details/catalog/{storefront}/albums/{id}GETAlbum details/catalog/{storefront}/albums/{id}/tracksGETAlbum tracks/catalog/{storefront}/artists/{id}GETArtist details/catalog/{storefront}/artists/{id}/albumsGETArtist's albums/catalog/{storefront}/artists/{id}/songsGETArtist's top songs/catalog/{storefront}/artists/{id}/related-artistsGETSimilar artists/catalog/{storefront}/playlists/{id}GETPlaylist details/catalog/{storefront}/chartsGETTop charts/catalog/{storefront}/genresGETAll genres/catalog/{storefront}/search/suggestionsGETSearch autocomplete/catalog/{storefront}/stations/{id}GETRadio station"
      },
      {
        "title": "Library (Requires user token)",
        "body": "EndpointMethodDescription/me/library/songsGETAll library songs/me/library/albumsGETAll library albums/me/library/artistsGETAll library artists/me/library/playlistsGETAll library playlists/me/library/playlists/{id}GETPlaylist details/me/library/playlists/{id}/tracksGETPlaylist tracks/me/library/searchGETSearch library/me/libraryPOSTAdd to library/catalog/{sf}/songs/{id}/libraryGETGet library ID from catalog ID"
      },
      {
        "title": "Playlist Management",
        "body": "EndpointMethodDescription/me/library/playlistsPOSTCreate playlist/me/library/playlists/{id}/tracksPOSTAdd tracks to playlist"
      },
      {
        "title": "Personalization",
        "body": "EndpointMethodDescription/me/recommendationsGETPersonalized recommendations/me/history/heavy-rotationGETFrequently played/me/recent/playedGETRecently played/me/recent/addedGETRecently added"
      },
      {
        "title": "Ratings",
        "body": "EndpointMethodDescription/me/ratings/songs/{id}GETGet song rating/me/ratings/songs/{id}PUTSet song rating/me/ratings/songs/{id}DELETERemove rating/me/ratings/albums/{id}GET/PUT/DELETEAlbum ratings/me/ratings/playlists/{id}GET/PUT/DELETEPlaylist ratings"
      },
      {
        "title": "Storefronts",
        "body": "EndpointMethodDescription/storefrontsGETAll storefronts/storefronts/{id}GETStorefront details/me/storefrontGETUser's storefront"
      },
      {
        "title": "Common Query Parameters",
        "body": "ParameterDescriptionExampletermSearch queryterm=beatlestypesResource typestypes=songs,albumslimitResults per page (max 25)limit=10offsetPagination offsetoffset=25includeRelated resourcesinclude=artists,albumsextendAdditional attributesextend=editorialNoteslLanguage codel=en-US"
      },
      {
        "title": "Search Example",
        "body": "GET /v1/catalog/us/search?term=wonderwall&types=songs&limit=10\n\nResponse:\n{\n  \"results\": {\n    \"songs\": {\n      \"data\": [{\n        \"id\": \"1234567890\",\n        \"type\": \"songs\",\n        \"attributes\": {\n          \"name\": \"Wonderwall\",\n          \"artistName\": \"Oasis\",\n          \"albumName\": \"(What's the Story) Morning Glory?\",\n          \"durationInMillis\": 258773,\n          \"releaseDate\": \"1995-10-02\",\n          \"genreNames\": [\"Alternative\", \"Music\"]\n        }\n      }]\n    }\n  }\n}"
      },
      {
        "title": "Library-First Workflow (Complete)",
        "body": "Adding a catalog song to a playlist requires 4 API calls:\n\nimport requests\n\nheaders = {\n    \"Authorization\": f\"Bearer {dev_token}\",\n    \"Music-User-Token\": user_token\n}\n\n# 1. Search catalog\nr = requests.get(\n    \"https://api.music.apple.com/v1/catalog/us/search\",\n    headers=headers,\n    params={\"term\": \"Wonderwall Oasis\", \"types\": \"songs\", \"limit\": 1}\n)\ncatalog_id = r.json()['results']['songs']['data'][0]['id']\n\n# 2. Add to library\nrequests.post(\n    \"https://api.music.apple.com/v1/me/library\",\n    headers=headers,\n    params={\"ids[songs]\": catalog_id}\n)\n\n# 3. Get library ID (catalog ID → library ID)\nr = requests.get(\n    f\"https://api.music.apple.com/v1/catalog/us/songs/{catalog_id}/library\",\n    headers=headers\n)\nlibrary_id = r.json()['data'][0]['id']\n\n# 4. Add to playlist (library IDs only!)\nrequests.post(\n    f\"https://api.music.apple.com/v1/me/library/playlists/{playlist_id}/tracks\",\n    headers={**headers, \"Content-Type\": \"application/json\"},\n    json={\"data\": [{\"id\": library_id, \"type\": \"library-songs\"}]}\n)"
      },
      {
        "title": "Create Playlist",
        "body": "POST /v1/me/library/playlists\nContent-Type: application/json\n\n{\n  \"attributes\": {\n    \"name\": \"Road Trip\",\n    \"description\": \"Summer vibes\"\n  },\n  \"relationships\": {\n    \"tracks\": {\n      \"data\": []\n    }\n  }\n}"
      },
      {
        "title": "Ratings",
        "body": "# Love a song (value: 1 = love, -1 = dislike)\nPUT /v1/me/ratings/songs/{id}\nContent-Type: application/json\n\n{\"attributes\": {\"value\": 1}}"
      },
      {
        "title": "Limitations",
        "body": "No playback control - API cannot play/pause/skip\nPlaylist editing - can only modify API-created playlists\nToken management - dev tokens expire every 180 days\nRate limits - Apple enforces request limits"
      },
      {
        "title": "Common Mistakes",
        "body": "❌ Using catalog IDs in playlists:\n\n# WRONG\njson={\"data\": [{\"id\": \"1234567890\", \"type\": \"songs\"}]}\n\nFix: Add to library first, get library ID, then add.\n\n❌ Playing catalog songs via AppleScript:\n\n# WRONG\nplay track id \"1234567890\"\n\nFix: Song must be in library.\n\n❌ Unescaped AppleScript strings:\n\n# WRONG\nname = \"Rock 'n Roll\"\nscript = f'tell application \"Music\" to play playlist \"{name}\"'\n\nFix: Escape quotes.\n\n❌ Expired tokens:\nDev tokens last 180 days max.\nFix: Check expiration, handle 401 errors."
      },
      {
        "title": "The Easy Way: mcp-applemusic",
        "body": "The mcp-applemusic MCP server handles all this complexity automatically: AppleScript escaping, token management, library-first workflow, ID conversions.\n\nInstall:\n\ngit clone https://github.com/epheterson/mcp-applemusic.git\ncd mcp-applemusic && python3 -m venv venv && source venv/bin/activate\npip install -e .\n\nConfigure Claude Desktop:\n\n{\n  \"mcpServers\": {\n    \"Apple Music\": {\n      \"command\": \"/path/to/mcp-applemusic/venv/bin/python\",\n      \"args\": [\"-m\", \"applemusic_mcp\"]\n    }\n  }\n}\n\nOn macOS, most features work immediately. For catalog features or Windows/Linux, see the repo README.\n\nManualmcp-applemusic4 API calls to add songplaylist(action=\"add\", auto_search=True)AppleScript escapingAutomaticToken managementAutomatic with warnings"
      }
    ],
    "body": "Apple Music Integration\n\nGuide for integrating with Apple Music. Covers AppleScript (macOS), MusicKit API (cross-platform), and the critical library-first requirement.\n\nWhen to Use\n\nInvoke when users ask to:\n\nManage playlists (create, add/remove tracks, list)\nControl playback (play, pause, skip, volume)\nSearch catalog or library\nAdd songs to library\nAccess listening history or recommendations\nCritical Rule: Library-First Workflow\n\nYou CANNOT add catalog songs directly to playlists.\n\nSongs must be in the user's library first:\n\n❌ Catalog ID → Playlist (fails)\n✅ Catalog ID → Library → Playlist (works)\n\nWhy: Playlists use library IDs (i.abc123), not catalog IDs (1234567890).\n\nThis applies to both AppleScript and API approaches.\n\nPlatform Comparison\nFeature\tAppleScript (macOS)\tMusicKit API\nSetup required\tNone\tDev account + tokens\nPlaylist management\tFull\tAPI-created only\nPlayback control\tFull\tNone\nCatalog search\tNo\tYes\nLibrary access\tInstant\tWith tokens\nCross-platform\tNo\tYes\nAppleScript (macOS)\n\nZero setup. Works immediately with the Music app.\n\nRun via Bash:\n\nosascript -e 'tell application \"Music\" to playpause'\nosascript -e 'tell application \"Music\" to return name of current track'\n\n\nMulti-line scripts:\n\nosascript <<'EOF'\ntell application \"Music\"\n    set t to current track\n    return {name of t, artist of t}\nend tell\nEOF\n\nAvailable Operations\nCategory\tOperations\nPlayback\tplay, pause, stop, resume, next track, previous track, fast forward, rewind\nPlayer State\tplayer position, player state, sound volume, mute, shuffle enabled/mode, song repeat\nCurrent Track\tname, artist, album, duration, time, rating, loved, disliked, genre, year, track number\nLibrary\tsearch, list tracks, get track properties, set ratings\nPlaylists\tlist, create, delete, rename, add tracks, remove tracks, get tracks\nAirPlay\tlist devices, select device, current device\nTrack Properties (Read)\ntell application \"Music\"\n    set t to current track\n    -- Basic info\n    name of t           -- \"Hey Jude\"\n    artist of t         -- \"The Beatles\"\n    album of t          -- \"1 (Remastered)\"\n    album artist of t   -- \"The Beatles\"\n    composer of t       -- \"Lennon-McCartney\"\n    genre of t          -- \"Rock\"\n    year of t           -- 1968\n\n    -- Timing\n    duration of t       -- 431.0 (seconds)\n    time of t           -- \"7:11\" (formatted)\n    start of t          -- start time in seconds\n    finish of t         -- end time in seconds\n\n    -- Track info\n    track number of t   -- 21\n    track count of t    -- 27\n    disc number of t    -- 1\n    disc count of t     -- 1\n\n    -- Ratings\n    rating of t         -- 0-100 (20 per star)\n    loved of t          -- true/false\n    disliked of t       -- true/false\n\n    -- Playback\n    played count of t   -- 42\n    played date of t    -- date last played\n    skipped count of t  -- 3\n    skipped date of t   -- date last skipped\n\n    -- IDs\n    persistent ID of t  -- \"ABC123DEF456\"\n    database ID of t    -- 12345\nend tell\n\nTrack Properties (Writable)\ntell application \"Music\"\n    set t to current track\n    set rating of t to 80          -- 4 stars\n    set loved of t to true\n    set disliked of t to false\n    set name of t to \"New Name\"    -- rename track\n    set genre of t to \"Alternative\"\n    set year of t to 1995\nend tell\n\nPlayer State Properties\ntell application \"Music\"\n    player state          -- stopped, playing, paused, fast forwarding, rewinding\n    player position       -- current position in seconds (read/write)\n    sound volume          -- 0-100 (read/write)\n    mute                  -- true/false (read/write)\n    shuffle enabled       -- true/false (read/write)\n    shuffle mode          -- songs, albums, groupings\n    song repeat           -- off, one, all (read/write)\n    current track         -- track object\n    current playlist      -- playlist object\n    current stream URL    -- URL if streaming\nend tell\n\nPlayback Commands\ntell application \"Music\"\n    -- Play controls\n    play                          -- play current selection\n    pause\n    stop\n    resume\n    playpause                     -- toggle play/pause\n    next track\n    previous track\n    fast forward\n    rewind\n\n    -- Play specific content\n    play (first track of library playlist 1 whose name contains \"Hey Jude\")\n    play user playlist \"Road Trip\"\n\n    -- Settings\n    set player position to 60     -- seek to 1:00\n    set sound volume to 50        -- 0-100\n    set mute to true\n    set shuffle enabled to true\n    set song repeat to all        -- off, one, all\nend tell\n\nLibrary Queries\ntell application \"Music\"\n    -- All library tracks\n    every track of library playlist 1\n\n    -- Search by name\n    tracks of library playlist 1 whose name contains \"Beatles\"\n\n    -- Search by artist\n    tracks of library playlist 1 whose artist contains \"Beatles\"\n\n    -- Search by album\n    tracks of library playlist 1 whose album contains \"Abbey Road\"\n\n    -- Combined search\n    tracks of library playlist 1 whose name contains \"Hey\" and artist contains \"Beatles\"\n\n    -- By genre\n    tracks of library playlist 1 whose genre is \"Rock\"\n\n    -- By year\n    tracks of library playlist 1 whose year is 1969\n\n    -- By rating\n    tracks of library playlist 1 whose rating > 60  -- 3+ stars\n\n    -- Loved tracks\n    tracks of library playlist 1 whose loved is true\n\n    -- Recently played (sort by played date)\n    tracks of library playlist 1 whose played date > (current date) - 7 * days\nend tell\n\nPlaylist Operations\ntell application \"Music\"\n    -- List all playlists\n    name of every user playlist\n\n    -- Get playlist\n    user playlist \"Road Trip\"\n    first user playlist whose name contains \"Road\"\n\n    -- Create playlist\n    make new user playlist with properties {name:\"New Playlist\", description:\"My playlist\"}\n\n    -- Delete playlist\n    delete user playlist \"Old Playlist\"\n\n    -- Rename playlist\n    set name of user playlist \"Old Name\" to \"New Name\"\n\n    -- Get playlist tracks\n    every track of user playlist \"Road Trip\"\n    name of every track of user playlist \"Road Trip\"\n\n    -- Add track to playlist (must be library track)\n    set targetPlaylist to user playlist \"Road Trip\"\n    set targetTrack to first track of library playlist 1 whose name contains \"Hey Jude\"\n    duplicate targetTrack to targetPlaylist\n\n    -- Remove track from playlist\n    delete (first track of user playlist \"Road Trip\" whose name contains \"Hey Jude\")\n\n    -- Playlist properties\n    duration of user playlist \"Road Trip\"   -- total duration\n    time of user playlist \"Road Trip\"       -- formatted duration\n    count of tracks of user playlist \"Road Trip\"\nend tell\n\nAirPlay\ntell application \"Music\"\n    -- List AirPlay devices\n    name of every AirPlay device\n\n    -- Get current device\n    current AirPlay devices\n\n    -- Set output device\n    set current AirPlay devices to {AirPlay device \"Living Room\"}\n\n    -- Multiple devices\n    set current AirPlay devices to {AirPlay device \"Living Room\", AirPlay device \"Kitchen\"}\n\n    -- Device properties\n    set d to AirPlay device \"Living Room\"\n    name of d\n    kind of d           -- computer, AirPort Express, Apple TV, AirPlay device, Bluetooth device\n    active of d         -- true if playing\n    available of d      -- true if reachable\n    selected of d       -- true if in current devices\n    sound volume of d   -- 0-100\nend tell\n\nString Escaping\n\nAlways escape user input:\n\ndef escape_applescript(s):\n    return s.replace('\\\\', '\\\\\\\\').replace('\"', '\\\\\"')\n\nsafe_name = escape_applescript(user_input)\nscript = f'tell application \"Music\" to play user playlist \"{safe_name}\"'\n\nLimitations\nNo catalog access - only library content\nmacOS only - no Windows/Linux\nMusicKit API\n\nCross-platform but requires Apple Developer account ($99/year) and token setup.\n\nAuthentication\n\nRequirements:\n\nApple Developer account\nMusicKit key (.p8 file) from developer portal\nDeveloper token (JWT, 180 day max)\nUser music token (browser OAuth)\n\nGenerate developer token:\n\nimport jwt, datetime\n\nwith open('AuthKey_XXXXXXXXXX.p8') as f:\n    private_key = f.read()\n\ntoken = jwt.encode(\n    {\n        'iss': 'TEAM_ID',\n        'iat': int(datetime.datetime.now().timestamp()),\n        'exp': int((datetime.datetime.now() + datetime.timedelta(days=180)).timestamp())\n    },\n    private_key,\n    algorithm='ES256',\n    headers={'alg': 'ES256', 'kid': 'KEY_ID'}\n)\n\n\nGet user token: Browser OAuth to https://authorize.music.apple.com/woa\n\nHeaders for all requests:\n\nAuthorization: Bearer {developer_token}\nMusic-User-Token: {user_music_token}\n\n\nBase URL: https://api.music.apple.com/v1\n\nAvailable Endpoints\nCatalog (Public - dev token only)\nEndpoint\tMethod\tDescription\n/catalog/{storefront}/search\tGET\tSearch songs, albums, artists, playlists\n/catalog/{storefront}/songs/{id}\tGET\tSong details\n/catalog/{storefront}/albums/{id}\tGET\tAlbum details\n/catalog/{storefront}/albums/{id}/tracks\tGET\tAlbum tracks\n/catalog/{storefront}/artists/{id}\tGET\tArtist details\n/catalog/{storefront}/artists/{id}/albums\tGET\tArtist's albums\n/catalog/{storefront}/artists/{id}/songs\tGET\tArtist's top songs\n/catalog/{storefront}/artists/{id}/related-artists\tGET\tSimilar artists\n/catalog/{storefront}/playlists/{id}\tGET\tPlaylist details\n/catalog/{storefront}/charts\tGET\tTop charts\n/catalog/{storefront}/genres\tGET\tAll genres\n/catalog/{storefront}/search/suggestions\tGET\tSearch autocomplete\n/catalog/{storefront}/stations/{id}\tGET\tRadio station\nLibrary (Requires user token)\nEndpoint\tMethod\tDescription\n/me/library/songs\tGET\tAll library songs\n/me/library/albums\tGET\tAll library albums\n/me/library/artists\tGET\tAll library artists\n/me/library/playlists\tGET\tAll library playlists\n/me/library/playlists/{id}\tGET\tPlaylist details\n/me/library/playlists/{id}/tracks\tGET\tPlaylist tracks\n/me/library/search\tGET\tSearch library\n/me/library\tPOST\tAdd to library\n/catalog/{sf}/songs/{id}/library\tGET\tGet library ID from catalog ID\nPlaylist Management\nEndpoint\tMethod\tDescription\n/me/library/playlists\tPOST\tCreate playlist\n/me/library/playlists/{id}/tracks\tPOST\tAdd tracks to playlist\nPersonalization\nEndpoint\tMethod\tDescription\n/me/recommendations\tGET\tPersonalized recommendations\n/me/history/heavy-rotation\tGET\tFrequently played\n/me/recent/played\tGET\tRecently played\n/me/recent/added\tGET\tRecently added\nRatings\nEndpoint\tMethod\tDescription\n/me/ratings/songs/{id}\tGET\tGet song rating\n/me/ratings/songs/{id}\tPUT\tSet song rating\n/me/ratings/songs/{id}\tDELETE\tRemove rating\n/me/ratings/albums/{id}\tGET/PUT/DELETE\tAlbum ratings\n/me/ratings/playlists/{id}\tGET/PUT/DELETE\tPlaylist ratings\nStorefronts\nEndpoint\tMethod\tDescription\n/storefronts\tGET\tAll storefronts\n/storefronts/{id}\tGET\tStorefront details\n/me/storefront\tGET\tUser's storefront\nCommon Query Parameters\nParameter\tDescription\tExample\nterm\tSearch query\tterm=beatles\ntypes\tResource types\ttypes=songs,albums\nlimit\tResults per page (max 25)\tlimit=10\noffset\tPagination offset\toffset=25\ninclude\tRelated resources\tinclude=artists,albums\nextend\tAdditional attributes\textend=editorialNotes\nl\tLanguage code\tl=en-US\nSearch Example\nGET /v1/catalog/us/search?term=wonderwall&types=songs&limit=10\n\nResponse:\n{\n  \"results\": {\n    \"songs\": {\n      \"data\": [{\n        \"id\": \"1234567890\",\n        \"type\": \"songs\",\n        \"attributes\": {\n          \"name\": \"Wonderwall\",\n          \"artistName\": \"Oasis\",\n          \"albumName\": \"(What's the Story) Morning Glory?\",\n          \"durationInMillis\": 258773,\n          \"releaseDate\": \"1995-10-02\",\n          \"genreNames\": [\"Alternative\", \"Music\"]\n        }\n      }]\n    }\n  }\n}\n\nLibrary-First Workflow (Complete)\n\nAdding a catalog song to a playlist requires 4 API calls:\n\nimport requests\n\nheaders = {\n    \"Authorization\": f\"Bearer {dev_token}\",\n    \"Music-User-Token\": user_token\n}\n\n# 1. Search catalog\nr = requests.get(\n    \"https://api.music.apple.com/v1/catalog/us/search\",\n    headers=headers,\n    params={\"term\": \"Wonderwall Oasis\", \"types\": \"songs\", \"limit\": 1}\n)\ncatalog_id = r.json()['results']['songs']['data'][0]['id']\n\n# 2. Add to library\nrequests.post(\n    \"https://api.music.apple.com/v1/me/library\",\n    headers=headers,\n    params={\"ids[songs]\": catalog_id}\n)\n\n# 3. Get library ID (catalog ID → library ID)\nr = requests.get(\n    f\"https://api.music.apple.com/v1/catalog/us/songs/{catalog_id}/library\",\n    headers=headers\n)\nlibrary_id = r.json()['data'][0]['id']\n\n# 4. Add to playlist (library IDs only!)\nrequests.post(\n    f\"https://api.music.apple.com/v1/me/library/playlists/{playlist_id}/tracks\",\n    headers={**headers, \"Content-Type\": \"application/json\"},\n    json={\"data\": [{\"id\": library_id, \"type\": \"library-songs\"}]}\n)\n\nCreate Playlist\nPOST /v1/me/library/playlists\nContent-Type: application/json\n\n{\n  \"attributes\": {\n    \"name\": \"Road Trip\",\n    \"description\": \"Summer vibes\"\n  },\n  \"relationships\": {\n    \"tracks\": {\n      \"data\": []\n    }\n  }\n}\n\nRatings\n# Love a song (value: 1 = love, -1 = dislike)\nPUT /v1/me/ratings/songs/{id}\nContent-Type: application/json\n\n{\"attributes\": {\"value\": 1}}\n\nLimitations\nNo playback control - API cannot play/pause/skip\nPlaylist editing - can only modify API-created playlists\nToken management - dev tokens expire every 180 days\nRate limits - Apple enforces request limits\nCommon Mistakes\n\n❌ Using catalog IDs in playlists:\n\n# WRONG\njson={\"data\": [{\"id\": \"1234567890\", \"type\": \"songs\"}]}\n\n\nFix: Add to library first, get library ID, then add.\n\n❌ Playing catalog songs via AppleScript:\n\n# WRONG\nplay track id \"1234567890\"\n\n\nFix: Song must be in library.\n\n❌ Unescaped AppleScript strings:\n\n# WRONG\nname = \"Rock 'n Roll\"\nscript = f'tell application \"Music\" to play playlist \"{name}\"'\n\n\nFix: Escape quotes.\n\n❌ Expired tokens: Dev tokens last 180 days max. Fix: Check expiration, handle 401 errors.\n\nThe Easy Way: mcp-applemusic\n\nThe mcp-applemusic MCP server handles all this complexity automatically: AppleScript escaping, token management, library-first workflow, ID conversions.\n\nInstall:\n\ngit clone https://github.com/epheterson/mcp-applemusic.git\ncd mcp-applemusic && python3 -m venv venv && source venv/bin/activate\npip install -e .\n\n\nConfigure Claude Desktop:\n\n{\n  \"mcpServers\": {\n    \"Apple Music\": {\n      \"command\": \"/path/to/mcp-applemusic/venv/bin/python\",\n      \"args\": [\"-m\", \"applemusic_mcp\"]\n    }\n  }\n}\n\n\nOn macOS, most features work immediately. For catalog features or Windows/Linux, see the repo README.\n\nManual\tmcp-applemusic\n4 API calls to add song\tplaylist(action=\"add\", auto_search=True)\nAppleScript escaping\tAutomatic\nToken management\tAutomatic with warnings"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/epheterson/mcp-applemusic",
    "publisherUrl": "https://clawhub.ai/epheterson/mcp-applemusic",
    "owner": "epheterson",
    "version": "1.0.6",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/mcp-applemusic",
    "downloadUrl": "https://openagent3.xyz/downloads/mcp-applemusic",
    "agentUrl": "https://openagent3.xyz/skills/mcp-applemusic/agent",
    "manifestUrl": "https://openagent3.xyz/skills/mcp-applemusic/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/mcp-applemusic/agent.md"
  }
}