Spotify MCP
NPM · @NOVALUX12/SPOTIFY-MCP
Spotify Web API MCP: playback, library, playlists, search, podcasts. Not affiliated with Spotify.
Available components
Last scanned (8 hours ago)
Scores higher than 99% of npm servers
Category Entertainment and Games
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security98
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- No install/post-install scripts declared.Pass
- 32 of 104 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency100
- Source repository is publicly reachable at the declared URL. View diagnostics → Pass
- Cryptographically verified build provenance (signed, bound to NovaLux12/spotify-mcp-server). View diagnostics → Pass
- Clear OSI-approved license (MIT).Pass
- Actively maintained (last published 17 days ago).Pass
- Publishes a security disclosure policy (SECURITY.md).Pass
Schema Quality & AI Usability81
- 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Pass
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 24249 tokens (~163/item across 148 items; 131 tools + 17 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management100
- No destabilizing schema changes in the last 30 days.Pass
Tool Coverage100
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 100% of tool parameters carry a description.Pass
- Structured output schemas are declared (8% of tools); any adoption earns full credit.Pass
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- All 10 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
- An AI judge read all 133 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 1 Nov 26 +11
- Stability: fail → pass ▲ security
- 25 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 17 to 20.
- 23 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 10 to 14.
- 20 Oct 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 0 to 4.
- 19 Oct 26 0
- Stability: fail → unverified ▼ security
- Tool safety: pass → unverified ▼ security
- Capabilities: pass → unverified ▼ functional
- Tool coverage: 100 → unverified ▼ functional
- Schema quality: 100 → unverified ▼ functional
- Package version: 3.1.0 → 3.1.1 functional
- 14 Oct 26 +33
- Stability: unverified → fail ▼ security
- Injection markers: unverified → pass ▲ security
- Tool coverage: unverified → 100 ▲ functional
- Schema quality: unverified → 100 ▲ functional
- MCP protocol: unverified → pass ▲ functional
- 13 Oct 26 0
- Package version: 3.0.1 → 3.1.0 functional
- 11 Oct 26 −33
- Stability: fail → unverified ▼ security
- Tool safety: pass → unverified ▼ security
- Capabilities: pass → unverified ▼ functional
- Tool coverage: 100 → unverified ▼ functional
- Schema quality: 100 → unverified ▼ functional
- Package version: 3.0.1 → 3.1.0 functional
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 5 Nov 2026 · Analysed npm/@novalux12/spotify-mcp@3.1.1
Provenance Verified
A signed build attestation was found and verified, binding this exact artifact to the source repository it claims to come from.
| Result | Verified |
|---|---|
| Ecosystem | npm |
| Reason | Verified |
| Discovered via | Registry attestation endpoint |
| Source repo | NovaLux12/spotify-mcp-server |
| Certificate issuer | https://token.actions.githubusercontent.com |
| Certificate SAN | https://github.com/NovaLux12/spotify-mcp-server/.github/workflows/publish.yml@refs/tags/v3.1.1 |
| Rekor log index | 3316895548 |
| Predicate type | SLSA build provenance https://slsa.dev/provenance/v1 |
| Subject digest | sha512:2540a1fa4aacf0673c6ff516b98214d6eb33fdc66f31143b60e77a8126ca0dd3b342ca039af3a3f85a91545074c36de9e080ed2ea8d3986235e9e47da |
Background: How many MCP packages publish verified provenance →
Dependencies 104 packages
| Packages resolved | 104 |
|---|---|
| Stale | 32 |
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
add_to_playlist ~132
Add tracks or episodes to a playlist. Max 100 URIs per call.
| Name | Type | Req | Description |
|---|---|---|---|
| check_duplicates | boolean | – | Skip URIs that are already in the playlist instead of appending them (default: false) |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| playlist_id | string | yes | Playlist ID |
| position | integer | – | Insert at this index; appends if omitted. 0-based index into the playlist's current item order (0 = the first item). |
| uris | array | yes | Track or episode URIs to add |
No output schema declared.
No examples provided.
add_to_queue ~112
Add a track or episode to the end of the playback queue.
| Name | Type | Req | Description |
|---|---|---|---|
| device_id | string | – | Target device ID |
| dry_run | boolean | – | Preview only: describe what would change without performing it. Default false — pass true to preview. |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| uri | string | yes | Spotify track or episode URI (e.g. spotify:track:...) |
No output schema declared.
No examples provided.
apply_scene ~113
Apply a saved scene: resolve its device hint, transfer playback, then set volume/shuffle/repeat and start the saved context (in that order; missing targets are skipped)
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: describe what would change without performing it. Default false — pass true to preview. |
| name | string | yes | Scene name to apply |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
audiobook_progress ~114
Audiobook progress rollup: chapters total, played count, current chapter, percent complete. Walks every chapter page up to the shared fetch-all cap and reports scan coverage. Quota: 1 audiobook GET + chapter page GETs.
| Name | Type | Req | Description |
|---|---|---|---|
| audiobook_id | string | yes | Audiobook ID |
| market | string | – | Market, e.g. 'US' |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
backup_first ~80
Create a pre-flight library snapshot before a destructive operation. Returns snapshot file path and counts for later restore. Read-only against Spotify.
| Name | Type | Req | Description |
|---|---|---|---|
| notes | string | – | Free-text note for the snapshot |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
backup_library ~237
Snapshot your ENTIRE library to a local JSON file (read-only against Spotify): liked tracks, saved albums/shows/episodes/audiobooks, followed artists, and every playlist with its items. Walks capped at SPOTIFY_MCP_FETCH_ALL_CAP (500/category) and each playlist at SPOTIFY_MCP_PLAYLIST_ITEMS_CAP (500); the smaller wins, so a full backup of a large playlist needs both raised. Files land in SPOTIFY_MCP_BACKUP_DIR (default ~/.spotify-mcp/backups), mode 0600.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| notes | string | – | Free-text note stored in the snapshot _meta block |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| walk_cap | integer | – | Cap on items per category walked for THIS call (default: SPOTIFY_MCP_FETCH_ALL_CAP). Bounds what is READ, not rows rendered — use max_results to shrink the response. |
No output schema declared.
No examples provided.
batch_add_to_playlist ~315
Add tracks from multiple source URIs (tracks, albums, artists, playlists) to a target playlist in one call. Dedupes within the batch and optionally against the existing playlist. Batches writes in groups of 100. Dry-run previews without writing. Elicitation for 100+ tracks. Target the playlist by ID/URI/URL or by lane name.
| Name | Type | Req | Description |
|---|---|---|---|
| dedupe | boolean | – | Deduplicate (within batch and against target). Default: true |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| limit | integer | – | Source page size, 1–100. Default: 100 |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| scan_cap | integer | – | Maximum source rows to scan; bounded by SPOTIFY_MCP_FETCH_ALL_CAP |
| source_uris | array | yes | Source URIs: spotify:track:, spotify:album:, spotify:artist:, spotify:playlist: |
| target_lane | string | – | Lane name from the lane registry; provide exactly one of target_playlist_id or target_lane |
| target_playlist_id | string | – | Target playlist ID, spotify:playlist: URI, or URL; provide exactly one of target_playlist_id or target_lane |
No output schema declared.
No examples provided.
call_tool ~100
Call any REGISTERED tool by name — the dispatcher that makes a trimmed surface usable. find_tool discovers a name, inspect_tool shows its schema. Reaches only tools this session registered; for anything else use enable_toolset. Refuses to call itself.
| Name | Type | Req | Description |
|---|---|---|---|
| arguments | object | – | Arguments for that tool, exactly as its own schema declares them |
| name | string | yes | Exact registered tool name (find_tool discovers it; inspect_tool shows its schema) |
Structured output declared, but exposes no named fields.
No examples provided.
cancel_wind_down ~75
Cancel the in-process wind-down ramp, if one is running
| Name | Type | Req | Description |
|---|---|---|---|
| device_id | string | – | Only cancel if the active wind-down targets this device id |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
check_following_artists ~149
Check if the user follows specific artists — this tests FOLLOW state, not library-saved state (for that use check_in_library). Accepts IDs or spotify:artist: URIs. Rows carry {id, uri, follows}; returns a boolean per ID. Max 50.
| Name | Type | Req | Description |
|---|---|---|---|
| ids | array | yes | Artist IDs, spotify:artist: URIs, or artist URLs; CSV accepted |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
check_in_library ~248
Preferred. Accepts the widest URI mix (track, album, episode, show, audiobook, artist, user, playlist) in one request. Check whether items are saved in or followed by the user — this tests LIBRARY-SAVED/FOLLOWED state, distinct from check_following_artists which only tests artist FOLLOW state. Returns a boolean per URI via Spotify's unified endpoint. Max 40. Following an artist is no longer expressible: Spotify's February 2026 changes removed PUT/DELETE /me/following, and this endpoint's save side does not accept spotify:artist: URIs, so there is no endpoint that can follow or unfollow an artist. This read still answers the question for artist URIs.
| Name | Type | Req | Description |
|---|---|---|---|
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| uris | array | yes | Spotify URIs to check (accepts tracks, albums, episodes, shows, audiobooks, artists, users, playlists) |
No output schema declared.
No examples provided.
check_playlist_following ~137
Check if you follow 1–50 playlists. Follow state: GET /me/library/contains?uris=spotify:playlist:<id>,… (40/req, 1–2 GETs). Unreadable state reports unknown, never not-followed.
| Name | Type | Req | Description |
|---|---|---|---|
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| playlists | array | – | Canonical ordered playlists (1–50) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
clean_all_playlists ~362
Scan every playlist in your library for duplicate items (repeated URIs, and on opt-in same-song copies under different URIs when match_by=name_artist). Reports per-playlist findings by default; pass apply=true to remove them (keeps the first occurrence of each group). Bulk removals ask for one confirmation before anything is deleted. See the duplicate-matching vocabulary in SPEC section 4.
| Name | Type | Req | Description |
|---|---|---|---|
| apply | boolean | – | Deprecated alias for dry_run — prefer dry_run. false (default): report only. true: execute the cleanup across all playlists with duplicates. If both are given, dry_run wins. |
| dry_run | boolean | – | Preview only — when true, nothing is changed; when false via dry_run=false or apply=true, executes the cleanup |
| include_relinked | boolean | – | Deprecated alias for `match_by`, kept for one release: true is `name_artist` and false is `uri`. It cannot express the `name` rule, which is why `match_by` replaced it. Sending both, where they mean… |
| match_by | string | – | Which rule decides that two items are the same: `uri` (exact URI, the default), `name_artist` (case-insensitive name + credited artists, catches relinks/remasters), or `name` (case-insensitive name o… |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
clean_backup_artifacts ~326
Delete the NON-library files sharing SPOTIFY_MCP_BACKUP_DIR with your library backups: closed listening sessions (`listening-session-*.json`), playlist write pre-images (`playlistops-pre-*.json`) and legacy or migrated playback bookmarks (`playback-bookmark-*.json`). Library backups and their `.meta.json` sidecars are never touched — use `delete_backup`, and naming one here is refused. These files are local and gone for good once deleted. Preview by default; executing is confirmation-gated and refused when the client cannot prompt (SPOTIFY_MCP_CONFIRM=never bypasses). Ages are mtimes, and the default window is SPOTIFY_MCP_BACKUP_ARTIFACT_RETENTION_DAYS — separate from the library window. Unrecognised files are listed, not deleted.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: perform the read side and return a PLAN without changing anything. Default true — pass dry_run=false to commit. |
| family | string | – | Which non-library family to act on. Default all. |
| files | array | – | File names to delete instead of a sweep. Each must be inside the backup directory and match a known family; `family` and `older_than_days` then do not apply. |
| older_than_days | integer | – | Age floor in days. 0 = no age filter. Omit to use the retention window. |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
clone_playlist_cover ~122
Copy cover image from source playlist to target. Quota: GET images + PUT images (plus image fetch).
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| image_index | integer | – | Which cover image to copy. Default 0. 0-based index into the playlist's current item order (0 = the first item). |
| source_playlist_id | string | yes | Source playlist ID, URI, or URL |
| target_playlist_id | string | yes | Target playlist ID, URI, or URL |
No output schema declared.
No examples provided.
compare_playlist_covers ~167
Compare two playlists covers: URL equality, dimensions. Quota: 2 GETs.
| Name | Type | Req | Description |
|---|---|---|---|
| limit | integer | – | Source page size, 1–100. Default: 100 |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| playlist_a | string | – | Canonical A playlist; provide with playlist_b |
| playlist_b | string | – | Canonical B playlist; provide with playlist_a |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| scan_cap | integer | – | Maximum rows to read from each playlist; bounded by SPOTIFY_MCP_FETCH_ALL_CAP |
No output schema declared.
No examples provided.
copy_playlist ~248
Duplicate an existing playlist into a new playlist, preserving track order. Creates the new playlist then adds tracks in batches of 100. Dry-run reports what would be created.
| Name | Type | Req | Description |
|---|---|---|---|
| collaborative | boolean | – | Collaborative flag. Default: false |
| description | string | – | Description for the new playlist (defaults to source description) |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| limit | integer | – | Source page size, 1–100. Default: 100 |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| new_name | string | yes | Name for the new playlist |
| public | boolean | – | Public flag for the new playlist. Default: false |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| scan_cap | integer | – | Maximum source rows to scan; bounded by SPOTIFY_MCP_FETCH_ALL_CAP |
| source_playlist_id | string | yes | Source playlist ID, spotify:playlist: URI, or URL |
No output schema declared.
No examples provided.
create_playlist ~98
Create a new playlist for the current user. Set dry_run=true to preview without creating.
| Name | Type | Req | Description |
|---|---|---|---|
| collaborative | boolean | – | Whether the playlist is collaborative. Default: false |
| description | string | – | Playlist description |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| name | string | yes | Playlist name |
| public | boolean | – | Whether the playlist is public. Default: false |
No output schema declared.
No examples provided.
create_smart_playlist ~395
Create a playlist from rules over your own listening data: top tracks (by time range), recently played, or saved tracks — with optional artist-name filtering and a one-track-per-artist toggle. When source=saved_tracks the pool is the newest N saved tracks (N=scan_cap, default fetchAllCap=500) and truncation is reported. No deprecated recommendations endpoints involved. Every source has a pool ceiling (top_tracks 100, recently_played 50, saved_tracks scan_cap), reported as pool_capped with pool_cap — a capped pool is a floor, not a complete scan. dry_run previews the exact track list without creating anything.
| Name | Type | Req | Description |
|---|---|---|---|
| artist_filter | array | – | Only include tracks whose artist name contains any of these substrings (case-insensitive), e.g. ["Radiohead", "Miles Davis"]. |
| description | string | – | Playlist description |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| limit | integer | – | How many tracks the playlist should hold (after filters). Default 30. |
| name | string | yes | Playlist name |
| public | boolean | – | Whether the playlist is public |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| scan_cap | integer | – | How many saved tracks to scan when source=saved_tracks; default SPOTIFY_MCP_FETCH_ALL_CAP (500). Reports truncation when hit. |
| source | string | – | Where candidates come from: your top tracks by time_range, your recently played history, or your saved (liked) tracks. |
| time_range | string | – | ~4 weeks / ~6 months / all time. Default: medium_term |
| unique_artists | boolean | – | Keep at most one track per primary artist. Default false. |
No output schema declared.
No examples provided.
delete_backup ~179
Delete one library backup file (and its metadata sidecar) from SPOTIFY_MCP_BACKUP_DIR. Irreversible — the library rows in the file cannot be recovered from anywhere else. Destructive and confirmation-gated: dry_run defaults to true, and executing is refused when the client cannot prompt (SPOTIFY_MCP_CONFIRM=never bypasses). Paths outside the backup directory are refused.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only, and the default: pass dry_run: false to delete the snapshot. |
| file | string | yes | Backup file name (e.g. backup-2026-01-02-1.json) or a path inside the backup directory |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
delete_scene ~63
Delete a saved playback scene from the local sidecar
| Name | Type | Req | Description |
|---|---|---|---|
| name | string | yes | Scene name to delete |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
diff_playlists ~221
Compare two playlists up to the configured source cap: tracks only in A, only in B (by track ID), and tracks present in both but at different positions. Rendered rows are capped by max_results; truncation metadata reports when source walks hit scan_cap.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| limit | integer | – | Source page size, 1–100. Default: 100 |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| playlist_a | string | – | Canonical A playlist; provide with playlist_b |
| playlist_b | string | – | Canonical B playlist; provide with playlist_a |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| scan_cap | integer | – | Maximum source rows to scan; bounded by SPOTIFY_MCP_FETCH_ALL_CAP |
No output schema declared.
No examples provided.
enable_toolset ~145
Register an inactive toolset into THIS session and emit the MCP tools-list-changed notification — widens the surface without a restart. Takes the SPOTIFY_MCP_TOOLSETS vocabulary (all, core, playback, catalog, playlists, library, personalization, statsfm, taste, discovery, portability). Reverts entirely if it would breach the aggregate schema budget; refuses a module SPOTIFY_MCP_READONLY hides.
| Name | Type | Req | Description |
|---|---|---|---|
| sets | array | yes | Toolset names to activate. Known sets: core, playback, playbackintel, catalog, playlists, library, personalization, statsfm, portability, taste, discovery, resources, prompts, accounts. 'all' selects… |
Structured output declared, but exposes no named fields.
No examples provided.
expand_mood_to_queries ~176
Turn a free-text listening mood into search terms (genres, keywords, terms to avoid) for search. Uses the host model via MCP sampling when the host advertises the sampling capability; otherwise returns a built-in static map. Calls no Spotify endpoint and changes nothing. A model reply that cannot be parsed returns isError after one retry — it is never replaced by a guess.
| Name | Type | Req | Description |
|---|---|---|---|
| max_tokens | integer | – | Token ceiling for the sampling call. Default: 512. Ignored on the static-map path |
| mood | string | yes | The mood or vibe to expand, in free text (e.g. "rainy afternoon", "late night coding") |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
export_all_playlists ~163
Export every owned (or all) playlist with metadata + items to a sidecar file. Quota: GET /me/playlists + N×GET /playlists/{id}/items; capped by fetchAllCap.
| Name | Type | Req | Description |
|---|---|---|---|
| format | string | – | Output format |
| include_items | boolean | – | Include track items per playlist |
| output_dir | string | – | Local directory to write into, confined to the output root (default ~/.spotify-mcp/portability, set SPOTIFY_MCP_PORTABILITY_DIR to move it) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| scope | string | – | owned = only playlists you own |
No output schema declared.
No examples provided.
export_followed_artists ~144
Export your followed artists to a local directory as JSON or CSV. Fields: uri, name, genres. The file's exported_at is the export time, not a per-artist follow date (Spotify does not expose followed_at).
| Name | Type | Req | Description |
|---|---|---|---|
| format | string | – | Output format: json or csv |
| output_dir | string | – | Local directory to write into, confined to the output root (default ~/.spotify-mcp/portability, set SPOTIFY_MCP_PORTABILITY_DIR to move it) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
export_library_json ~176
Export your full library (saved tracks, albums, shows, episodes, audiobooks) to a local directory as JSON or CSV sidecar files. Respects SPOTIFY_MCP_FETCH_ALL_CAP per type; when capped, reports cap_reached + truncated and a prose footer ("first N of … — raise SPOTIFY_MCP_FETCH_ALL_CAP").
| Name | Type | Req | Description |
|---|---|---|---|
| format | string | – | Output format: json (single file) or csv (one file per type) |
| output_dir | string | – | Local directory to write into, confined to the output root (default ~/.spotify-mcp/portability, set SPOTIFY_MCP_PORTABILITY_DIR to move it) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
export_listening_history ~232
Export your listening history (recently played) to a JSON or CSV sidecar by walking /me/player/recently-played with before-cursor pagination. Respects SPOTIFY_MCP_FETCH_ALL_CAP; writes file 0600 and reports path + counts.
| Name | Type | Req | Description |
|---|---|---|---|
| after | string | – | Cursor: only return items played after this timestamp (milliseconds since epoch or ISO string) |
| before | string | – | Cursor: only return items played before this timestamp (milliseconds since epoch or ISO string) |
| format | string | – | Output format: json or csv |
| limit | integer | – | Alias for max_items |
| max_items | integer | – | Max history items to export (default: SPOTIFY_MCP_FETCH_ALL_CAP) |
| output_dir | string | – | Local directory to write into, confined to the output root (default ~/.spotify-mcp/portability, set SPOTIFY_MCP_PORTABILITY_DIR to move it) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
export_playlist ~237
Export a playlist's full item list as an M3U playlist file or a CSV spreadsheet. Pages every item; pass output_path to write a file (created with mode 0600) inside the configured output root, or omit it to get the document inline. CSV cells are formula-safe.
| Name | Type | Req | Description |
|---|---|---|---|
| format | string | – | Output format: m3u (playable playlist) or csv (spreadsheet) |
| include_headers | boolean | – | Emit the #EXTM3U marker / CSV header row |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| output_path | string | – | Write the full document to this local file (relative paths resolve inside the output root, default ~/.spotify-mcp/exports) instead of returning it inline |
| overwrite | boolean | – | Allow replacing an existing file at output_path (refused by default) |
| playlist_id | string | yes | Playlist ID |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
export_profile_state ~157
Export local sidecar stores (scenes, genre-tags, playback-ext, search-history, mutations, artist-watchlist) to a single schema-versioned JSON archive. artist-watchlist is ~/.spotify-mcp/artist-watchlist.json; SPOTIFY_MCP_DATA_DIR overrides that directory.
| Name | Type | Req | Description |
|---|---|---|---|
| include_history | boolean | – | Include mutation history JSONL (can be large) |
| output_dir | string | – | Directory to write the archive into, confined to the output root (default ~/.spotify-mcp/exports, set SPOTIFY_MCP_EXPORT_DIR to move it) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
filter_by_genre ~146
List URIs of your saved tracks or albums whose artists carry a given genre tag (case-insensitive tag-name match against your sidecar). Output is directly usable as create_playlist / add_to_playlist input. Read-only.
| Name | Type | Req | Description |
|---|---|---|---|
| genre | string | yes | Genre tag to match (case-insensitive, e.g. "pop") |
| kind | string | yes | Which saved collection to filter |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
find_duplicate_saved_tracks ~260
Read-only duplicate detection over your saved (liked) tracks. Exact groups require the same non-null ISRC and album id with duration within ±2s, and keep the oldest dated save. On opt-in, near-duplicate groups show same-title/artist tracks whose ISRC, release, or duration differs; these are distinct saved tracks and are review-only with no removals. Undated saves sort after dated saves. Optionally pass a playlist_id to cross-reference which group members also appear in that playlist. Never mutates your library.
| Name | Type | Req | Description |
|---|---|---|---|
| include_near_duplicates | boolean | – | Also report same-title/artist groups with a different ISRC, release, or duration. Near duplicates are review-only and never recommend removal. Default false. |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| playlist_id | string | – | Optional playlist ID to cross-reference: members of each duplicate group that also appear in this playlist are flagged, so cleanup or review decisions can account for where the track is already curat… |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
find_duplicate_tracks_across_playlists ~117
Find tracks that appear in more than one of the given playlists (cross-playlist dupes). Quota: N GETs (one per playlist).
| Name | Type | Req | Description |
|---|---|---|---|
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| playlists | array | – | Canonical ordered playlists (2–20) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
find_duplicates_in_playlist ~237
Find duplicate tracks in a playlist under one published matching rule. `match_by` selects the rule (`uri` — the same track object twice; `name_artist` — same name and credited artists, catching relinks and remasters; `name` — same title only) and the rule is echoed back as `match_by`, so a group count is never unattributable. See the duplicate-matching vocabulary in SPEC section 4.
| Name | Type | Req | Description |
|---|---|---|---|
| match_by | string | – | Which rule decides that two items are the same: `uri` (exact URI, the default), `name_artist` (case-insensitive name + credited artists, catches relinks/remasters), or `name` (case-insensitive name o… |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| playlist_id | string | yes | Playlist ID |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
find_tool ~152
Search the live tool registry by name or description substring — the fastest way to discover which of the 500+ tools handles a job. Discovery set: find_tool/inspect_tool/toolset_report are always available (also via catalog). Use this first when unsure which verb to use (e.g., playlist vs snapshot vs search).
| Name | Type | Req | Description |
|---|---|---|---|
| limit | integer | – | Max matches to return (default 25) |
| query | string | yes | Case-insensitive substring to match against tool names and descriptions |
| response_format | string | – | 'concise' (default) = prose bullet list; 'detailed' = the same prose; 'json' = the result payload as parseable JSON text, identical to structuredContent |
Structured output declared, but exposes no named fields.
No examples provided.
follow_playlist ~155
Follow a playlist — save it to your Spotify library — via PUT /me/library. Spotify removed the playlist-followers endpoints in Feb 2026; this is the only way to follow a playlist. Supports dry_run (default true); writes require confirmation unless SPOTIFY_MCP_CONFIRM=never.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only (default): pass dry_run: false to execute the follow. |
| playlist_id | string | yes | Playlist ID to follow |
| public | boolean | – | Must be true or omitted; the library endpoint has no visibility parameter. |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| Name | Type | Req | Description |
|---|---|---|---|
| cancelled | boolean | – | – |
| dry_run | boolean | – | – |
| ok | boolean | – | – |
| receipt | string|null | – | – |
No examples provided.
followed_playlists_audit ~117
Inventory of followed vs owned playlists: counts, collab, public, follower totals. Quota: GET /me/playlists paged.
| Name | Type | Req | Description |
|---|---|---|---|
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| only_followed | boolean | – | Only followed (not owned) playlists (default false) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
following_analytics ~136
Followed-artist rollups from the tag sidecar; popularity/followers unavailable (Spotify no longer returns those fields). Quota: GET /me/following.
| Name | Type | Req | Description |
|---|---|---|---|
| group_by | string | – | Rollup dimension; popularity/followers report 'unavailable' |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| top_n | integer | – | Top N groups to show |
No output schema declared.
No examples provided.
get_currently_playing ~144
Lightweight poll of what is playing right now: the item and progress only. For full session state (shuffle/repeat mode, active device, volume) use get_now_playing instead.
| Name | Type | Req | Description |
|---|---|---|---|
| additional_types | array | – | Item types to include in the response. Default: ['track', 'episode'] |
| market | string | – | ISO 3166-1 alpha-2 country code — localises item names; lowercase input is uppercased; defaults to SPOTIFY_MCP_MARKET |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
get_devices ~102
List available Spotify Connect devices. The same rows are readable as a resource with no tool call at spotify://player/devices ('?format=json' returns the raw API object).
| Name | Type | Req | Description |
|---|---|---|---|
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
get_followed_artists ~141
Get the artists the user follows. fetch_all=true walks every page; limit/after page manually.
| Name | Type | Req | Description |
|---|---|---|---|
| after | string | – | Artist ID cursor for pagination (from previous response) |
| fetch_all | boolean | – | Walk every page instead of one page (ignores limit) |
| limit | integer | – | 1–50. Default: 20 |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
get_now_playing ~148
Full device/session state for what is playing right now — item, progress, plus shuffle/repeat mode, active device, and volume. For a lightweight item+progress poll use get_currently_playing instead.
| Name | Type | Req | Description |
|---|---|---|---|
| additional_types | array | – | Item types to include in the response. Default: ['track', 'episode'] |
| market | string | – | ISO 3166-1 alpha-2 country code — localises item names; lowercase input is uppercased; defaults to SPOTIFY_MCP_MARKET |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
get_playlist ~324
Get a playlist's metadata (including cover image) and items. Use market to relink tracks and flag unavailable ones, and fields/additional_types to trim the payload — both are forwarded to the metadata read and the item pages.
| Name | Type | Req | Description |
|---|---|---|---|
| additional_types | array | – | Item types to include beyond the default 'track', e.g. ['track', 'episode'] |
| fetch_all | boolean | – | Fetch all items across pages (up to 500), continuing FROM offset. limit is the page size. Note: library tools' fetch_all ignores offset — contracts differ between modules (#110). |
| fields | string | – | Comma-separated list of response fields to keep, e.g. 'total,items(track(name,uri))' |
| id | string | – | Alias for playlist_id, resolved the same way |
| limit | integer | – | Items per page, 1–100. Default: 50 |
| market | string | – | ISO 3166-1 alpha-2 country code, e.g. 'GB'; relinks tracks to that market and flags unavailable ones |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| offset | integer | – | Pagination offset for items. Default: 0 |
| playlist_id | string | – | Playlist ID, spotify:playlist: URI, or open.spotify.com/playlist URL |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
get_playlist_added_dates ~125
List when each track was added to a playlist (added_at + added_by). Quota: GET /playlists/{id}/items paged.
| Name | Type | Req | Description |
|---|---|---|---|
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| playlist_id | string | yes | Playlist ID |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| sort | string | – | Sort by added_at (default added_asc) |
No output schema declared.
No examples provided.
get_playlist_cover ~108
Get a playlist's cover image URLs
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | – | Alias for playlist_id, matching get_playlist |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| playlist_id | string | – | Playlist ID (or pass it as 'id') |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
get_playlist_items ~307
List a playlist's items on a single page. Use market to relink tracks and flag unavailable ones, and fields/additional_types to trim the payload.
| Name | Type | Req | Description |
|---|---|---|---|
| additional_types | array | – | Item types to include beyond the default 'track', e.g. ['track', 'episode'] |
| fetch_all | boolean | – | Fetch every item across pages (up to 500), continuing FROM offset rather than restarting at 0. limit is the page size. Note: library tools' fetch_all instead ignores offset — contracts differ between… |
| fields | string | – | Comma-separated list of response fields to keep, e.g. 'total,items(track(name,uri))' |
| id | string | – | Alias for playlist_id, matching get_playlist |
| limit | integer | – | Items per page, 1–100. Default: 100 |
| market | string | – | ISO 3166-1 alpha-2 country code, e.g. 'GB'; relinks tracks to that market and flags unavailable ones |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| offset | integer | – | Pagination offset. Default: 0 |
| playlist_id | string | – | Playlist ID (or pass it as 'id') |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
get_playlist_snapshot ~106
Expose snapshot_id + item count for optimistic concurrency. Quota: 2 GETs.
| Name | Type | Req | Description |
|---|---|---|---|
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| playlist_id | string | yes | Playlist ID, spotify:playlist: URI, or URL |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
get_queue ~256
Read the playback queue. Use this for queue CONTENTS (what is playing, what is up next, how long it runs, what repeats). Use peek_next for a short lookahead. Quota: 1 read; view=enriched and include=runtime add one GET /me/player, and the context label adds one catalog read.
| Name | Type | Req | Description |
|---|---|---|---|
| include | array | – | Local analyses over the same single read, no extra request except runtime: runtime = total/avg/longest/shortest, time left on the current track, and a per-item timeline of when each row starts playin… |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| view | string | – | 'raw' (default) = the queue as returned. 'enriched' = plus the source context (playlist/album name) and total time remaining. |
No output schema declared.
No examples provided.
get_saved_albums ~179
Get albums saved in the user's library. Set fetch_all=true to retrieve the entire collection. Output is capped by max_results (default: SPOTIFY_MCP_MAX_ITEMS).
| Name | Type | Req | Description |
|---|---|---|---|
| fetch_all | boolean | – | Fetch all pages instead of one page (ignores limit/offset) |
| limit | integer | – | 1–50. Default: 20 |
| market | string | – | ISO 3166-1 alpha-2 country code, e.g. 'US' |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| offset | integer | – | Pagination offset. Default: 0 |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
get_saved_counts ~162
Library size snapshot: counts for tracks/albums/shows/episodes/audiobooks/playlists via limit=1 reads — no item paging. The total covers library saves only: playlists are owned and followed collections, so their count is reported alongside the library rows and excluded from the total. A collection that could not be read (rate limited, gated, or erroring) is reported as unreadable with its reason and left out of the total — it is never reported as 0. One attempt per collection: a rate limit is surfaced, not retried. Quota: 6 GETs.
| Name | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
How do I install the Spotify MCP server?
Spotify MCP runs locally as an npm package, launched with npx -y @novalux12/spotify-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
npm · @novalux12/spotify-mcp
claude mcp add novalux12-spotify-mcp-server -- npx -y @novalux12/spotify-mcp
What is the Spotify MCP server?
Spotify MCP is listed in the public MCP registry as io.github.NovaLux12/spotify-mcp-server. Spotify Web API MCP: playback, library, playlists, search, podcasts. Not affiliated with Spotify. This page covers its npm package (@novalux12/spotify-mcp).
Is the Spotify MCP server safe to use?
Spotify MCP scores 96 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 5 November 2026. It declares no install or post-install scripts. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the Spotify MCP server expose?
Spotify MCP exposes 131 tools: search, get_saved_tracks, get_saved_albums, get_saved_shows, get_saved_episodes, and 126 more. Their descriptions and schemas cost roughly 23,162 tokens of context every time the server is loaded.
Is the Spotify MCP server still maintained?
Spotify MCP is still listed as active in the MCP registry. We last reached this channel on 5 November 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the Spotify MCP server under?
Spotify MCP declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.