# BPM Enrichment Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Add a `bpm` field (tempo from Spotify audio-features) to every track object returned by the MCP server. **Architecture:** A private `_enrich_with_bpm(sp, tracks)` helper in `spotify_client.py` batch-fetches audio features for a list of parsed track dicts (100 IDs per API call) and adds a `bpm` field in place. Each of the three track-returning functions stores the track `id` during parsing, then calls this helper before returning. **Tech Stack:** Python 3.11+, spotipy (`sp.audio_features()`), no new dependencies. --- ### Task 1: Add `_enrich_with_bpm` helper **Files:** - Modify: `spotify_client.py` — add helper after `_format_duration` - [ ] **Step 1: Add the helper function** In `spotify_client.py`, insert the following function immediately after `_format_duration` (around line 58): ```python def _enrich_with_bpm(sp: spotipy.Spotify, tracks: list[dict]) -> None: ids = [t["id"] for t in tracks] for i in range(0, len(ids), 100): chunk_ids = ids[i : i + 100] features = sp.audio_features(chunk_ids) for track, feat in zip(tracks[i : i + 100], features): track["bpm"] = round(feat["tempo"], 1) if feat else None ``` - [ ] **Step 2: Verify syntax** ```bash cd /Users/kriss/Dev/scm/scm.vilanet.fr/kriss/mcp-spotify .venv/bin/python -c "import spotify_client; print('OK')" ``` Expected: `OK` --- ### Task 2: Add `id` field and BPM enrichment to `get_playlist_tracks` **Files:** - Modify: `spotify_client.py:get_playlist_tracks` - [ ] **Step 1: Add `"id"` to the track dict and call the helper** In `get_playlist_tracks`, add `"id": track["id"],` to the `results.append({...})` block (alongside `"uri"`), and add `_enrich_with_bpm(sp, results)` just before the `return` statement: ```python results.append({ "name": track["name"], "artists": [a["name"] for a in track["artists"]], "album": track["album"]["name"], "duration_ms": track["duration_ms"], "duration": _format_duration(track["duration_ms"]), "popularity": track.get("popularity"), "id": track["id"], "uri": track["uri"], "added_at": item["added_at"], }) page += 1 response = sp.next(response) if response["next"] else None _enrich_with_bpm(sp, results) _dbg(f"get_playlist_tracks returning {len(results)} tracks") return results ``` - [ ] **Step 2: Smoke test** ```bash SPOTIPY_CLIENT_ID=d66baed203d1461a860acbc5db27e3f5 \ SPOTIPY_CLIENT_SECRET=6d9ccf95957749ffac433919b585f4ff \ SPOTIPY_REDIRECT_URI=http://127.0.0.1:8888/callback \ .venv/bin/python -c " import spotify_client, json tracks = spotify_client.get_playlist_tracks('7LhqpCM88rPqDqxTLadLmf') for t in tracks[:3]: print(t['name'], '|', t.get('bpm'), 'bpm') " 2>/dev/null ``` Expected: 3 lines like `oh baby | 128.0 bpm` --- ### Task 3: Add `id` field and BPM enrichment to `list_saved_tracks` **Files:** - Modify: `spotify_client.py:list_saved_tracks` - [ ] **Step 1: Add `"id"` to the track dict and call the helper** In `list_saved_tracks`, add `"id": track["id"],` to the `results.append({...})` block, and add `_enrich_with_bpm(sp, results)` just before the `return` statement: ```python results.append({ "name": track["name"], "artists": [a["name"] for a in track["artists"]], "album": track["album"]["name"], "duration_ms": track["duration_ms"], "duration": _format_duration(track["duration_ms"]), "popularity": track["popularity"], "id": track["id"], "uri": track["uri"], "added_at": item["added_at"], }) _enrich_with_bpm(sp, results) return results ``` - [ ] **Step 2: Smoke test** ```bash SPOTIPY_CLIENT_ID=d66baed203d1461a860acbc5db27e3f5 \ SPOTIPY_CLIENT_SECRET=6d9ccf95957749ffac433919b585f4ff \ SPOTIPY_REDIRECT_URI=http://127.0.0.1:8888/callback \ .venv/bin/python -c " import spotify_client tracks = spotify_client.list_saved_tracks(limit=3) for t in tracks: print(t['name'], '|', t.get('bpm'), 'bpm') " 2>/dev/null ``` Expected: 3 lines with bpm values. --- ### Task 4: Add `id` field and BPM enrichment to `search_tracks` **Files:** - Modify: `spotify_client.py:search_tracks` - [ ] **Step 1: Add `"id"` to the track dict and call the helper** In `search_tracks`, add `"id": track["id"],` to the `results.append({...})` block, and add `_enrich_with_bpm(sp, results)` just before the `return` statement: ```python for track in response["tracks"]["items"]: results.append({ "name": track["name"], "artists": [a["name"] for a in track["artists"]], "album": track["album"]["name"], "duration_ms": track["duration_ms"], "duration": _format_duration(track["duration_ms"]), "popularity": track["popularity"], "id": track["id"], "uri": track["uri"], }) _enrich_with_bpm(sp, results) return results ``` - [ ] **Step 2: Smoke test** ```bash SPOTIPY_CLIENT_ID=d66baed203d1461a860acbc5db27e3f5 \ SPOTIPY_CLIENT_SECRET=6d9ccf95957749ffac433919b585f4ff \ SPOTIPY_REDIRECT_URI=http://127.0.0.1:8888/callback \ .venv/bin/python -c " import spotify_client tracks = spotify_client.search_tracks('LCD Soundsystem', limit=3) for t in tracks: print(t['name'], '|', t.get('bpm'), 'bpm') " 2>/dev/null ``` Expected: 3 lines with bpm values. --- ### Task 5: Commit - [ ] **Commit all changes** ```bash git add spotify_client.py git commit -m "feat: add bpm field to all track-returning tools via audio-features endpoint" ```