Skip to main content
Glama
README.md
# spotify-dj MCP

<p>
  <img alt="Python 3.14" src="https://img.shields.io/badge/python-3.14-3776AB.svg?logo=python&logoColor=white">
  <img alt="MCP 2.1.1" src="https://img.shields.io/badge/mcp-2.1.1-blue.svg">
  <img alt="Tools" src="https://img.shields.io/badge/tools-31%20%2B%203%20prompts-green.svg">
  <img alt="License" src="https://img.shields.io/badge/license-MIT-yellow.svg">
</p>

A Spotify DJ MCP server: real DJ metadata plus full playlist control, in one
local server. Spotify removed `audio-features` in 2024, so pure Spotify MCPs
cannot give BPM anymore. This one rebuilds it from free sources, with
per-field provenance, and pairs it with staged playlist writes.

## What it does

- DJ metadata for any track: BPM, key plus Camelot, energy, danceability,
  valence. Multi-tier free chain (cache, ReccoBeats, Deezer, AcousticBrainz,
  TheAudioDB, optional local analysis), every value tagged with provider.
- Transition scoring 0-100 (harmonic plus octave-aware tempo plus energy),
  next-track suggestions, energy-arc setlist planning, Rekordbox-friendly
  export.
- Full Spotify control: search, playlists (list, read, create, edit, add,
  remove, reorder with snapshot rollback), playback, queue, devices, library,
  top items, history.
- Safety first: every stored-data mutation stages a preview with an
  `operation_id`, then a single-use commit revalidates before applying.
  Writes need resolved Spotify IDs, never guesses.

## Quick start

Requires Python 3.14, a Spotify account with Premium (app owner), and [`uv`](https://astral.sh/uv).

```powershell
git clone https://github.com/cikeyz/spotify-dj.git
Set-Location spotify-dj
uv venv --python 3.14
.\.venv\Scripts\Activate.ps1
uv pip install -r requirements.txt
```

Create a Spotify app (2 min, free): open the
[dashboard](https://developer.spotify.com/dashboard), Create app, add exactly
`http://127.0.0.1:8888/callback` to Redirect URIs, check Web API only, then add
yourself under User Management. Copy the Client ID, then:

```powershell
$env:SPOTIFY_DJ_HOME = "$env:LOCALAPPDATA\spotify-dj"
.\.venv\Scripts\python.exe setup\setup.py --client-id '<your-client-id>'
.\.venv\Scripts\python.exe setup\setup.py --auth-url
# open the printed URL, approve, then:
.\.venv\Scripts\python.exe setup\setup.py --auth-code '<pasted-redirect-url>'
.\.venv\Scripts\python.exe setup\tests\verify_server.py
```

Expect `RESULT: ALL CHECKS PASSED`. Full walkthrough in [`docs/SETUP.md`](docs/SETUP.md).

## MCP client config (stdio only)

```json
{
  "mcpServers": {
    "spotify-dj": {
      "command": "C:\\path\\to\\.venv\\Scripts\\python.exe",
      "args": ["C:\\path\\to\\server.py"],
      "env": { "SPOTIFY_DJ_HOME": "C:\\path\\to\\state" }
    }
  }
}
```

Launch the `.venv` Python directly, never through uv's runner. Tokens, cache, and
audit logs live in `SPOTIFY_DJ_HOME`, never in this repo.

## Tools (31) and prompts (3)

| Family | Tools |
|---|---|
| Search and library | `spotify_search`, `spotify_get_track`, `spotify_library_tracks`, `spotify_library_albums`, `spotify_top_items`, `spotify_history_recent` |
| Playlists | `spotify_playlists_list`, `spotify_playlist_get`, `spotify_playlist_create`, `spotify_playlist_edit`, `spotify_playlist_add`, `spotify_playlist_remove`, `spotify_playlist_reorder` |
| Playback | `spotify_devices_list`, `spotify_playback_get`, `spotify_play`, `spotify_pause`, `spotify_skip`, `spotify_queue` |
| DJ intelligence | `dj_audio_features`, `dj_compare_tracks`, `dj_score_transition`, `dj_suggest_next`, `dj_audit_playlist`, `dj_plan_set`, `dj_apply_plan`, `dj_export_setlist` |
| Infra | `spotify_auth_status`, `spotify_write_commit`, `spotify_write_cancel`, `spotify_write_list_staged` |

Prompts: `build-set` (crate to ordered setlist), `audit-crate` (drift and
duplicate report), `organize-playlist` (dedupe, sort, split).

Reads return cursor envelopes (`items`, `next_page_token`, `has_more`) capped
at 30KB. Mutations stage first, commit once. Details and live API discoveries
in [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).

## Optional: local analysis tier

Without it the server uses keyless catalogs only. To measure BPM and key from
audio as a last resort (proves out at ~5s per track):

```powershell
.\.venv\Scripts\python.exe -m pip install librosa
$env:SPOTIFY_DJ_LOCAL_ANALYSIS = "1"
```

## Tests

```powershell
.\.venv\Scripts\python.exe setup\tests\verify_server.py
.\.venv\Scripts\python.exe setup\tests\test_server.py
```

`verify_server.py` is offline plus static. `test_server.py` runs live against
your account with self-cleaning `SPOTIFYDJ-TEST-` playlists and must end with
`RESULT: ALL CHECKS PASSED` and zero residue.

## Layout

- `server.py`: thin shell (tools, registration, stdio entry)
- `core.py`: state, staged store, Spotify client, envelopes
- `playlists.py`, `collection.py`, `dj.py`, `prompts.py`: feature modules
- `setup/setup.py`: PKCE grant, refresh, status
- `setup/tests/`: verify plus live batteries
- `docs/`: `SETUP.md` guide, `ARCHITECTURE.md` design plus discoveries

Released under the [MIT License](LICENSE).