Apple Music MCP
Provides tools for interacting with an Apple Music account, including reading listening history, heavy rotation, recommendations, Replay summaries, library playlists, searching the catalog, and safely creating playlists and appending tracks with duplicate checks.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
Apple Music MCP
A self-hosted Model Context Protocol server that lets compatible AI assistants use your Apple Music account and query a listening-history database you control.
Run it on Cloudflare Workers with D1 and KV. It does not need a computer left on, a Cloudflare Tunnel, or an AI provider API key. Each installation connects one Apple Music account; every authorized client gets the same 14 tools. You supply your own Apple credentials and music authorization.
Features
Library and discovery: search the catalog, browse playlists and their tracks, and get personalized recommendations and heavy rotation.
Official Apple Music Replay: request the latest eligible year's summary and top content directly from Apple.
Playlist creation and appending: resolve up to 100 catalog IDs or song name/artist pairs in one request, preview matches, reject ambiguity, and skip duplicates.
Observed listening history: collect Apple's current recently played window every two minutes, preserve events and distinct raw payload versions in D1, and query history with pagination.
Timeframe analytics: summaries and rankings for tracks, artists, albums, and genres; rolling, calendar, and exact custom ranges.
Remote client options: Streamable HTTP with a bearer key, MCP OAuth, or a private capability URL that needs no extra password.
Reliable collection: shared leases, transactional snapshot updates, empty-window protection, overlap diagnostics, and persistent Apple rate-limit cooldowns.
Efficient operation: daily indexed maintenance, cached developer tokens and catalog searches, bounded private catalog RPC, and lazy MCP initialization.
Optional ChatGPT Sites compatibility: keep an owner-private Sites plugin as a thin proxy to the Cloudflare backend, or use the separate Sites deployment mode.
Playlist changes are limited to creating an empty playlist and appending tracks. Removal, replacement, reordering, deletion, artwork changes, and metadata editing are not exposed.
Related MCP server: Apple Music MCP Server
How it works
flowchart LR
Client[Compatible MCP client] -->|Streamable HTTP| Worker[Cloudflare Worker]
Setup[Protected browser setup] -->|MusicKit authorization| Worker
Cron[Two-minute Cron Trigger] --> Worker
Site[Optional private Sites proxy] --> Worker
Worker -->|Apple developer and music user tokens| Apple[Apple Music API]
Worker --> D1[Ledger, encrypted token, cache, diagnostics]
Worker --> KV[OAuth registrations and grants]
Worker -->|Private RPC| Resolver[Same Worker: CatalogResolver]The browser setup flow obtains a Music User Token. The server encrypts it with AES-GCM before storing it in D1, and signs short-lived ES256 developer tokens with your Apple private key. The collector compares successive recently played windows and commits new events and the new snapshot together.
Observed history is approximate. Apple returns at most 30 recent tracks and no exact play timestamps. Collection cannot backfill old activity or guarantee complete coverage. Use Replay for Apple's official rankings; account-wide plays/minutes are available only when Apple explicitly supplies them. See history and operations.
Requirements
Node.js 22.18+ and npm.
A Cloudflare account with Workers, D1, and KV access.
An Apple Developer Program account able to create Media IDs and Media Services keys.
An active Apple Music subscription for the account being connected.
An AI client with remote Streamable HTTP MCP support. Merely accepting web links does not make a client MCP-capable.
Cloudflare's free allowances can support personal use, but request, CPU, database, KV, and storage limits still apply. Apple subscriptions and any AI-client charges are separate. This project does not enable a paid Cloudflare plan. See cost and maintenance.
Part 1: Create Apple credentials
In Apple Certificates, Identifiers & Profiles:
Create a Media ID, give it your own description and reverse-domain identifier, and enable its MusicKit/Apple Music service.
Create a Media Services private key and associate it with that Media ID.
Download the
.p8file while Apple makes it available, and record the key ID and developer team ID.
Keep the complete private key, including its PEM header and footer. Never commit it. Refer to Apple's Media ID/key instructions if the portal's labels change.
Part 2: Deploy to Cloudflare
1. Install
Clone this repository using its GitHub Code button, then run:
cd apple-music-mcp
npm ci
cp wrangler.example.toml wrangler.toml
npx wrangler login
npx wrangler whoamiwrangler.toml is your private deployment configuration and is ignored by Git. Choose your own Worker name if necessary. If you change its top-level name, change services[0].service to the same value: the CATALOG_RESOLVER binding points to the same Worker's CatalogResolver entrypoint. Keep that binding for large song-resolution batches.
2. Create storage
npx wrangler kv namespace create OAUTH_KV
npx wrangler d1 create apple-music-mcpCopy the returned KV ID and database ID into the matching placeholders in wrangler.toml. If you choose a different database name, update database_name and the database arguments in the following commands. These are your resources; the repository includes no production account IDs.
3. Set secrets
Generate four independent random values using a password manager or run openssl rand -base64 32 four times. Store them as:
Secret | Purpose |
| Shared all-tools bearer key; also the default source of the private capability URL. Use at least 32 random characters. |
| Passcode for the protected Apple Music setup page. |
| Passcode for approving MCP OAuth clients. |
| Encrypts the stored Music User Token. Retain it with private backups. |
| Your developer team ID. |
| Your Media Services key ID. |
| Complete contents of your |
Enter values interactively, rather than putting them in command arguments or shell history:
npx wrangler secret put MCP_API_KEY
npx wrangler secret put SETUP_TOKEN
npx wrangler secret put OAUTH_CONSENT_TOKEN
npx wrangler secret put TOKEN_ENCRYPTION_KEY
npx wrangler secret put APPLE_TEAM_ID
npx wrangler secret put APPLE_KEY_ID
npx wrangler secret put APPLE_PRIVATE_KEYPOKE_MCP_API_KEY is an optional legacy override for deriving the capability URL. Its name does not limit it to Poke. New installations can omit it and use MCP_API_KEY. Setup and encryption secrets serve different purposes; they are not credentials you give an AI client.
4. Apply migrations, validate, deploy
npx wrangler d1 migrations list apple-music-mcp --remote
npx wrangler d1 migrations apply apple-music-mcp --remote
npm test
npm run typecheck
npx wrangler deploy --dry-run
npm run deployApply all migrations before running the new code. They create the encrypted-token/configuration tables, listening ledger and payload versions, diagnostic/audit tables, fenced collector controls, maintenance indexes, migration archives, and catalog cache.
The example config enables one */2 * * * * Cron Trigger and a private catalog resolver binding. No separate helper Worker or Tunnel is needed. Keep SITE_COLLECTOR_URL unset for standalone Cloudflare operation.
5. Authorize Apple Music
Open your deployed Worker's clean setup URL:
https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev/setupEnter SETUP_TOKEN, select Authorize Apple Music, complete Apple's prompt, and wait for Apple Music connected. The passcode travels in a POST body and establishes a ten-minute HttpOnly setup session; do not add it to the URL.
The Music User Token may eventually expire. Apple supplies no refresh-token flow for it; return to /setup and authorize again when necessary, retaining the existing history and encryption key.
6. Connect your AI client
All three options grant the same 14 tools against the one connected account. There are no separate read-only roles.
Option | MCP URL | Authentication |
Shared bearer |
|
|
Private capability URL |
| None beyond possession of the URL. |
MCP OAuth |
| Client's OAuth flow; approve with |
Bearer configuration (adapt field names to your client):
{
"name": "Apple Music",
"url": "https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.dev/mcp",
"transport": "streamable-http",
"headers": { "Authorization": "Bearer <MCP_API_KEY>" }
}Private URL configuration: generate the connection locally from your existing key:
node scripts/mcp-connection.mjs https://YOUR_WORKER.YOUR_SUBDOMAIN.workers.devThe helper asks for the key without echoing it and saves private settings in ignored work/mcp-connection.json. Use POKE_MCP_API_KEY if your deployment sets that override; otherwise use MCP_API_KEY. The capability token is the lowercase SHA-256 digest of that key, not the raw key and not a new independent credential. The same capability token can instead be supplied as Authorization: Bearer <CAPABILITY_TOKEN> at /mcp.
Treat the entire capability URL as a credential. The example configuration disables invocation URL logging; keep it disabled when using this mode. Credential vaults that substitute secrets only in headers should use the bearer option rather than embedding a vault placeholder in the URL. Some clients automatically select OAuth even for a capability URL; use their explicit API-key/bearer mode in that case.
OAuth configuration: add the /mcp URL to a client implementing MCP OAuth discovery. Check the client name on the browser consent screen, enter OAUTH_CONSENT_TOKEN, and return to the client. The server uses S256 PKCE, one-hour access tokens, 30-day refresh tokens, and the apple_music scope.
Examples for Poke, custom connector clients, and Sites compatibility explain the different connection flows. A plain browser GET to /mcp is not an MCP test: this is a stateless POST transport, and GET/DELETE are not used for sessions or streams.
7. Verify
Discover tools and confirm that the client sees 14. Call apple_music_status; it should report credentials configured and connected. Call apple_music_analytics_status and observe at least two actual scheduled successes about two minutes apart. Check the latest successful poll and any cooldown; a configured cron or manual refresh alone does not establish automatic collection.
For playlist verification, start with dryRun: true. A real create or append changes the library, so only request one when you intend that change. Never automatically repeat an uncertain write.
Tools
Tool | Purpose / main inputs |
| Connection, credentials, token update time, storefront. |
| Bounded observed history: timeframe, |
| Apple's heavy rotation; |
| Personalized recommendation groups; |
| Official latest eligible year rankings, catalog-enriched songs, and explicit totals availability. |
| Library playlists and editability; |
| Playlist tracks: |
| Catalog search: |
| Create an empty playlist: |
| Resolve/preview/deduplicate/append: |
| Refresh the complete available recent window, up to 30 tracks. |
| Ledger coverage, recent attempts, overlap/failure diagnostics, cooldown. |
| Observed totals and top categories for a timeframe. |
| Rank tracks/artists/albums/genres: timeframe, |
Playlist example
After obtaining an editable playlist's ID, preview an entire batch in one call:
{
"playlistId": "<YOUR_LIBRARY_PLAYLIST_ID>",
"tracks": [
{ "name": "<SONG_TITLE>", "artist": "<ARTIST_NAME>" },
{ "id": "<APPLE_CATALOG_SONG_ID>" }
],
"dryRun": true,
"allowPartial": false
}Inspect unresolved and ambiguous matches before changing dryRun to false. With allowPartial=false, any unresolved or ambiguous item blocks the entire append. Duplicates already in the playlist or repeated in the request are skipped. POST writes are never retried automatically; an uncertain outcome returns verification information and doNotRetry when appropriate. A successful Apple response can still precede visible propagation to library reads.
Timeframes
Presets: today, 24h, 7d, 30d, 90d, ytd, last_year, all_time.
{ "preset": "30d", "limit": 20, "refreshFirst": false }Or provide an inclusive start and optional exclusive end, with explicit UTC/offset timestamps and no preset:
{
"start": "2026-01-01T00:00:00Z",
"end": "2026-02-01T00:00:00Z",
"timeZone": "Etc/UTC",
"limit": 50
}Calendar presets default to America/Denver; pass your own IANA timeZone as needed. Reuse a returned timeframe.asOf as the optional asOf input on other preset queries to keep their bounds aligned. Use exact start/end without asOf for custom ranges. The ledger remains live, so this does not freeze the database. For pagination, keep the same timeframe and use the returned nextCursor while hasMore=true. Custom ranges, SQL aggregation, and estimated timestamps all refer to the observed ledger, not complete Apple playback records.
Replay and ranking details
Replay preserves Apple’s ranking order and fills missing song names, artists, and links through bounded catalog-ID lookups. songMetadata and per-song metadataStatus disclose missing/unavailable metadata without inventing a match. totalsAvailable=false means the response contains no account-wide listening totals; an album’s catalog track count is not a play count. rankingInfo reports the different returned list lengths, and coverage.periodState identifies current-year rankings that can change.
Observed rankings expose name consistently while retaining the legacy key. Album IDs and links use valid recorded Apple Music album URLs or catalog lookups from archived song catalog IDs, with album/artist checks; unavailable or mismatched references are not fabricated. Heavy Rotation preserves Apple’s resource order and can contain playlists or albums without ranks or play counts; use observed top stats for measured rankings.
Local development
npm ci
cp .dev.vars.example .dev.vars
# Fill .dev.vars with your own local secrets.
npm run db:migrate:local
npm run dev:localThe checked-in wrangler.local.toml uses simulated D1/KV and a resolver binding to the local Worker. Open http://127.0.0.1:8787/setup, authorize Apple Music, and connect an MCP client to /mcp with the local bearer key. Keep the server bound locally.
Wrangler does not fire Cron Triggers automatically during local development. For one collection pass while it is running:
curl -fsS 'http://127.0.0.1:8787/__scheduled?cron=%2A%2F2+%2A+%2A+%2A+%2A'Continuous local collection needs a host scheduler and a running computer. Local history and authorization persist under .wrangler/state; back them up before resetting local state. npm run build builds the Sites bundle, whereas npm run deploy deploys the Cloudflare Worker.
Updates, operations, and privacy
Apply pending D1 migrations before deploying new code. Preserve existing database/KV bindings and the encryption key. Keep exactly one authoritative collector during any migration; transferring the latest data is required before rolling back to an older database.
This repository contains reusable source, placeholder configuration, schema migrations, and synthetic tests. Do not publish live capability URLs, keys, Apple authorization, listening data, database dumps, logs, screenshots, owner identities, production configuration, or private migration reports. The ignore rules exclude the usual local locations; review the staged tree and Git history before sharing. Ignoring a file does not remove a previously committed copy.
Project layout
Path | Contents |
| Cloudflare authentication/routes, Cron, private |
| 14 tool schemas/handlers and bounded stateless HTTP transport. |
| Apple API, token/catalog caching, matching batches, retries/timeouts. |
| Ledger collection, snapshots, history pages, SQL analytics. |
| Fenced leases, persisted cooldowns, daily maintenance gate. |
| Protected authorization and encrypted token storage. |
| Shared capability URL and equivalent bearer authentication. |
| Optional Sites entrypoint, migration/service routes, timer, proxy. |
| Ordered Cloudflare D1 migrations. |
| Separate Sites schema and generated migrations. |
| Private local connection-settings helper. |
| Synthetic protocol, history, concurrency, matching, transport, and safety tests. |
| Placeholder setup templates. |
References
This server cannot be deployed
Maintenance
Related MCP Connectors
Your Apple Health data, food diary and lifts, for ChatGPT, Claude and Gemini. Approved on iPhone.
Personal context and preferences for AI via OAuth-approved profile sections and taste data.
Read-only access to your own bank, card and brokerage accounts for Claude, ChatGPT and other AI agents: balances, transactions, spending, subscriptions, cashflow and investment holdings. It can never move money.
Every email and calendar account you connect, for AI agents, with permissions and approvals.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables AI assistants to control Spotify playback, manage playlists, search music, and access listening history. Requires Spotify Premium and uses secure OAuth 2.0 with PKCE authentication.1364 npmMIT
- FlicenseNot gradedqualityDmaintenanceIntegrates Apple Music with MCP clients to search the global catalog, manage personal playlists, and access library data. It enables users to perform actions like creating playlists, adding tracks, and viewing recommendations through natural language commands.1-
- AlicenseNot gradedqualityDmaintenanceConnects Claude Code to Apple Music using only your Apple ID, without needing a developer account. Enables access to recently played, playlists, search, recommendations, and playlist creation.8 npmMIT
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to control Spotify playback, search music, manage playlists and library, and access user listening insights via the Spotify Web API.-