Spotify MCP
NPM · @NOVALUX12/SPOTIFY-MCP
Spotify Web API MCP: playback, library, playlists, search, podcasts. Not affiliated with Spotify.
Available components
Last scanned (9 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
Checks we ran (16)
- Malware scan
- Known CVEs
- Install scripts
- Dependency health
- Source repository
- Provenance
- License
- Maintenance
- Security disclosure
- Schema quality
- Stability
- Tool coverage
- Injection markers
- Destructive annotations
- Judged manipulation
- MCP protocol
Does not apply to this package (2)
- Endpoint SecurityScored on hosted endpoints only. A package has no live endpoint of its own for us to probe.
- Transport & ReachabilityScored on hosted endpoints only. A package has no live endpoint of its own for us to probe.
The score does not measure everything. What the score does not measure →
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 →
get_saved_episodes ~180
Get podcast episodes 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_shows ~156
Get podcast shows 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 |
| 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_tracks ~180
Get tracks saved in the user's Liked Songs. 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_user_playlists ~155
List the current user's playlists
| Name | Type | Req | Description |
|---|---|---|---|
| fetch_all | boolean | – | Fetch every playlist (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 modules… |
| limit | integer | – | 1–50. Default: 20 |
| 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_user_playlists_by_id ~169
List another Spotify user's public playlists (paginated). Removed by Spotify's February 2026 Web API changes — unavailable for newer app registrations. Output is capped by max_results (default: SPOTIFY_MCP_MAX_ITEMS).
| Name | Type | Req | Description |
|---|---|---|---|
| limit | integer | – | 1–50. Default: 20 |
| 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 |
| user_id | string | yes | Spotify user ID, spotify:user: URI, or open.spotify.com/user URL |
No output schema declared.
No examples provided.
get_user_profile ~115
Get any Spotify user's public profile (display name, profile image). Removed by Spotify's February 2026 Web API changes — unavailable for newer app registrations. The `followers` field was separately removed from user profiles, so no follower count is reported
| Name | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| user_id | string | yes | Spotify user ID, spotify:user: URI, or open.spotify.com/user URL |
No output schema declared.
No examples provided.
grow_playlist ~214
Propose tracks to grow one of your playlists using ONLY your own listening data (no recommendations): finds tracks appearing in >=2 of your OTHER playlists, boosts ones sharing an artist with the target playlist, excludes tracks already in it (and optionally your saved library), and returns top candidates with evidence. Read-only: review the proposals, then call add_to_playlist with the URIs you want.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| exclude_saved | boolean | – | Skip tracks already in your saved library (default true) |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| playlist_id | string | yes | Target playlist ID to grow |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| size | integer | – | How many candidates to propose (default 20) |
No output schema declared.
No examples provided.
history_search ~83
Search portability, backup and mutation-history stores; hits name their source. Quota: local only (no API).
| Name | Type | Req | Description |
|---|---|---|---|
| query | string | – | Substring to match |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| scope | string | – | Scope |
No output schema declared.
No examples provided.
import_from_sidecar ~315
Additive restore from a library.json sidecar written by export_library_json: re-adds every missing saved item across all five collections (tracks, albums, shows, episodes, audiobooks) through the unified PUT /me/library endpoint, skipping items the library already holds. Rows whose uri is not a canonical spotify:<kind>:<22-char id> URI are counted as invalid and never sent. Collections the file does not carry are named in absent_keys. The exporter's own truncated / cap_reached flags are surfaced as sidecar_truncated + truncated_collections: a capped sidecar restores only the rows it holds and says so, and a file with no flag reports completeness as UNKNOWN rather than complete. The prompt and the result both state the sidecar path, the date the file itself declares (exported_at, or the named reason it declares none — never the mtime), the row count, the one use being made of it, and whether a human confirmed that use (see consent_note). dry_run=true by default. Quota: local read + contains-check + chunked writes when dry_run=false.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only, making no API calls at all. Writes happen only when explicitly set to false. |
| input_path | string | – | Path to sidecar JSON (default: <portability>/library.json) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
import_playlist ~239
Parse an M3U or CSV document (the inverse of export_playlist) and append its Spotify URIs to a target playlist. Pass the document inline via content, or read it from input_path (a regular file inside the configured read roots). URIs already in the playlist are skipped, so a re-run adds nothing. Adds in batches of 100. Use dry_run=true to preview without writing. Result records the document source and the use made of it (consent_note); under 100 new URIs nothing is gated.
| Name | Type | Req | Description |
|---|---|---|---|
| content | string | – | The M3U or CSV document body, passed inline |
| dry_run | boolean | – | Parse and report what would be added without touching the playlist |
| format | string | – | Document format; auto-detected when omitted |
| input_path | string | – | Read the document from this local file instead of content |
| playlist_id | string | yes | Target playlist ID, spotify:playlist: URI, or share URL |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
import_profile_state ~201
Restore local sidecar stores from a profile-state archive. merge unions each store on its own keys and de-duplicates search_history by entry id; overwrite replaces each store, keeping a 0600 <file>.bak of what it replaced. The mutation ledger (stores.mutations_history) is export-only: it is never appended to or replaced, and an archive carrying it is reported as skipped. dry_run reports the per-store plan and writes nothing. Refuses newer schema versions.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| input_path | string | yes | Path to the profile-state archive JSON file |
| mode | string | – | merge = union on each store's own keys; overwrite = replace, keeping a .bak |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
inspect_tool ~79
Show one tool's full description and input schema before calling it
| Name | Type | Req | Description |
|---|---|---|---|
| response_format | string | – | 'concise' (default) = prose bullet list; 'detailed' = the same prose; 'json' = the result payload as parseable JSON text, identical to structuredContent |
| tool_name | string | yes | Exact registered tool name |
Structured output declared, but exposes no named fields.
No examples provided.
library_genre_report ~132
Aggregate your saved library by user-declared genre tags. Scans all saved tracks and albums, joins each item's artists against your tag sidecar (see tag_management), and reports per-genre track/album counts plus the contributing artists. Genres are unavailable from Spotify itself, so only artists you have tagged appear here.
| 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.
library_hygiene ~147
Read-only album hygiene over your liked tracks: flags near-complete albums worth saving and lone singles with nothing else liked from their artist (low confidence). Album totals come from the /me/tracks walk; a width-bounded per-id GET /albums/{id} fills in the rest. Never mutates. dry_run previews cost.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview cost only. |
| 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.
library_snapshot_diff ~97
Diff two sidecar JSON files (library.json or playlists.json): added/removed counts + samples. Quota: local only (no API).
| Name | Type | Req | Description |
|---|---|---|---|
| after_path | string | yes | Path to after snapshot JSON |
| before_path | string | yes | Path to before snapshot JSON |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
list_accounts ~102
List every local account this server can act as, and which one it is acting as now. Returns each account's account_id, profile name, display name and token file PATH — never any token material. Reads the local registry and one GET /me for the acting account; no mutation requests are issued.
| 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.
list_backups ~115
List complete and partial library backups (newest first) using bounded metadata sidecar reads, with a bounded prefix fallback for legacy snapshots. Expires snapshots past SPOTIFY_MCP_BACKUP_RETENTION_DAYS (default 30, 0 disables) and reports what it removed, plus the store envelope (dir_bytes, oldest_created, oldest_retention_until).
| 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.
list_scenes ~52
List saved playback scenes from the local sidecar
| 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.
merge_playlists ~251
Merge multiple playlists into one. Deduplicates tracks across sources (first-seen order wins) and adds them in batches of 100. Pass target_playlist_id to append to an existing playlist (it is NOT cleared) or new_name to create a fresh playlist.
| 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) |
| new_name | string | – | Name for a newly created target playlist |
| playlists | array | – | Canonical ordered playlists (1–10) |
| public | boolean | – | Visibility of a 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 |
| target_playlist_id | string | – | Existing playlist to APPEND into (never cleared) |
No output schema declared.
No examples provided.
move_items_between_playlists ~375
Bulk rehome items between playlists. Mode copy keeps the source intact; mode move removes from source after copying — by playlist position, removing exactly the transferred occurrences and leaving any other copy in the source. Supports dedupe against target and optional name/artist filter. Either side may be named by lane.
| Name | Type | Req | Description |
|---|---|---|---|
| dedupe | boolean | – | Skip tracks already in target. Default: true |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| filter | string | – | Optional substring filter: only transfer tracks whose name or artist name contains this string (case-insensitive) |
| limit | integer | – | Source page size, 1–100. Default: 100 |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| mode | string | – | copy = leave source intact; move = remove from source after copy |
| 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_lane | string | – | Lane name resolving to the source playlist; provide exactly one of source_playlist_id or source_lane |
| source_playlist_id | string | – | Source playlist ID, spotify:playlist: URI, or URL; provide exactly one of source_playlist_id or source_lane |
| target_lane | string | – | Lane name resolving to the target playlist; 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.
overlap_playlists ~207
Find tracks shared across playlists: reports how many playlists each track appears in and lists tracks present in at least min_overlap playlists (default: all of them), most-shared first.
| 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) |
| min_overlap | integer | – | Minimum number of playlists a track must appear in. Default: all playlists |
| playlists | array | – | Canonical ordered playlists (2–10) |
| 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.
pause ~84
Pause playback on the active device
| 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 |
No output schema declared.
No examples provided.
pin_playlist ~124
DEPRECATED, use follow_playlist. This tool never pinned anything; it has always saved the playlist to your Spotify library via PUT /me/library.
| 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.
plan_podcast_session ~281
Greedy-pack your saved podcast episodes into a listening session of a given length. Episodes play their remaining time (duration minus resume position); fully played ones are skipped. Scanning stops at the first unplayed episode that doesn't fit.
| Name | Type | Req | Description |
|---|---|---|---|
| kind | string | – | Restrict the source: 'episodes' = your saved episodes only, 'shows' = recent episodes of your saved shows only. Omit to use saved episodes (plus saved shows when saved_only is false) |
| market | string | – | ISO 3166-1 alpha-2 country code for the saved-show episode lookups, e.g. "US". Defaults to SPOTIFY_MCP_MARKET, then to the account country — these lookups are market-gated, so a wrong default silentl… |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| minutes | integer | yes | Session length in minutes (1–480) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| saved_only | boolean | – | When no kind is set, include recent episodes of saved shows too. Default: true (saved episodes only) |
No output schema declared.
No examples provided.
play ~217
Start or resume playback. Optionally target specific content.
| Name | Type | Req | Description |
|---|---|---|---|
| context_uri | string | – | Spotify URI for an album, artist, or playlist |
| device_id | string | – | Target device ID; uses active device if omitted |
| dry_run | boolean | – | Preview only: describe what would change without performing it. Default false — pass true to preview. |
| offset | integer | – | Index within an album/playlist context to start from. Ignored for ad-hoc uris; not valid for artist contexts (use offset_uri instead). |
| offset_uri | string | – | Track URI inside the context to start from — required for artist contexts, where a numeric index is rejected |
| position_ms | integer | – | Seek position to start at (ms) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| uris | array | – | Up to 100 track/episode URIs to play as an ad-hoc queue |
No output schema declared.
No examples provided.
play_from_search ~190
Search Spotify by name and immediately play the best match. Works for songs and podcast episodes — no URI needed.
| Name | Type | Req | Description |
|---|---|---|---|
| device_id | string | – | Target device ID; uses active device if omitted |
| dry_run | boolean | – | Preview only: describe what would change without performing it. Default false — pass true to preview. |
| market | string | – | ISO 3166-1 alpha-2 country code — affects availability/relinking of results; defaults to SPOTIFY_MCP_MARKET |
| query | string | yes | Search text, e.g. a song title or podcast episode name |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| search_type | string | – | What to search for: 'track' (song) or 'episode' (podcast episode) |
No output schema declared.
No examples provided.
playlist_collab_toggle ~100
Toggle collaborative/public flags (guards public=true && collaborative=true 400). Quota: GET + PUT.
| Name | Type | Req | Description |
|---|---|---|---|
| collaborative | boolean | – | Target collaborative state for the playlist |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| playlist_id | string | yes | Playlist ID, spotify:playlist: URI, or URL |
| public | boolean | – | Target visibility: true makes the playlist public |
No output schema declared.
No examples provided.
playlist_reverse ~67
Reverse a playlist in one atomic replace. Quota: GET all + PUT/POST.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| playlist_id | string | yes | Playlist ID, spotify:playlist: URI, or URL |
No output schema declared.
No examples provided.
playlist_shuffle ~88
Fisher-Yates shuffle a playlist (seeded optional). Quota: GET all + PUT/POST.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| playlist_id | string | yes | Playlist ID, spotify:playlist: URI, or URL |
| seed | string | – | Deterministic shuffle seed; omit for a random order |
No output schema declared.
No examples provided.
playlist_sort ~163
Sort a playlist in place by added_at/name/artist/duration. Quota: GET all + PUT/POST. popularity is not a sort key: the API no longer returns it on playlist items.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| 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 |
| sort_by | string | – | Sort key applied to the playlist |
No output schema declared.
No examples provided.
playlist_subtract ~270
Remove tracks of B..N from A by REWRITING A: one PUT replaces every row with the ones that survive, so any row of A absent from the union is DELETED, and the rows that remain are re-written in order. Subtracting every track empties A via one PUT with an empty uris array (Spotify's documented clear); a reply with no snapshot_id reports unconfirmed, not ok. Quota: N GETs + PUT.
| Name | Type | Req | Description |
|---|---|---|---|
| base_playlist_id | string | yes | Base playlist ID, URI, or URL. Required; list only the subtraction sources in playlists. |
| 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) |
| playlists | array | – | Canonical ordered playlists (1–10) |
| 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.
playlist_symmetric_difference ~168
Tracks in exactly one of two playlists (XOR). 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.
playlist_template_apply ~164
Create an instant mood/vibe playlist from a template (focus, wind-down, gym, commute) composed from your existing listening data. Creates a new playlist and fills it.
| Name | Type | Req | Description |
|---|---|---|---|
| description | string | – | Playlist description override |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| limit | integer | – | How many tracks (1-100, default 30) |
| name | string | – | Playlist name (default: "<Template> Mix") |
| public | boolean | – | Whether the playlist is public |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| template | string | yes | Template name |
No output schema declared.
No examples provided.
playlist_to_library ~122
Save all tracks of a playlist to your Liked Songs (library). Quota: GET playlist items + PUT /me/tracks (chunked 50).
| Name | Type | Req | Description |
|---|---|---|---|
| dedupe | boolean | – | Skip tracks already saved (default true) |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| playlist_id | string | yes | Source playlist ID |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
playlist_trim ~154
Trim playlist to N items (keep first/last/random) by OVERWRITING the playlist: every row outside the kept set is DELETED, and the kept rows are re-written in the new order. An overwrite that deletes rows asks for confirmation first. Quota: 2 walks of the playlist items + 2 metadata GETs + PUT/POST.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| keep | integer | yes | How many items to keep |
| keep_which | string | – | Which end of the playlist to keep items from. Default first |
| playlist_id | string | yes | Playlist ID, spotify:playlist: URI, or URL |
No output schema declared.
No examples provided.
playlist_union ~285
Union of 2–10 playlists into target (deduped, first-seen order). An empty union empties the target the same way subtract does. Quota: N GETs + PUT/POST; replacing an existing target also reads its current items and its playlist metadata to measure the destructive impact.
| Name | Type | Req | Description |
|---|---|---|---|
| dedupe | boolean | – | Drop duplicate URIs across the merged sources. 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) |
| playlists | array | – | Canonical ordered playlists (2–10) |
| 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 |
| target_name | string | – | Name for a newly created target playlist; provide exactly one of target_playlist_id or target_name |
| target_playlist_id | string | – | Existing target playlist (ID, URI, or URL); provide exactly one of target_playlist_id or target_name |
No output schema declared.
No examples provided.
remove_duplicate_playlist_items ~293
Remove duplicate items from a playlist: keeps the first occurrence of each track and removes later repeats, under the `match_by` rule the other duplicate tools use — `uri` (default, exact repeats), `name_artist` (same name and credited artists, catching remasters and relinks under a new URI) or `name` (same title only). The rule applied is echoed as `match_by`. Supports dry_run; removals of 10+ items ask for confirmation via elicitation. See the duplicate-matching vocabulary in SPEC section 4.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| 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… |
| playlist_id | string | yes | Playlist ID |
No output schema declared.
No examples provided.
remove_from_library ~173
Preferred. Accepts the widest URI mix (track, album, episode, show, audiobook, user, playlist) in one request. Remove one or more items from the user's library via Spotify's unified library endpoint. Max 40. PREVIEWS BY DEFAULT — pass dry_run=false to commit. Removals of 10+ items additionally require elicitation confirmation (or SPOTIFY_MCP_CONFIRM=never for automation).
| 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. |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| uris | array | yes | Spotify URIs to remove |
No output schema declared.
No examples provided.
remove_from_library_by_playlist ~158
Remove from Liked Songs any tracks that also appear in a given playlist. Quota: 2 GETs + DELETE (chunked). PREVIEWS BY DEFAULT — pass dry_run=false to commit. Removing 10+ saved tracks additionally requires elicitation confirmation (or SPOTIFY_MCP_CONFIRM=never for automation).
| 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. |
| playlist_id | string | yes | Playlist ID whose tracks will be removed from library |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
remove_from_playlist ~102
Remove tracks or episodes from a playlist. Max 100 entries per call.
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| playlist_id | string | yes | Playlist ID |
| snapshot_id | string | – | Apply the removal against this playlist version instead of the latest |
| uris | array | yes | URIs to remove; use { uri, positions } to target specific occurrences of a repeated URI |
No output schema declared.
No examples provided.
reorder_playlist_items ~179
Move a range of items within a playlist. Spotify semantics: when insert_before > range_start, the effective destination shifts down by range_length because the moved range is lifted out first (e.g. moving [2] to insert_before=4 lands it AT index 3).
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| insert_before | integer | yes | Index to insert the range before. 0-based index into the playlist's current item order (0 = the first item). |
| playlist_id | string | yes | Playlist ID |
| range_length | integer | – | Number of items to move. Default: 1 |
| range_start | integer | yes | Index of the first item to move. 0-based index into the playlist's current item order (0 = the first item). |
No output schema declared.
No examples provided.
replace_playlist_items ~98
Replace ALL items in a playlist with the supplied URIs, overwriting the current contents. Lists longer than 100 URIs are sent in chunks internally (replace + appends).
| Name | Type | Req | Description |
|---|---|---|---|
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| playlist_id | string | yes | Playlist ID |
| uris | array | yes | Complete ordered list of track or episode URIs the playlist should contain |
No output schema declared.
No examples provided.
restore_library_snapshot ~326
STRICTLY ADDITIVE restore of a library snapshot written by backup_library (see list_backups). Adds only what is missing: saves absent tracks/albums/shows/episodes/audiobooks, follows unfollowed artists, and creates NEW playlists named 'Restored · <name> (<snapshot date>)' — existing playlists are never touched and nothing is deleted, renamed, or overwritten. Truncated snapshots are previewable but refused before confirmation or writes; quota-hit, contentless or wrong-schema_version snapshots are refused outright. Prompt and result state where the stored data came from, the date the FILE declares (naming the reason when absent — never the mtime), the item count, and the single use made of it; dry_run defaults to TRUE (read-only preview); setting dry_run=false requires explicit confirmation before any write, fails closed when elicitation is unavailable or errors, and allows writes when SPOTIFY_MCP_CONFIRM=never.
| Name | Type | Req | Description |
|---|---|---|---|
| backup_path | string | yes | Snapshot JSON path from backup_library (see list_backups) |
| categories | array | – | Which snapshot categories to restore. Default: all |
| dry_run | boolean | – | DEFAULT true: read-only preview of exactly what would be added. Set false to perform the (additive) writes after explicit confirmation. |
| 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.
save_discover_weekly ~145
Archive your Discover Weekly into a regular playlist (creates or overwrites the archive). Resolves Discover Weekly via /me/playlists exact match first, falling back to search (unverified); dry_run previews; idempotent if archive already matches. Result echoes source identity (owner, url, verified).
| Name | Type | Req | Description |
|---|---|---|---|
| archive_name | string | – | Archive playlist name (created if missing, overwritten if present) |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
save_release_radar ~144
Archive your Release Radar into a regular playlist (creates or overwrites the archive). Resolves Release Radar via /me/playlists exact match first, falling back to search (unverified); dry_run previews; idempotent if archive already matches. Result echoes source identity (owner, url, verified).
| Name | Type | Req | Description |
|---|---|---|---|
| archive_name | string | – | Archive playlist name (created if missing, overwritten if present) |
| dry_run | boolean | – | Preview only: validate inputs and describe exactly what would change without performing it |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
No output schema declared.
No examples provided.
save_scene ~173
Save a named playback scene (device + volume + shuffle/repeat + optional context) to the local sidecar (~/.spotify-mcp/scenes.json)
| Name | Type | Req | Description |
|---|---|---|---|
| context_uri | string | – | Context URI to start on apply (e.g. spotify:playlist:…) |
| device_hint | string | – | Device name substring (case-insensitive) or exact device id |
| name | string | yes | Scene name (key in the sidecar) |
| repeat | string | – | Repeat mode: 'off' | 'track' | 'context' |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| shuffle | boolean | – | Shuffle state |
| volume | integer | – | Master volume percent (0–100) |
No output schema declared.
No examples provided.
save_to_library ~163
Preferred. Accepts the widest URI mix (track, album, episode, show, audiobook, user, playlist) in one request. Save one or more items to the user's library via Spotify's unified library endpoint. Max 40. PREVIEWS BY DEFAULT — pass dry_run=false to commit.
| 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. |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| uris | array | yes | Spotify URIs to save (e.g. ["spotify:track:abc", "spotify:user:xyz"]) |
No output schema declared.
No examples provided.
schedule_wind_down ~166
Preview or start a volume wind-down: absolute-minute volume steps, then pause. Set dry_run to preview without replacing or cancelling an active timer.
| Name | Type | Req | Description |
|---|---|---|---|
| device_id | string | – | Target device id; defaults to the active device |
| dry_run | boolean | – | Preview only: describe what would change without performing it. Default false — pass true to preview. |
| floor_volume | integer | – | Volume floor the ramp never goes below (default 10) |
| minutes | integer | yes | Total ramp duration in minutes (1–180) |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| step_minutes | integer | – | Minutes between volume steps (default 5) |
No output schema declared.
No examples provided.
search ~338
Search Spotify's catalog for tracks, artists, albums, playlists, shows, episodes, or audiobooks. Pass `types` as an array (e.g. `["artist"]`) to search a single kind — no track/album fallback noise. Decision guide: search (general, ≤10/type), search_deep (paginated fetch_all up to 50/type), search_fresh (tag:new last 2 weeks), search_by_isrc (exact ISRC), whats_new (personal radar from follows).
| Name | Type | Req | Description |
|---|---|---|---|
| include_external | string | – | Pass "audio" to include externally-hosted audio items marked as playable |
| limit | integer | – | Results per type, 1–10. Default: 5 |
| market | string | – | ISO 3166-1 alpha-2 country code, e.g. 'US' — uppercased automatically |
| max_results | integer | – | Max items to return (default: SPOTIFY_MCP_MAX_ITEMS env or 50) |
| offset | integer | – | Index of the first result to return, 0–1000. Use with limit to page through results |
| query | string | yes | Search query |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| types | array | – | Content types to search, as an array. Default: ["track","artist","album"]. Pass e.g. ["artist"] for an artist-only search. "audiobook" is only available in the US, UK, CA, IE, NZ and AU markets. |
No output schema declared.
No examples provided.
search_deep ~324
Paged catalog search that walks past the API limit of 10 results per type. Fetches up to 5 pages of 10 results per requested type server-side from a caller-supplied `offset`, dedupes by id, and returns compact rows. Type walks overlap (width: SPOTIFY_MCP_MAX_CONCURRENCY, else SPOTIFY_MCP_FANOUT_CONCURRENCY, else 4); same request count. Decision guide: use search_deep when you need >10 results/type or a later window; otherwise use search (single page), search_fresh (new releases), search_by_isrc (ISRC-exact), whats_new (personal follows).
| Name | Type | Req | Description |
|---|---|---|---|
| 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 | – | Index of the first result to walk per type, 0–1000. The next_offset a call reports is the offset to pass here to continue. Default: 0 |
| pages | integer | – | Pages of 10 results to walk per type, 1–5. Default: 1 |
| query | string | yes | Search query |
| response_format | string | – | 'concise' = human prose, 'detailed' = more fields in prose, 'json' = raw API object |
| types | array | – | Content types to search. Default: ["track"] |
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.
What did VerifyMCP test on the Spotify MCP server?
VerifyMCP ran 16 checks on Spotify MCP, covering Malware scan, Known CVEs, Install scripts, Dependency health and 12 more. Endpoint Security and Transport & Reachability do not apply to an npm package, so they were not tested. The score does not measure everything, and the scoring documentation lists what it leaves out.