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

4.7 KiB
Raw Permalink Blame History

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
  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):

{
  "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.