mcp-spotify-free
A free-account Spotify MCP server for reading your library, searching Spotify, and controlling playback on Spotify Connect devices.
Read the full Liked Songs playlist and search within it.
Search the whole Spotify catalog for tracks, artists, albums, playlists, and profiles.
Play songs by name, liked-song search, or raw track URI.
Control playback: pause, resume, skip next/previous, and set volume.
List devices, check now playing/status, and drive Chromecast with a shortcut tool.
Manage the Spotify session: login/capture cookies, logout, and diagnose session status.
Clean up leftover “MCP Spotify Free” Connect device entries.
Enables playback control and device switching to Chromecast through Spotify Connect, including sending audio to the Chromecast and performing play, resume, pause, next, and previous actions.
Provides tools for interacting with a free Spotify account: reading the Liked Songs library, searching the full Spotify catalog, inspecting playback and devices, and controlling playback (play, pause, resume, skip, volume) across Spotify Connect devices.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-spotify-free play my liked songs on the living room Chromecast"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Why this exists
Spotify's public Web API hides the Liked Songs playlist behind Premium:
GET /v1/me/tracks answers 403 on a free account, and so does every
library-read endpoint built on it. Almost every "Spotify liked songs exporter"
on GitHub uses spotipy.current_user_saved_tracks() — Premium only.
The Spotify web player has no such restriction: it serves the full library to free users. This server speaks the same internal protocol the web player uses, so a free account gets:
its complete Liked Songs playlist (591 tracks on the reference account)
catalog search — the same search box as the web player (tracks, artists, albums, playlists, profiles), so any song can be played, not only the liked ones
real playback control — play, pause, skip, volume
device switching — send the sound to the Chromecast instead of the laptop
Every other Spotify MCP server needs Premium (checked October 2026)
A sweep of the MCP registries and PyPI/GitHub found no other Spotify MCP server that works on a plain free account. They all go through the official Spotify Web API, which means a registered developer app + OAuth, and playback is Premium-only — before Spotify tightened the API in February 2026, where the app owner must now hold Premium and Dev Mode apps are capped at 5 authorized users. For example, quoting their own docs:
marcelmarais/spotify-mcp-server— prerequisites: "A Spotify Premium account" + "A registered Spotify Developer application"mcp-spotify(PyPI) — "A Spotify Premium account (required by Spotify for Web API access)"jamiew/spotify-mcp— "Requires a Spotify Premium account"mcp-server-spotify(PyPI) /leoalord/spotify-mcp-server/iceener/spotify-streamable-mcp-server— bring your own developer app (client ID + secret + OAuth), Premium required for playback since Feb 2026
This server needs none of that: no developer app, no OAuth callback, no client secret, no Premium. It reads the session cookies of a browser where you are already logged in and speaks the web player's own protocol.
Related MCP server: Spotify MCP Server
Quick Start
npx (recommended)
npx mcp-spotify-freenpm install (global)
npm install -g mcp-spotify-free
mcp-spotify-freeFrom source
cd ~/Documents/mcp-spotify-free
python3 -m pip install -r requirements.txt
python3 server.py loginHow it works
1. Session (no password, no OAuth app, no Premium)
The server reads the Spotify cookies of a browser where you are already logged
in (open.spotify.com), decrypts them locally with the macOS keychain
(PBKDF2-HMAC-SHA1 + AES-128-CBC, the standard Chromium scheme), and
exchanges them for a short-lived user access token.
Two sources are tried, in order:
~/.config/mcp-spotify-free/cookies.json— the captured session (works with the browser closed)the browser profile itself (Edge by default) — read straight from the Chromium cookie database, nothing is dumped or copied out
spotify_session_status() tells you which one is in use and whether Spotify
still accepts it.
2. TOTP guard
open.spotify.com/api/token is protected by a 6-digit TOTP
(HMAC-SHA1, 30 s period) whose secret is XOR-obfuscated inside the web-player
bundle. spotify_free/totp.py de-obfuscates it, re-reads the live bundle on
every run (the file name changes with every Spotify release — the current one
is looked up in the open.spotify.com HTML), and keeps a hardcoded fallback
so a network hiccup never breaks the server.
3. Library
POST api-partner.spotify.com/pathfinder/v2/query — the same GraphQL-ish
gateway the web player uses — with the fetchPlaylistContents operation and
the Liked Songs playlist alias spotify:playlist:37i9dQZF1F5p3rmiWPIYgZ
(also hardcoded in the web player, not account specific).
4. Catalog search
Same gateway, searchTopResultsList operation — the endpoint behind the
web player's search box. It works on a free account.
5. Playback The Spotify Connect "harmony" command protocol:
POST connect-state/v1/player/command/from/{source}/to/{target}
PUT connect-state/v1/connect/volume/from/{source}/to/{target}Addressing the command to the Chromecast's device id is the "play on" — the audio moves from the laptop to the TV.
Device policy — the server leaves no trace
The command protocol needs a source device. Registering one would add a
permanent entry ("MCP Spotify Free") to the account's device list, and every
crashed run would leave another ghost behind. Instead the server reuses the
account's own web-player device (Web Player (Microsoft Edge)) as the
source: the commands are accepted exactly the same way, and nothing is added
to the device list. Only if no web-player device exists does the server
register one — with a stable, persisted device id, so even then the list
never grows beyond a single entry.
cleanup_devices() removes the entries left by earlier versions. It uses
DELETE /connect-state/v1/devices/{id}, which drops the entry from the
account's device list immediately (the hobs_ variant only drops the
subscription and leaves a visible ghost for hours).
IDE Integration
Cursor / Windsurf / VS Code
{
"mcpServers": {
"spotify-free": {
"command": "npx",
"args": ["mcp-spotify-free"]
}
}
}Claude Desktop
{
"mcpServers": {
"spotify-free": {
"command": "npx",
"args": ["mcp-spotify-free"]
}
}
}OpenCode / Claude Code
claude mcp add spotify-free --scope user -- npx mcp-spotify-freeThrough mcp-cli (this machine)
The server is registered in ~/.config/mcp/mcp_servers.json under
spotify-free, so it is reachable through the mcp-cli wrapper:
mcp-cli info spotify-free # list the tools
mcp-cli call spotify-free spotify_status '{}' # account + devices
mcp-cli call spotify-free play_song '{"query":"one more time","device":"Chromecast"}'
mcp-cli call spotify-free cleanup_devices '{}' # drop leftover devicesTools
get_docs()— the full usage guide, returned as one big text. Start here.spotify_status()— account, token state, liked-song count, now playing, every Connect device.list_liked_songs(limit, offset, query)— the Liked Songs playlist, newest first. Withquerythe whole library is scanned.search_liked_songs(query, limit)— only the matches, whole library.search_spotify(query, limit)— the whole catalog: tracks, artists, albums, playlists, profiles.play_song(query, device, index)— the main one: looks the title up in the Liked Songs, falls back to the catalog, and plays the best match.sourcein the answer tells you where the match came from.play_liked_song(query, device, index)— Liked Songs only.play_track(uri, device)— play a rawspotify:track:...URI.chromecast_sent(track_query, action)— the shortcut: always the Chromecast.action=play/resume/pause/next/previous.pause_playback(device)/resume_playback(device)skip_next(device)/skip_previous(device)set_volume(level, device)— 0-100.list_devices()— every Connect device with its volume and active flag.now_playing()— current track, playing/paused, position, active device.cleanup_devices()— remove the leftoverMCP Spotify FreeConnect devices of the earlier versions.spotify_session_status()— diagnose the session.spotify_login()/spotify_logout()— capture / forget the session.
Every tool returns a structured payload: ok, action, plus the relevant
data — and on failure error with a human-readable cause. When the failure is
the session (bad or expired browser cookies, 401 / 403 from the token
endpoints), the payload also carries a remedy block with paste-ready
commands for the agent: show a macOS popup explaining the login is needed,
open https://open.spotify.com in the default browser, run
spotify_login(), then retry the original call.
Typical agent flow
get_docs()
-> list_devices() # find the Chromecast
-> play_song("one more time", "Chromecast") # library first, catalog fallback
-> pause_playback()Direct use from Python
from spotify_free import SpotifyFreeClient
client = SpotifyFreeClient()
for track in client.liked_songs(limit=5):
print(track["name"], "-", ", ".join(track["artists"]), "|", track["added_at"])
hits = client.search_catalog("le songe") # the whole catalog
client.play_track(hits["tracks"][0]["uri"], device="Chromecast")
client.pause()Or run the bundled demo:
python3 examples/quickstart.pyRequirements
Item | Detail |
OS | macOS (cookie decryption uses the login keychain) |
Browser | Edge by default; Chrome, Brave, Vivaldi, Opera supported — must have an active |
Python | 3.10+ |
Environment variables:
SPOTIFY_BROWSER—edge(default),chrome,brave,vivaldi,operaSPOTIFY_COOKIES_FILE— path to a JSON file of cookies (bypasses the browser)SPOTIFY_USE_PROXY— set to1to send traffic through the system proxy (off by default: the localproxy-localplugin only carries LLM traffic)
Architecture
mcp-spotify-free/
├── server.py FastMCP server + all tool definitions
├── spotify_free/
│ ├── client.py token, library, catalog search, devices, playback
│ ├── cookies.py Chromium cookie decryption (macOS keychain)
│ ├── session.py session capture / storage / validation
│ └── totp.py web-player TOTP (de-obfuscation + auto-discovery)
├── examples/quickstart.py dependency-free demo
├── requirements.txt
└── pyproject.tomlPrivacy & terms
Cookies are read from your own machine and decrypted locally. They are never written to disk (except the captured copy in
~/.config/mcp-spotify-free/cookies.json, mode 0600) and never sent anywhere but Spotify.No password is ever handled, and no Spotify developer app / client secret is involved.
The access token lives in memory for the lifetime of the process.
Spotify's Developer Terms do not allow third-party use of the web-player token endpoint. This is a personal tool for your own account — do not ship it as a product or redistribute it.
Troubleshooting
Any session/cookie failure (
401,403,no spotify cookies found) — the failing tool returns aremedyfield instead of a dead error: it tells the calling agent to show the user a macOS popup ("log in so music can play"), to openopen.spotify.comin the default browser, tospotify_login()and retry. Nothing else to do by hand.no spotify cookies found— log in toopen.spotify.comin the browser named bySPOTIFY_BROWSER, then retry.token request failed (400)— the TOTP version moved on; the server re-reads the bundle automatically, but check thatopen.spotify.comis reachable.no active Spotify device— start the Spotify app (or any Connect device) so the account has an active player.no device matching 'x'— calllist_devices()for the exact names.A "MCP Spotify Free" entry shows up in the Spotify app — run
cleanup_devices(); it removes the entry from the account's device list.Keychain prompt on first run — macOS asks once to let
securityread the browser's Safe Storage item.
Contributing
PRs welcome. Open an issue first for non-trivial changes.
License
MIT — see LICENSE.
Available Tools
20 toolschromecast_sentChromecast SentC
Shortcut: drive the Chromecast.
Always targets the device named "Chromecast" (falls back to a Google / Chromecast device if the name differs).
Inputs: action, track_query. Returns: object
cleanup_devicesCleanup DevicesA
Remove the leftover "MCP Spotify Free" Connect devices of this server.
The server does not register a device of its own any more (it reuses the account's web-player device to send the commands), but earlier versions did - those entries are removed here, right away.
Inputs: no named parameters. Returns: object
get_docsGet DocsA
Full usage guide for every tool of this server (one big text).
Inputs: no named parameters. Returns: result
list_devicesList DevicesB
List every Spotify Connect device (Chromecast, MacBook, phones, TVs).
Inputs: no named parameters. Returns: object
list_liked_songsList Liked SongsC
Read the Liked Songs playlist (free accounts included).
Inputs: limit, query, offset. Returns: object
now_playingNow PlayingB
Current track, play/pause state and the active device.
Inputs: no named parameters. Returns: object
pause_playbackPause PlaybackC
Pause playback ("" = the device that is currently playing).
Inputs: device. Returns: object
play_liked_songPlay Liked SongC
Play a liked song, optionally on a specific Spotify Connect device.
Inputs: query (required), index, device. Returns: object
play_songPlay SongA
Play a song by name - Liked Songs first, then the whole catalog.
This is the tool to use when the user says "play ": it looks the title/artist up in the Liked Songs and, if nothing matches, falls back to the Spotify catalog search.
Inputs: query (required), index, device. Returns: object
play_trackPlay TrackB
Play a raw Spotify track URI on a device.
Inputs: uri (required), device. Returns: object
resume_playbackResume PlaybackC
Resume playback ("" = the device that is currently playing).
Inputs: device. Returns: object
search_liked_songsSearch Liked SongsA
Search the whole Liked Songs library for a title / artist / album.
Inputs: query (required), limit. Returns: object
search_spotifySearch SpotifyA
Search the whole Spotify catalog (not only your library).
Same search box as the web player: tracks, artists, albums, playlists and profiles. Use it when the song is not in the Liked Songs.
Inputs: query (required), limit. Returns: object
set_volumeSet VolumeB
Set the volume of a device (0-100).
Inputs: level (required), device. Returns: object
skip_nextSkip NextC
Skip to the next track.
Inputs: device. Returns: object
skip_previousSkip PreviousC
Go back to the previous track.
Inputs: device. Returns: object
spotify_loginSpotify LoginA
Capture a working Spotify session (free account is enough).
Tries, in order: the stored session, then the browser profile. If the browser keeps the session cookie in memory, the user is asked to quit the browser (Cmd+Q) so Chromium flushes it to disk - the tool keeps polling until the session is captured, then stores it on the filesystem so later runs work without the browser.
Inputs: browser, timeout. Returns: object
spotify_logoutSpotify LogoutA
Forget the stored session (does not log the account out of Spotify).
Inputs: no named parameters. Returns: object
spotify_session_statusSpotify Session StatusB
Diagnose the session: where the cookies come from and if they work.
Inputs: no named parameters. Returns: object
spotify_statusSpotify StatusB
Account, token, library size, now playing and every Connect device.
Inputs: no named parameters. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 20 tools
The playback trio play_song / play_liked_song / play_track all ultimately start playback of a track, and an agent could easily misselect between them (play_song already falls back to catalog search and can target devices, so play_liked_song's niche is thin). Similarly search_liked_songs vs list_liked_songs vs search_spotify borders on overlapping, though descriptions do help distinguish library vs catalog. The rest (pause/resume/skip/volume/devices/session) are clearly distinct.
Most tools follow a snake_case verb_noun pattern (play_song, list_devices, set_volume, search_spotify), with a consistent spotify_ prefix on session tools. Outliers are chromecast_sent (a noun/past-tense name that doesn't describe an action) and now_playing (noun phrase), but overall the convention is readable and predictable.
At 20 tools this sits at the heavy end of the recommended 3-15 range for what is essentially a single-domain playback controller. Some of that weight comes from near-duplicate playback entries and a bulky get_docs tool that could be folded into status output.
Core lifecycle is covered: session login/logout/status, device listing and cleanup, play/pause/resume/skip forward-back, volume, search, library listing and now-playing. Minor gaps remain (no seek/position, no shuffle or repeat, no queue management, no playlist creation), but an agent can work around these for the stated free-account playback purpose.
Maintenance
Related MCP Connectors
Full Spotify Web API coverage - albums, artists, playlists, player controls, and more.
Spotify: Spotify Data API for Millions of songs & podcasts, artists, albums, playlists and more.
Spotify MCP server for ChatGPT, Claude and any AI agent: search songs and artists, list playlists, read playlist songs, create playlist, add songs to playlist, remove songs from playlist, set playlist public or private and save to Liked Songs in your own Spotify account. Cotlet works in the account through your Cloud Browser, a real Chrome where you sign in to Spotify yourself; Cotlet does not store your password and you need no Spotify API key. About the official Spotify API: Spotify has a full Web API and, since 23 Apr 2026, an official connector for Claude (checked 5 Nov 2026). The API needs an app you register, and in development mode the app owner must have Premium and the app allows 5 users; unlimited users need a registered business with at least 250,000 monthly users. Setup and FAQ: https://cotlet.dev/integrations/spotify-api-mcp-server
Spotify MCP — Web API via client_credentials OAuth
Related MCP Servers
- FlicenseBqualityDmaintenanceEnables AI assistants to control Spotify playback, search for music, manage playlists, and interact with your Spotify library through natural language commands.19-
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to control Spotify playback, search music, manage playlists and library, and access user listening insights via the Spotify Web API.-
- AlicenseAqualityDmaintenanceEnables searching and managing Spotify playlists, tracks, and user information through the Spotify Web API.10MIT
- AlicenseNot gradedqualityCmaintenanceEnables control of Spotify playback via the official Web API, including search/play, pause, skip, volume, queue, and device management.133 npm1MIT