SpotifyMCP
# SpotifyMCP
[](https://github.com/NovaLux12/spotify-mcp-server/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/@novalux12/spotify-mcp)
[](LICENSE)

An MCP server that wraps the Spotify Web API โ lets Claude and other AI assistants control playback, search the catalog (tracks, podcasts, audiobooks), and manage your library and playlists.
600 tools. Every non-deprecated endpoint, plus extras most servers skip. [Full list โ](SPEC.md)
---
> ### ๐ค Paste this to your agent
>
> Copy the block below into Claude Code, Cursor, OpenClaw, or any coding agent โ it will set SpotifyMCP up for you.
>
> ```
> Set up the Spotify MCP server from https://github.com/NovaLux12/spotify-mcp-server.
>
> 1. Walk me through creating a Spotify app at https://developer.spotify.com/dashboard
> with redirect URI http://127.0.0.1:8888/callback, or use the Client ID I paste below.
> 2. Clone, build, and authenticate:
> git clone https://github.com/NovaLux12/spotify-mcp-server.git
> cd spotify-mcp-server && npm ci && npm run build
> SPOTIFY_CLIENT_ID=<paste-here> npm run auth
> 3. Wire it into my MCP host config and verify with the get_me tool.
>
> My Spotify Client ID: <paste here or say "help me create one">
> ```
---
## Why this one
| | |
|---|---|
| **Complete** | 600 tools โ playback, search, catalog, library, playlists, following + extras like duplicate cleanup, M3U/CSV import-export, podcast sessions, snapshot diffing, listening analytics, market checks, stats.fm taste imports, and 11 taste composite briefs, playlists, and reports. |
| **Safe** | `dry_run` previews on every write, receipts that prove what landed, human confirmation for bulk deletes, and `READONLY` to hide all writes. |
| **Honest** | No zombie tools for endpoints Spotify removed. Legacy lookups explain the 403 instead of crashing. |
| **Polished** | Paginated (up to 500), podcasts first-class, device-aware playback, `spotify_doctor` self-diagnosis, real test suite. |
## Quick start
### 1. Create a Spotify app
[Spotify Developer Dashboard](https://developer.spotify.com/dashboard) โ Create app โ add this Redirect URI exactly:
```
http://127.0.0.1:8888/callback
```
Copy the **Client ID**.
### 2. Authenticate
```bash
SPOTIFY_CLIENT_ID=your_client_id_here npx -y @novalux12/spotify-mcp@latest auth
```
Opens a browser, saves tokens to `~/.spotify-mcp/tokens.json`, auto-refreshes after.
<details><summary>Windows & headless</summary>
**Windows (Command Prompt):**
```cmd
set SPOTIFY_CLIENT_ID=your_client_id_here && npx -y @novalux12/spotify-mcp@latest auth
```
**Windows (PowerShell):**
```powershell
$env:SPOTIFY_CLIENT_ID="your_client_id_here"; npx -y @novalux12/spotify-mcp@latest auth
```
**Headless / remote host:**
```bash
SPOTIFY_HEADLESS=1 SPOTIFY_CLIENT_ID=your_client_id_here npx -y @novalux12/spotify-mcp@latest auth
# prints a URL โ open it on any machine โ paste the redirect back
```
Check: `npx -y @novalux12/spotify-mcp@latest doctor` โ exit 0 means you're good.
</details>
### 3. Add to your MCP host
```json
{
"mcpServers": {
"spotify": {
"command": "npx",
"args": ["-y", "@novalux12/spotify-mcp@latest"],
"env": { "SPOTIFY_CLIENT_ID": "your_client_id_here" }
}
}
}
```
Restart the host. A hammer icon in the chat input means it's connected.
<details><summary>Claude Code ยท OpenClaw ยท other hosts</summary>
**Claude Code (no JSON editing):**
```bash
claude mcp add spotify -- npx -y @novalux12/spotify-mcp@latest
export SPOTIFY_CLIENT_ID=your_client_id_here
```
**OpenClaw** โ `~/.openclaw/openclaw.json` โ `mcp.servers`:
```json
"spotify": {
"command": "node",
"args": ["/path/to/spotify-mcp-server/dist/index.js"],
"cwd": "/path/to/spotify-mcp-server",
"env": { "SPOTIFY_CLIENT_ID": "your_client_id_here" }
}
```
Any spec-compliant host works โ same `command`/`args`/`env` shape under `mcpServers` or `servers`. If the host can't pass env vars, authenticate once beforehand; the token cache persists.
</details>
## What you can ask
- "What are my top tracks this month?"
- "Make a late-night driving playlist"
- "Add Blinding Lights to my workout playlist"
- "What podcasts have new episodes?"
- "Clean duplicates across all my playlists"
- "What does my taste look like? Build a playlist from it"
- "Do my stats.fm lifetime genres match what I've played this month?"
## Configuration
All via env vars โ no config file. Only `SPOTIFY_CLIENT_ID` is required.
| Variable | Example | Purpose |
|---|---|---|
| `SPOTIFY_MCP_TOOLSETS` | `playback,catalog` | Trim by group for hosts that cap tool counts |
| `SPOTIFY_MCP_READONLY` | `1` | Hide every write tool |
| `SPOTIFY_MCP_HISTORY` | `1` | Log mutations to JSONL for undo |
Full reference: [docs/configuration.md](docs/configuration.md)
`spotify_doctor` (CLI + in-server tool) diagnoses token state, scope gaps, Premium gating, and rate-limit cooldowns without extra setup.
## Docs
- [SPEC.md](SPEC.md) โ every tool, resource & prompt
- [ARCHITECTURE.md](ARCHITECTURE.md) โ how it's built
- [docs/configuration.md](docs/configuration.md) โ all env vars
- [docs/statsfm.md](docs/statsfm.md) โ stats.fm second source: setup, tool cheat sheet, gotchas
- [docs/cookbook.md](docs/cookbook.md) โ ten copy-paste agent recipes
- [docs/taste.md](docs/taste.md) โ anonymized taste showcase driving a playlist
- [docs/faq.md](docs/faq.md) โ auth, Premium, 403s, headless, tokens
- [CONTRIBUTING.md](CONTRIBUTING.md) โ dev setup & conventions
- [CHANGELOG.md](CHANGELOG.md) โ release history
## Requirements
- **Premium** for playback control (play/pause/skip/seek/volume/queue). Free accounts can still use search, library & playlists.
- Node 22.9+, Spotify app in dev mode (5 users until extended quota).
- Audiobooks gated by Spotify to US/UK/CA/IE/NZ/AU.
- A subset of endpoints is **registration-gated** โ 403 on current app registrations regardless of scopes or Premium. See [Registration-gated endpoints](#registration-gated-endpoints).
### Registration-gated endpoints
Some Web API endpoints are denied **at the app-registration level**: on current Spotify app registrations they return `403 Forbidden` no matter which OAuth scopes you grant or whether the account is Premium. This is Spotify-side gating, not a misconfiguration on your end. Verified by live probe on 2026-08-27 ([#329](https://github.com/NovaLux12/spotify-mcp-server/issues/329)):
| Response | Endpoints |
|---|---|
| `403 Forbidden` | `/browse/new-releases`, `/browse/categories` (and `/browse/categories/{id}/playlists`), `/markets`, `/artists/{id}/top-tracks`, `/users/{id}` (and `/users/{id}/playlists`), every documented `/me/{type}/contains` check (tracks, albums, shows, episodes, audiobooks, following), `/playlists/{id}/followers/contains` |
| `404 Not Found` | `/recommendations`, `/recommendations/available-genre-seeds` |
| `410 Gone` | `/me/apps`, `/me/chapters` |
Notes:
- Tools wrapping a gated endpoint are **not hidden** โ they still work on legacy app registrations where Spotify granted the endpoint. On a newer registration you'll get the server's plain-English 403 explanation instead of a crash.
- The undocumented `/me/library/contains` check is *not* gated (it returned 200 on the same probe) and powers the duplicate-cleanup tooling.
- Legacy lookups the server already explains gracefully (audio-features, audio-analysis, related-artists, featured-playlists) also probe as 403; their tools say so in the error message.
<details><summary>Troubleshooting</summary>
- **"Not authenticated"** โ re-run `auth`; check `~/.spotify-mcp/tokens.json` exists and the redirect URI matches exactly (no trailing slash).
- **Auth loop / S256 error** โ open a private window, log into spotify.com first, then retry the auth URL there.
- **Port in use (8888)** โ free the port, set `SPOTIFY_REDIRECT_URI` to another port, or use `SPOTIFY_HEADLESS=1`.
- **"Premium required"** on playback โ expected on Free accounts; no workaround.
- **`Forbidden` on lookup tools** (categories, markets, top-tracks, user profiles, library `contains` checks) โ these endpoints are registration-gated by Spotify; see [Registration-gated endpoints](#registration-gated-endpoints).
- **Still stuck?** `npx -y @novalux12/spotify-mcp@latest doctor` or ask your agent to run the [spotify-mcp-doctor skill](skills/spotify-mcp-doctor/SKILL.md).
</details>
## Development
```bash
git clone https://github.com/NovaLux12/spotify-mcp-server.git && cd spotify-mcp-server
npm ci && npm run build
cp .env.example .env # add your Client ID
npm run auth # one-time login
npm run dev # run from source
npm test # unit + MCP smoke tests
```
---
*Not affiliated with Spotify. Use per the [Spotify Developer Terms](https://developer.spotify.com/terms).*
[MIT](LICENSE) ยฉ Carme99 and NovaLux12 contributors ยท Acknowledges [calebWei/SpotifyMCP](https://github.com/calebWei/SpotifyMCP) and [varunneal/spotify-mcp](https://github.com/varunneal/spotify-mcp).
TDQS
Scored across 608 tools
With 608 tools, the surface is saturated with near-duplicates: get_now_playing vs get_currently_playing vs get_playback_snapshot, listening_streaks vs listening_streak_report, playlist_intersect vs playlist_intersection, b_sides_finder vs b_sides_detector, plus roughly 20 URI-parsing utilities and 30+ snapshot tools. Explicit legacy aliases help at the margins, but an agent cannot reliably disambiguate such overlapping clusters.
Names mix verb_noun (get_track, create_playlist), noun_verb (playlist_sort, playlist_intersect), bare verbs (play, pause, mute, seek), and there is no consistent preview/commit pattern (sort_playlist_plan vs playlist_sort vs sort_playlist_apply; reverse_playlist_plan vs playlist_reverse). Arbitrary aliasing like get_show_episodes/list_show_episodes and statsfm_taste_profile/taste_profile adds further chaos.
608 tools is an extreme count for any MCP server, far beyond the 50+ threshold for a failing score. The scope could be served by a small fraction of these tools; dozens of report tools, snapshot variants, and URI helpers are redundant.
The server covers the full Spotify API surface plus stats.fm and local sidecar features: playback, library, playlists, search, podcasts, audiobooks, analytics, snapshots, and mutation tracking. Missing features are mostly removed API endpoints (artist top tracks, user profile) with explicit disclosures, and genuine gaps (queue clear, insert-next) have documented workarounds.