# spotify-mcp MCP server
mcp-name: io.github.jamiew/spotify-mcp
MCP server connecting Claude with Spotify. This fork of [varunneal/spotify-mcp](https://github.com/varunneal/spotify-mcp) adds smart-batching tools and advanced playlist features that optimize API usage.
This server runs locally over stdio. Want a hosted MCP instead? The sister project
[spotify-mcp-cloudflare](https://github.com/jamiew/spotify-mcp-cloudflare) deploys to Cloudflare
Workers in a few minutes, with OAuth in the browser and no local install for anyone connecting.
## Features
### Core Functionality
- **Playback Control**: Start, pause, skip tracks, manage queue
- **Search & Discovery**: Find tracks, albums, artists, playlists with pagination
- **Real-time State**: Live user profile and playback status
- **Resources**: Read user, playback, track, playlist, artist, and album state by URI
### Modern MCP Protocol
- **Server instructions**: whole-surface guidance ships once per session instead of per tool
- **Structured output**: every tool returns a typed schema, not a bare dict
- **Tool annotations & icons**: read-only/destructive hints, titles, and a Spotify glyph
- **Progress notifications**: live updates while paginating large playlists
- **Elicitation**: destructive playlist removals ask for confirmation on clients that support it
### Enhanced Playlist Tools (New in this fork)
- **Smart Batch Operations**: Add/remove up to 100 tracks in single API calls
- **Large Playlist Support**: Efficiently handle playlists with 1000+ tracks using pagination
- **Advanced Playlist Management**: Create, modify details, reorder tracks, bulk track operations
- **API-Optimized Workflows**: Intelligent batching reduces API calls by 60-80%
### Tools
| Tool | Does |
| --- | --- |
| `get_me` | The signed-in user's profile |
| `search_music` | Search tracks, albums, artists or playlists, with filters and regime-aware page limits |
| `get_tracks` | Details for up to 50 tracks in one request; individual reads when batching is unavailable |
| `get_artist` | Details for up to 50 artists in one request; top tracks when you ask for a single artist |
| `get_album` | Details for up to 20 albums in one request; the track list when you ask for a single album |
| `get_playback_state` | What's playing now: track, device, progress, shuffle, repeat |
| `control_playback` | Play, pause, next, previous, seek, volume, shuffle, repeat; best-effort state confirmation |
| `list_devices` | Available Spotify Connect devices |
| `transfer_playback` | Move playback to another device |
| `get_queue` | Now playing plus the upcoming queue |
| `add_to_queue` | Queue a track |
| `list_playlists` | The user's playlists, paginated |
| `get_playlist` | Playlist metadata without its tracks; track count when available |
| `get_playlist_tracks` | Playlist tracks, paginated to any size |
| `create_playlist` | Create a playlist |
| `update_playlist_details` | Rename a playlist or change its description/visibility |
| `add_tracks_to_playlist` | Add up to 100 tracks in one call |
| `remove_tracks_from_playlist` | Remove tracks (confirms first where the client supports it) |
| `reorder_playlist` | Move a block of tracks to a new position |
| `unfollow_playlist` | Unfollow a playlist — how Spotify deletes your own |
| `get_saved_tracks` | Liked Songs, paginated |
| `save_tracks` | Like tracks |
| `remove_saved_tracks` | Unlike tracks |
| `check_saved_tracks` | Which of up to 50 tracks are already liked, without paging the library |
| `check_saved_albums` | Which of up to 20 albums are already saved |
| `check_following_artists` | Which of up to 50 artists the user follows |
| `get_top_items` | Top artists or tracks over a time range |
| `get_recently_played` | Recently played tracks with timestamps |
`tests/test_tool_metadata.py` fails if this table drifts from the code, or if a tool ships
without a title, icon and behaviour annotations.
Restricted apps cap search pages at 10 results. Advance with the returned `offset + limit`,
not the requested page size. Individual track fallbacks can require up to 50 Spotify requests.
Playlist `limit`/`offset` count positions, so a page includes any unresolved rows at those
positions. Local files and unresolved rows come back with `id: null`, local files also set
`is_local`, and they keep their position so `reorder_playlist` indices stay correct.
## Installation
Requires a Spotify **Premium** account and [`uv`](https://docs.astral.sh/uv/) >= 0.54.
### 1. Get Spotify API keys
1. Create an app at [developer.spotify.com/dashboard](https://developer.spotify.com/dashboard).
2. Add redirect URI `http://127.0.0.1:8888` — it must match exactly what you set below.
3. Copy the **Client ID** and **Client Secret**.
### 2. Add the server to your MCP client
Every client runs the same command — `uvx spotify-mcp-jamiew` — with your three Spotify env vars. No clone, no local path.
**Standard config** (works in most clients):
```json
{
"mcpServers": {
"spotify": {
"command": "uvx",
"args": ["spotify-mcp-jamiew"],
"env": {
"SPOTIFY_CLIENT_ID": "your_client_id",
"SPOTIFY_CLIENT_SECRET": "your_client_secret",
"SPOTIFY_REDIRECT_URI": "http://127.0.0.1:8888"
}
}
}
}
```
Claude Code
```bash
claude mcp add spotify \
-e SPOTIFY_CLIENT_ID=your_client_id \
-e SPOTIFY_CLIENT_SECRET=your_client_secret \
-e SPOTIFY_REDIRECT_URI=http://127.0.0.1:8888 \
-- uvx spotify-mcp-jamiew
```
Add `-s user` to install it globally across all projects. Verify with `claude mcp list`.
Claude Desktop
Add the **standard config** above to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows), then fully restart Claude Desktop.
Codex CLI
```bash
codex mcp add spotify \
--env SPOTIFY_CLIENT_ID=your_client_id \
--env SPOTIFY_CLIENT_SECRET=your_client_secret \
--env SPOTIFY_REDIRECT_URI=http://127.0.0.1:8888 \
-- uvx spotify-mcp-jamiew
```
Or add to `~/.codex/config.toml`:
```toml
[mcp_servers.spotify]
command = "uvx"
args = ["spotify-mcp-jamiew"]
[mcp_servers.spotify.env]
SPOTIFY_CLIENT_ID = "your_client_id"
SPOTIFY_CLIENT_SECRET = "your_client_secret"
SPOTIFY_REDIRECT_URI = "http://127.0.0.1:8888"
```
Hermes
Add to `~/.hermes/config.yaml`, then run `/reload-mcp` (or restart Hermes):
```yaml
mcp_servers:
spotify:
command: uvx
args: [spotify-mcp-jamiew]
env:
SPOTIFY_CLIENT_ID: your_client_id
SPOTIFY_CLIENT_SECRET: your_client_secret
SPOTIFY_REDIRECT_URI: http://127.0.0.1:8888
```
OpenClaw
Add the **standard config** above to `~/.openclaw/openclaw.json` (under `mcpServers`), then `openclaw gateway restart`.
Other clients (mcp.json)
Most MCP clients read a JSON file with an `mcpServers` block — drop the **standard config** above into it.
Using something else? Paste this to your agent:
> Install the spotify-mcp MCP server from https://github.com/jamiew/spotify-mcp — it's on PyPI as `spotify-mcp-jamiew`, run it with `uvx spotify-mcp-jamiew`, and set env vars `SPOTIFY_CLIENT_ID`, `SPOTIFY_CLIENT_SECRET`, and `SPOTIFY_REDIRECT_URI=http://127.0.0.1:8888`.
Run from source (local dev)
```bash
git clone https://github.com/jamiew/spotify-mcp.git
cd spotify-mcp
uv sync
```
Then point your client at the checkout:
```json
{
"mcpServers": {
"spotify": {
"command": "uv",
"args": ["--directory", "/path/to/spotify-mcp", "run", "spotify-mcp"],
"env": {
"SPOTIFY_CLIENT_ID": "your_client_id",
"SPOTIFY_CLIENT_SECRET": "your_client_secret",
"SPOTIFY_REDIRECT_URI": "http://127.0.0.1:8888"
}
}
}
}
```
To run the latest unpublished commit without cloning: `uvx --from git+https://github.com/jamiew/spotify-mcp.git spotify-mcp`.
On first use the server opens a browser for Spotify OAuth; the token is cached locally for later runs.
## Usage Examples
- **"Create a chill study playlist with 20 tracks"** → Search + playlist creation + bulk track addition
- **"Show me the first 50 tracks from my 'Liked Songs'"** → Pagination for large playlists
- **"Find similar artists to Radiohead and add their top tracks to my queue"** → Search + artist info + queue management
## Development
Built with the **FastMCP framework** — focused single-purpose tools spanning playback, search, queue, and playlist management, with type-safe APIs and comprehensive test coverage.
**Debug with MCP Inspector:**
```bash
npx @modelcontextprotocol/inspector uv --directory /path/to/spotify_mcp run spotify-mcp
```
## Contributors
- [@jamiew](https://github.com/jamiew)
- [@varunneal](https://github.com/varunneal) — original [varunneal/spotify-mcp](https://github.com/varunneal/spotify-mcp)
- [@jonico](https://github.com/jonico)
- [@tedeuxx](https://github.com/tedeuxx)
- [@karimStekelenburg](https://github.com/karimStekelenburg)