spotify-mcp
<div align="center">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/84/Spotify_icon.svg" width="64" height="64" alt="">
<h1>spotify-mcp</h1>
</div>
An MCP server that lets MCP clients build and edit Spotify playlists from a
description. "Moody 90s trip-hop for a rainy commute", "add three more like the last one",
"drop anything over five minutes", etc. This is just a personal project intended for personal use, if you find it useful, that's a side effect, and you're welcome to use it.
## How it works
Spotify deprecated `/recommendations`, `/audio-features`, `/audio-analysis` and related-artists
for every app created after 2024-11-27, they return 403 and have no replacement. So the model
itself is the recommendation engine. These seven tools give it the three things it can't do itself:
| | Tool | Purpose |
|---|---|---|
| Resolve | `search_tracks` | Turn "Massive Attack – Teardrop" into a track URI. Supports `artist:`, `year:1990-1999`, `genre:`, `album:` |
| Ground | `get_my_taste` | Your real top tracks/artists, so "music like I listen to" means something |
| Read | `list_my_playlists`, `get_playlist` | Find a playlist by name; see what's in it before editing |
| Write | `create_playlist`, `add_tracks`, `remove_tracks` | Build and edit. Batched past Spotify's 100-track-per-request cap automatically |
There's a similar project named [spotify-mcp-server](https://github.com/marcelmarais/spotify-mcp-server) by [Marcel Marais](https://github.com/marcelmarais) that exposes many more functionalities. If you want to use this tool but find that the current list of exposed functions aren't enough for what you want to do, I'd recommend looking at his MCP server instead.
## Setup
### 1. Create a Spotify app
At [developer.spotify.com/dashboard](https://developer.spotify.com/dashboard) → **Create app**.
> **Footgun 1 — the redirect URI.** Spotify **rejects `localhost`**. Register the IP literal,
> exactly: `http://127.0.0.1:8888/callback`
> **Footgun 2 — the allowlist.** New apps are in *development mode*: capped at **5 users**, and
> each one must be added under **Settings → User Management** by their Spotify account email —
> **including your own**. Miss this and every API call 403s despite a perfectly valid token.
> (Extended quota has been organizations-only since 2025-05-15 and requires 250k+ monthly actives,
> so 5 users is the practical ceiling.)
Copy the **Client ID** and **Client secret**.
### 2. Build and log in
```bash
npm install && npm run build
export SPOTIFY_CLIENT_ID=...
export SPOTIFY_CLIENT_SECRET=...
npm run login
```
`npm run login` prints an authorization URL (and tries to open your browser), catches the callback
on 127.0.0.1:8888, and writes a refresh token to `~/.config/spotify-mcp/token.json` with mode
`0600`. One time only — the server refreshes access tokens itself from then on.
Scopes requested: `playlist-modify-public`, `playlist-modify-private`, `playlist-read-private`,
`playlist-read-collaborative`, `user-top-read`. No playback scopes — this server doesn't control
playback.
### 3. Register with your MCP client
```bash
claude mcp add spotify \
--env SPOTIFY_CLIENT_ID=... \
--env SPOTIFY_CLIENT_SECRET=... \
-- node /absolute/path/to/spotify-mcp/dist/index.js
```
Or in a client config file:
```json
{
"mcpServers": {
"spotify": {
"command": "node",
"args": ["/absolute/path/to/spotify-mcp/dist/index.js"],
"env": {
"SPOTIFY_CLIENT_ID": "...",
"SPOTIFY_CLIENT_SECRET": "..."
}
}
}
}
```
Then just ask: *"Make me a 20-track playlist of moody 90s trip-hop for a rainy commute."*
## Development
```bash
npm test # node:test, no framework — chunking, pagination, token refresh, error handling
npm run build
npx @modelcontextprotocol/inspector node dist/index.js # poke the tools by hand
```
Set `SPOTIFY_MCP_TOKEN_FILE` to override the token location.
Stack: `@modelcontextprotocol/server` v2 + `zod`. Everything else is a Node built-in — no express,
no axios, no dotenv, no Spotify client library.
## Notes
- **Auth flow**: authorization code with client secret, not PKCE. Spotify doesn't rotate refresh
tokens on this flow, so there's no lose-the-write-lose-the-account failure mode. Everything stays
on loopback.
- **The playlist endpoints moved.** Separately from the 2024-11-27 cull, Spotify retired the
`/tracks` playlist surface in favour of `/items`. Unlike the cull these *do* have replacements,
and the server uses them. Everything below 403s on the left, works on the right:
`GET/POST/DELETE /playlists/{id}/tracks` → `.../items`;
`POST /users/{id}/playlists` → `POST /me/playlists`;
`item.track` on a playlist entry → `item.item`;
`playlist.tracks.total` in `/me/playlists` → `playlist.items.total`;
and the DELETE body key `{"tracks": [...]}` → `{"items": [...]}`. That last one isn't in
Spotify's changelog — it 403s as "Insufficient client scope", which sends you hunting for a
scope problem you don't have.
- **`/me/playlists` lies about being empty.** It returns a valid, empty page roughly 40% of the
time on an account that demonstrably has playlists. An empty list is a silently wrong answer
rather than an error, so `list_my_playlists` retries up to four times before believing it.
Its `items.total` count also lags behind writes by a few seconds; the playlist itself is correct.
- **Playlist visibility is not settable.** `public` is accepted at creation and on update, returns
200, and is then ignored — new playlists come back public regardless. Flip it in the Spotify
client. Nothing to fix here; the API just doesn't honour the field.
- **Not included**: playback control, playlist rename/reorder, saved-library reads. Add when wanted.
TDQS
Scored across 7 tools
Each tool targets a clearly distinct action: searching tracks, reading listening history, listing playlists, reading a playlist's contents, creating playlists, adding tracks, and removing tracks. The descriptions further reinforce boundaries, so an agent should not confuse them.
All tool names follow a consistent verb_noun snake_case pattern: search_tracks, get_my_taste, list_my_playlists, get_playlist, create_playlist, add_tracks, remove_tracks. There are no mixed conventions or vague verbs.
Seven tools is well-scoped for a Spotify playlist-management server. Each tool covers a necessary step in the core workflow without redundancy or bloat.
The playlist workflow is well covered: discover via search/taste, list/read playlists, create playlists, and add/remove tracks. Minor gaps like renaming or deleting playlists are missing, but they are not central to the apparent purpose.