Files
mcp-spotify/docs/superpowers/specs/2026-05-22-spotify-mcp-design.md

131 lines
4.7 KiB
Markdown
Raw Normal View History

2026-05-25 21:34:23 +02:00
# 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.