Files
mcp-spotify/docs/superpowers/specs/2026-05-22-spotify-mcp-design.md
2026-05-25 21:34:23 +02:00

131 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Spotify MCP Server — Design Spec
**Date:** 2026-05-22
## Overview
A Python MCP server that exposes Spotify library and playlist management as tools for Claude. Connects via stdio transport (Claude launches it as a subprocess). Authentication uses the OAuth PKCE flow via `spotipy`; tokens are cached locally and auto-refreshed.
## Project Structure
```
mcp-spotify/
├── server.py # MCP server entry point, tool registrations
├── spotify_client.py # Thin wrapper around spotipy (auth + API calls)
├── pyproject.toml # Dependencies: mcp, spotipy, python-dotenv
├── .env.example # SPOTIPY_CLIENT_ID, SPOTIPY_CLIENT_SECRET, SPOTIPY_REDIRECT_URI
└── README.md # Setup instructions (creating a Spotify Developer app, registering with Claude Code)
```
## Dependencies
- `mcp` — official MCP Python SDK (stdio server)
- `spotipy` — Spotify Web API client with built-in OAuth and token caching
- `python-dotenv` — load `.env` at startup
## MCP Tools
| Tool | Description | Parameters |
|---|---|---|
| `list_playlists` | List the authenticated user's playlists | — |
| `get_playlist_tracks` | Get all tracks in a playlist with full metadata | `playlist_id: str` |
| `list_saved_tracks` | Get the user's liked/saved tracks | `limit: int = 50` |
| `search_tracks` | Search Spotify for tracks | `query: str`, `limit: int = 10` |
| `create_playlist` | Create a new playlist | `name: str`, `description: str = ""`, `public: bool = False` |
| `add_tracks_to_playlist` | Add tracks to a playlist by URI | `playlist_id: str`, `track_uris: list[str]` |
### Track data returned by `get_playlist_tracks`
Each track entry includes:
- `name` — track title
- `artists` — list of artist names
- `album` — album name
- `duration_ms` — duration in milliseconds
- `duration` — duration formatted as `mm:ss`
- `popularity` — Spotify popularity score (0100)
- `uri` — Spotify track URI (used to add tracks to playlists)
- `added_at` — ISO timestamp of when the track was added to the playlist
All fields come from a single paginated API call (`playlist_items`); no additional requests needed.
## Authentication
### Setup (once per user)
1. Create a Spotify Developer app at [developer.spotify.com](https://developer.spotify.com)
2. Set the redirect URI to `http://localhost:8888/callback`
3. Copy `.env.example` to `.env` and fill in:
```
SPOTIPY_CLIENT_ID=<your_client_id>
SPOTIPY_CLIENT_SECRET=<your_client_secret>
SPOTIPY_REDIRECT_URI=http://localhost:8888/callback
```
### First run
`spotify_client.py` initializes `spotipy.Spotify` with `SpotifyOAuth`. spotipy opens the browser to Spotify's auth page. After login, Spotify redirects to `localhost:8888/callback`. spotipy exchanges the code for tokens and caches them to `~/.cache/spotipy/<username>.cache`.
### Subsequent runs
spotipy reads the cached token. If expired, it silently refreshes using the stored refresh token. No browser interaction needed.
### OAuth scopes
```
playlist-read-private
playlist-read-collaborative
playlist-modify-public
playlist-modify-private
user-library-read
```
## Architecture & Data Flow
```
Claude (MCP client)
│ stdio (JSON-RPC)
server.py (mcp SDK — tool definitions + request routing)
│ Python function calls
spotify_client.py (spotipy wrapper)
│ HTTPS
Spotify Web API
```
`server.py` owns all MCP concerns: tool schemas, request parsing, response formatting.
`spotify_client.py` owns all Spotify concerns: auth, API calls, pagination, data shaping.
## Error Handling
- **Startup:** If required env vars are missing, raise immediately with a descriptive message before the server accepts any connections.
- **API errors:** `spotipy` raises `SpotifyException` for all API-level errors. These are caught in `server.py` and returned as MCP error responses containing the HTTP status code and Spotify error message.
- **Token expiry:** Handled transparently by spotipy's `SpotifyOAuth` — no special handling needed.
## Claude Code Registration
Add to `~/.claude/settings.json` (or project `.claude/settings.json`):
```json
{
"mcpServers": {
"spotify": {
"command": "python",
"args": ["/path/to/mcp-spotify/server.py"],
"env": {
"SPOTIPY_CLIENT_ID": "<your_client_id>",
"SPOTIPY_CLIENT_SECRET": "<your_client_secret>",
"SPOTIPY_REDIRECT_URI": "http://localhost:8888/callback"
}
}
}
}
```
Alternatively, env vars can be loaded from `.env` by `python-dotenv` and the `env` block omitted.
## Testing
No automated tests. The server is a thin adapter over `spotipy` and the Spotify Web API; mocking the API would test the wrong thing. Verification is done by running the server and calling tools from Claude.