Spotify Streamable MCP Server
Provides comprehensive Spotify integration with tools for searching the music catalog, reading player status, controlling playback and devices, managing playlists, and managing saved songs. Supports fuzzy search queries, voice control, and mood-based playlist creation.
Click on "Install 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., "@Spotify Streamable MCP Serverplay some relaxing jazz music"
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.
Spotify MCP Server
Fetch-native MCP server for Spotify — search music, control playback, manage playlists, and manage saved songs. It runs on Bun and Cloudflare Workers.
Author: overment
This repository targets thecandidate 2026-07-28 protocol with exact @modelcontextprotocol/server@2.0.0-beta.5 and @modelcontextprotocol/client@2.0.0-beta.5 pins. Do not describe it as conforming to the final dated release until the final specification and packages are published and verified.
The MCP boundary validates Host and Origin, uses strict CORS and bounded bodies, and validates opaque Resource Server tokens. Production operators must still configure the public URL/allowlists, TLS-facing deployment, Spotify credentials and redirect URIs, encrypted storage, rate limits, audit policy, and Spotify compliance.
Motivation
At first glance, a "Spotify MCP" may seem unnecessary—pressing play or skipping a song is often faster by hand. It becomes genuinely useful when you don't know the exact title (e.g., "soundtrack from [movie title]"), when you want to "create and play a playlist that matches my mood", or when you're using voice. This MCP lets an LLM handle the fuzzy intent → search → selection → control loop, and it returns clear confirmations of what happened. It works well with voice interfaces and can be connected to agents/workflows for smart‑home automations.
Demo

Alice — a desktop AI assistant

Claude Desktop
Related MCP server: Spotify MCP Server
Features
✅ Search — Find tracks, albums, artists, playlists
✅ Player Control — Play, pause, skip, seek, volume, shuffle, repeat, queue
✅ Device Transfer — Move playback between devices
✅ Playlists — Create, edit, add/remove tracks, reorder
✅ Library — Save/remove tracks, check if saved
OAuth 2.1 proxy — PKCE S256, CIMD/DCR metadata, opaque RS-token mapping, refresh and rotation
Dual runtime — Bun and Cloudflare Workers
Protected storage — Existing file/KV record formats and AES-256-GCM encryption remain compatible
MCP v2 candidate — Modern
2026-07-28plus SDK-owned stateless2025-11-25fallback
Design Principles
LLM-friendly: Tools don't mirror Spotify's API 1:1 — interfaces are simplified and unified
Batch-first: Operations use arrays (
queries[],operations[]) to minimize tool callsClear feedback: Every response includes human-readable
_msgwith what succeeded/failedBest-effort verification: Player control verifies device, context, and current track
Quick Start
1. Install
cd spotify-mcp
bun install2. Configure
cp .env.example .envEdit .env:
PORT=3000
AUTH_ENABLED=true
MCP_PUBLIC_URL=http://localhost:3000/mcp
MCP_ALLOWED_HOSTS=localhost,127.0.0.1,[::1]
MCP_ALLOWED_ORIGIN_HOSTNAMES=localhost,127.0.0.1,[::1]
MCP_LEGACY_MODE=stateless
MCP_MAX_REQUEST_BYTES=1048576
# From https://developer.spotify.com/dashboard
SPOTIFY_CLIENT_ID=your_client_id
SPOTIFY_CLIENT_SECRET=your_client_secret
# OAuth
OAUTH_SCOPES=playlist-read-private playlist-read-collaborative playlist-modify-public playlist-modify-private user-read-playback-state user-modify-playback-state user-read-currently-playing user-library-read user-library-modify
OAUTH_REDIRECT_URI=alice://oauth/callback
OAUTH_REDIRECT_ALLOWLIST=alice://oauth/callback3. Configure Spotify Dashboard
Add redirect URIs in Spotify Developer Dashboard:
http://127.0.0.1:3001/oauth/callback
alice://oauth/callback4. Run
bun dev
# MCP: http://127.0.0.1:3000/mcp
# OAuth: http://127.0.0.1:3001Server Instructions (What the Model Sees)
Use these tools to find music, get the current player status, control and transfer playback, and manage playlists and saved songs.
Tools
- search_catalog: Find songs, artists, albums, or playlists
- player_status: Read current player, available devices, queue, and current track
- spotify_control: Batch control playback (play, pause, next, previous, seek, volume, shuffle, repeat, transfer, queue)
- spotify_playlist: Manage playlists (list, get, items, create, update, add/remove items, reorder)
- spotify_library: Manage saved songs (get, add, remove, contains)
CRITICAL: device_id
- device_id is a long alphanumeric hash, NOT a human-readable name
- NEVER use the device name (like "MacBook Pro" or "iPhone") as device_id — this will fail!
- Always copy the exact device_id value from player_status → devices[].id or player.device_idTools
search_catalog
Search songs, artists, albums, and playlists.
Input:
{
queries: string[]; // Search terms
types: ("album"|"artist"|"playlist"|"track")[]; // What to search
market?: string; // 2-letter country code
limit?: number; // 1-50 (default 20)
offset?: number; // 0-1000 (default 0)
include_external?: "audio";
}Output:
{
_msg: string;
batches: Array<{
query: string;
totals: Record<string, number>;
items: Array<{ type, id, uri, name, artists?, album? }>;
}>;
}player_status
Read current player state, devices, queue, and current track.
Input:
{ include?: ("player"|"devices"|"queue"|"current_track")[] }Output:
{
_msg: string;
player?: {
is_playing: boolean;
device_id?: string; // Use this for control!
shuffle_state?: boolean;
repeat_state?: "off"|"track"|"context";
progress_ms?: number;
context_uri?: string|null;
};
current_track?: { type, id, uri, name, artists, album, duration_ms } | null;
devices?: Array<{
id: string; // Use this for control!
name: string;
type: string;
is_active: boolean;
volume_percent?: number;
}>;
queue?: { current_id?: string; next_ids: string[] };
}spotify_control
Control playback with batch operations.
Input:
{
operations: Array<{
action: "play"|"pause"|"next"|"previous"|"seek"|"volume"|"shuffle"|"repeat"|"transfer"|"queue";
device_id?: string; // Long alphanumeric hash from player_status
position_ms?: number; // For seek or play start position
volume_percent?: number; // 0-100 for volume
shuffle?: boolean;
repeat?: "off"|"track"|"context";
context_uri?: string; // Album/playlist URI
uris?: string[]; // Track URIs (don't combine with context_uri)
offset?: { position?: number; uri?: string };
queue_uri?: string;
transfer_play?: boolean;
}>;
parallel?: boolean; // Run concurrently (default: sequential)
}Output:
{
_msg: string;
results: Array<{ index, action, ok, error?, device_id?, device_name? }>;
summary: { ok: number; failed: number };
}spotify_playlist
Manage playlists.
Input:
// List user playlists
{ action: "list_user"; limit?: number; offset?: number }
// Get playlist details
{ action: "get"; playlist_id: string }
// Get playlist tracks (includes position for play offset)
{ action: "items"; playlist_id: string; limit?: number; offset?: number }
// Create playlist
{ action: "create"; name?: string; description?: string; public?: boolean }
// Update details
{ action: "update_details"; playlist_id: string; name?: string; description?: string }
// Add tracks
{ action: "add_items"; playlist_id: string; uris: string[] }
// Remove tracks
{ action: "remove_items"; playlist_id: string; tracks: { uri: string }[] }
// Reorder tracks
{ action: "reorder_items"; playlist_id: string; range_start: number; insert_before: number }spotify_library
Manage saved tracks.
Input:
// List saved tracks
{ action: "tracks_get"; limit?: number; offset?: number }
// Save tracks (use track IDs, not URIs)
{ action: "tracks_add"; ids: string[] }
// Remove saved tracks
{ action: "tracks_remove"; ids: string[] }
// Check if saved
{ action: "tracks_contains"; ids: string[] }Example Session
A complete walkthrough showing all tools working together.
1. "What's playing?"
Tool: player_status
{ "include": ["player", "devices", "current_track"] }Response:
'Come With Me - Radio Mix' is playing on 'MacBook Pro' (device_id: "8fc48c51d766...").
Available devices (use device_id for control):
• MacBook Pro (Computer) [ACTIVE] → device_id: "8fc48c51d766..."2. "Play Protected from this playlist"
First, get playlist items to find the track position:
Tool: spotify_playlist
{ "action": "items", "playlist_id": "2mMPIccnFiOd2xgkO0iABm", "limit": 50 }Response:
Loaded 50 items from 'Nora' (context: spotify:playlist:2mMPIccnFiOd2xgkO0iABm).
- #0 Come with Me - Radio Mix — spotify:track:2FxwTax2LGVybNIrreiwXv
- #7 Protected — spotify:track:1cRRIRrUiPnLOvsnWNhoH9
… and moreThen play at position #7:
Tool: spotify_control
{
"operations": [{
"action": "play",
"context_uri": "spotify:playlist:2mMPIccnFiOd2xgkO0iABm",
"offset": { "position": 7 }
}]
}Response:
Successful: play. Status: Now playing on 'MacBook Pro'. Current track: 'Protected'.3. "Add this to my favorites"
Tool: spotify_library
{ "action": "tracks_add", "ids": ["1cRRIRrUiPnLOvsnWNhoH9"] }Response:
Saved 1 track:
- Protected — spotify:track:1cRRIRrUiPnLOvsnWNhoH94. "Turn volume up to 100%"
Tool: spotify_control
{
"operations": [{ "action": "volume", "volume_percent": 100 }]
}Response:
Successful: volume. Status: Now playing on 'MacBook Pro'. Current track: 'Protected'. Volume: 100%HTTP and credential boundaries
POST /mcp— MCP endpoint. A freshMcpServeris registered for each request.GET /mcpandDELETE /mcp—405; this server does not create MCP transport sessions.GET /health— Runtime health.GET /.well-known/oauth-protected-resource/mcp— RFC 9728 Resource Server metadata. Legacy metadata aliases remain available.GET /.well-known/oauth-authorization-server— OAuth Authorization Server metadata.
OAuth proxy routes stay outside MCP dispatch. Workers expose them on the same origin; Bun exposes them on PORT + 1:
GET /authorize— Start the Spotify authorization flow.GET /oauth/callback— Exchange Spotify's provider code.POST /token— Exchange a client code or refresh an RS token.POST /revoke— Preserve the existing no-op revocation response.POST /register— Dynamic client registration/CIMD-compatible metadata flow.
The bearer presented to /mcp is an opaque MCP Resource Server token. A custom verifier looks up its stored alias, proactively refreshes Spotify when needed, and puts only resolvedSpotifyAccessToken in AuthInfo.extra. Tools never use AuthInfo.token, never forward the inbound MCP bearer, and never receive a Spotify refresh token. File/KV refresh records remain the only refresh-token boundary.
MCP_REQUIRED_SCOPES is optional and empty by default for rollout compatibility. When configured, missing trusted record scopes return 403 insufficient_scope.
Client Configuration (Claude Desktop)
{
"mcpServers": {
"spotify": {
"command": "bunx",
"args": ["mcp-remote", "http://127.0.0.1:3000/mcp", "--transport", "http-only"],
"env": { "NO_PROXY": "127.0.0.1,localhost" }
}
}
}Cloudflare Workers
Setup
Create a KV namespace:
wrangler kv namespace create TOKENSCopy
wrangler.example.jsonctowrangler.jsonc, set the KV ID, public deployment settings, and allowlists:
{
"vars": {
"AUTH_ENABLED": "true",
"MCP_LEGACY_MODE": "stateless",
"OAUTH_SCOPES": "playlist-read-private user-read-playback-state user-modify-playback-state user-library-read user-library-modify"
},
"kv_namespaces": [{ "binding": "TOKENS", "id": "your-kv-id" }]
}Set MCP_PUBLIC_URL, MCP_ALLOWED_HOSTS, MCP_ALLOWED_ORIGIN_HOSTNAMES, and AUTH_DISCOVERY_URL for the production hostname. The Worker has a backward-compatible first-request origin fallback, but explicit values are the recommended production posture.
Set secrets:
wrangler secret put SPOTIFY_CLIENT_ID
wrangler secret put SPOTIFY_CLIENT_SECRET
# Generate encryption key (32-byte base64url):
openssl rand -base64 32 | tr -d '=' | tr '+/' '-_'
# Copy the output, then:
wrangler secret put TOKENS_ENC_KEY
# Paste the generated key when promptedNote: The Worker retains the deployed
TOKENS_ENC_KEYbinding and also acceptsRS_TOKENS_ENC_KEY; Bun usesRS_TOKENS_ENC_KEY. Both feed the same AES-256-GCM record codec. Without a key, tokens are stored in plaintext (not recommended for production).
Deploy:
wrangler deployDevelopment
bun dev # Bun MCP + OAuth servers with reload
bun test # OAuth, protocol, provider mock, and storage compatibility tests
bun run typecheck # Bun and Worker TypeScript projects
bun run lint # Biome checks
bun run format:check # Formatting check
bun run build # Bun bundle
bun run types:worker:check # Generated Worker bindings
bun run build:worker # Wrangler dry-run/workerd bundle
bun run test:workerd # Actual local workerd, modern + legacy clients
bun start # Bun MCP + OAuth serversCandidate validation status
Automated tests use the official beta.5 client for modern and legacy flows, pin complete six-tool wire snapshots, exercise opaque-token 401/403 behavior, prove MCP/Spotify token separation and concurrent-principal isolation, mock all five Spotify provider tools, and verify plaintext/encrypted file and KV record compatibility. The Zod 4 projection preserves contract meaning while using draft 2020-12 anyOf for nullable fields and explicit JavaScript-safe bounds for integer schemas.
Credential-only validation remains for a real Spotify account and deployment: Spotify Dashboard redirect registration, a live authorize/callback/token/refresh cycle, account/Premium-dependent playback behavior, production KV bindings and secrets, and the final public hostname/TLS/allowlists. Final 2026-07-28 conformance also remains gated on the final specification and stable packages.
Architecture
src/
├── shared/
│ ├── tools/ # Tool definitions (work in Node + Workers)
│ │ ├── player-status.ts
│ │ ├── search-catalog.ts
│ │ ├── spotify-control.ts
│ │ ├── spotify-playlist.ts
│ │ └── spotify-library.ts
│ ├── oauth/ # OAuth flow (PKCE, discovery)
│ └── storage/ # Token storage (file, KV, memory)
├── services/
│ └── spotify/ # Spotify API clients
│ ├── sdk.ts # SpotifyApi wrapper
│ ├── player.ts # Player API
│ └── catalog.ts # Search API
├── schemas/
│ ├── inputs.ts # Zod input schemas
│ └── outputs.ts # Zod output schemas
├── config/
│ └── metadata.ts # Server & tool descriptions
├── core/ # v2 fresh-server factory and fetch-native SDK handler
├── http/ # MCP security/body/auth boundary and Bun OAuth app
├── index.ts # Bun dual-server entry
└── worker.ts # Cloudflare Worker isolate entryTroubleshooting
Issue | Solution |
"Device not found" | You used device name instead of device_id. Get the actual ID from |
"No active device" | Open Spotify on a device, then use |
"Unauthorized" | Complete OAuth flow. Tokens may have expired. |
"Rate limited" | Wait a moment and retry |
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Flicense-quality-maintenanceEnables control of Spotify playback, music search, and playlist management through natural language commands. Available in both Python and Vercel implementations with comprehensive OAuth2 authentication and device management.Last updated
- Flicense-quality-maintenanceEnables comprehensive Spotify integration through natural language commands, supporting playback control, music search, playlist management, and device control. Available in both Python and cloud-deployable JavaScript implementations.Last updated
- Flicense-qualityDmaintenanceEnables control of Spotify playback through OAuth authentication, including play/pause, track navigation, volume control, device management, and searching/playing songs by artist or track name.Last updated1
- AlicenseCqualityDmaintenanceEnables natural language control of Spotify, including search, playback, and device management, with robust error handling and automatic token refresh.Last updated374MIT
Related MCP Connectors
Spotify MCP — Web API via client_credentials OAuth
Hosted NeuroDock — stateless communication and planning tools over OAuth-secured Streamable HTTP.
Personal assistant MCP server with search, execute, packages, jobs, secrets, and integrations.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/iceener/spotify-streamable-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server