Skip to main content
Glama
README.md
<div align="center">

# Spotify MCP Server

**A comprehensive Model Context Protocol (MCP) server for Spotify**

Provides 51 granular tools perfect for building dynamic HUDs, music visualizers, and AI-powered music control interfaces

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=for-the-badge)](https://opensource.org/licenses/MIT)
[![Node.js Version](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=for-the-badge)](https://nodejs.org)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.4-blue?style=for-the-badge)](https://www.typescriptlang.org/)
[![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.0.1-purple?style=for-the-badge)](https://github.com/modelcontextprotocol/sdk)

</div>

---

<div align="center">

## Why This MCP Server?

</div>

<div align="center">

This MCP server is specifically designed for **dynamic HUD applications** where you need individual data points.
Instead of parsing large JSON responses, each tool returns exactly what you need.

</div>

<div align="center">

| Use Case | Traditional Approach | This Server |
|----------|---------------------|-------------|
| Get track name | Parse JSON → Extract `item.name` | `spotify_get_track_name` → Direct value |
| Get artist | Parse JSON → Extract `item.artists[0].name` | `spotify_get_artist_name` → Direct value |
| Show countdown timer | Parse JSON → Calculate remaining time → Format | `spotify_get_time_remaining_formatted` → "3:24" |
| Progress bar | Parse JSON → Calculate percentage | `spotify_get_track_progress_percentage` → "67" |
| Play/pause button | Parse JSON → Check `is_playing` | `spotify_is_playing` → "true" or "false" |

</div>

---

<div align="center">

## Complete Tool Coverage

**51 tools organized into 9 categories for maximum flexibility**

</div>

<div align="center">

| Category | Tool Count | Description |
|----------|------------|-------------|
| Bulk State Tools | 2 | Get complete playback state or track info in one call |
| Granular Track Info | 16 | Individual tools for artist, track name, album, duration, progress, artwork, and more |
| Granular Device Info | 6 | Get device name, type, volume, ID, and active status individually |
| Granular Playback State | 5 | Individual tools for play state, shuffle, repeat mode, and context |
| Playback Control | 7 | Play, pause, next, previous, seek, shuffle, and repeat controls |
| Volume & Device Control | 2 | Set volume and transfer playback between devices |
| Queue Management | 3 | View queue, add tracks, and see recently played |
| Search & Discovery | 5 | Search tracks, albums, artists, and get detailed information |
| Library Management | 5 | Manage saved tracks and playlists |

</div>

---

<div align="center">

## Key Features

</div>

<div align="center">

| Feature | Description |
|---------|-------------|
| Granular Data Access | 51 specialized tools for precise data retrieval |
| HUD Optimized | Returns plain text values perfect for UI components |
| Production Ready | Comprehensive error handling and automatic token refresh |
| Full Test Coverage | 94 tests covering all 51 tools and edge cases |
| Type Safe | Built with TypeScript and Zod schema validation |
| OAuth Authentication | Automatic token management and refresh |
| Zero Dependencies | Only requires Node.js 18+ and Spotify account |

</div>

---

<div align="center">

## Installation

</div>

<div align="center">

| Step | Instructions |
|:---:|:---|
| **1. Prerequisites** | • Node.js 18+ installed<br>• Spotify Account (Premium recommended)<br>• Spotify Developer App credentials |
| **2. Get Credentials** | 1. Go to [Spotify Developer Dashboard](https://developer.spotify.com/dashboard)<br>2. Create a new app<br>3. Note your **Client ID** and **Client Secret**<br>4. Add `http://localhost:8888/callback` to Redirect URIs |
| **3. Install** | `npm install` |
| **4. Configure** | Copy example env: `cp .env.example .env`<br><br>Edit `.env` with credentials:<br>`SPOTIFY_CLIENT_ID=your_id`<br>`SPOTIFY_CLIENT_SECRET=your_secret`<br>`SPOTIFY_REDIRECT_URI=http://localhost:8888/callback` |
| **5. Authenticate** | `npm run auth`<br>*(Opens browser to log in and saves tokens)* |
| **6. Build** | `npm run build` |
| **7. Configure Client** | Add to `claude_desktop_config.json`:<br><pre>{<br>  "mcpServers": {<br>    "spotify": {<br>      "command": "node",<br>      "args": ["/PATH/TO/dist/index.js"],<br>      "env": { ... }<br>    }<br>  }<br>}</pre> |

</div>

---

<div align="center">

## Usage

Once configured, restart your MCP client and you'll have access to all 51 tools!

### Example Queries

| Category | User Query | Tool Used |
|:---:|:---|:---|
| **Dynamic HUDs** | "What's the current track name?" | `spotify_get_track_name` |
| | "Get the artist" | `spotify_get_artist_name` |
| | "What's the time remaining?" | `spotify_get_time_remaining_formatted` |
| | "What's the playback progress percentage?" | `spotify_get_track_progress_percentage` |
| | "Is music playing?" | `spotify_is_playing` |
| **Playback Control** | "Pause the music" | `spotify_pause` |
| | "Skip to the next song" | `spotify_next` |
| | "Set volume to 50%" | `spotify_set_volume` |
| | "Enable shuffle" | `spotify_set_shuffle` |
| **Discovery** | "Search for tracks by The Beatles" | `spotify_search` |
| | "Add this song to my library" | `spotify_save_track` |

</div>

---

<div align="center">

## Complete API Reference

</div>

<div align="center">

### Bulk State Tools (2)

</div>

<div align="center">

| Tool | Returns | Use Case |
|------|---------|----------|
| `spotify_get_playback_state` | Complete playback state (JSON) | Get all playback info at once |
| `spotify_get_current_track` | Complete track info (JSON) | Get all track info at once |

</div>

<div align="center">

### Granular Track Info Tools (16)

</div>

<div align="center">

| Tool | Returns | Perfect For |
|------|---------|-------------|
| `spotify_get_track_name` | Track name only | HUD track display |
| `spotify_get_artist_name` | Primary artist name | HUD artist display |
| `spotify_get_all_artists` | All artists (comma-separated) | Full artist credits |
| `spotify_get_album_name` | Album name only | HUD album display |
| `spotify_get_track_duration_ms` | Duration in milliseconds | Calculations |
| `spotify_get_track_duration_formatted` | Duration as "M:SS" | HUD duration display |
| `spotify_get_track_progress_ms` | Current position in ms | Calculations |
| `spotify_get_track_progress_formatted` | Current position as "M:SS" | HUD position display |
| `spotify_get_time_remaining_ms` | Time left in ms | Calculations |
| `spotify_get_time_remaining_formatted` | Time left as "M:SS" | HUD countdown timer |
| `spotify_get_track_progress_percentage` | Progress as 0-100 | Progress bars |
| `spotify_get_track_uri` | Spotify URI | Playback control |
| `spotify_get_track_id` | Spotify ID | API calls |
| `spotify_get_album_art_url` | Album artwork URL | HUD artwork display |
| `spotify_get_track_explicit` | "true" or "false" | Explicit content indicator |
| `spotify_get_track_popularity` | Popularity 0-100 | Track metrics |

</div>

<div align="center">

### Granular Device Tools (6)

</div>

<div align="center">

| Tool | Returns | Perfect For |
|------|---------|-------------|
| `spotify_get_device_name` | Device name | HUD device display |
| `spotify_get_device_type` | Device type | Device icons |
| `spotify_get_device_volume` | Volume 0-100 | Volume displays |
| `spotify_get_device_id` | Device ID | Device switching |
| `spotify_is_device_active` | "true" or "false" | Active device indicator |
| `spotify_get_available_devices` | All devices (JSON) | Device selection |

</div>

<div align="center">

### Granular Playback State Tools (5)

</div>

<div align="center">

| Tool | Returns | Perfect For |
|------|---------|-------------|
| `spotify_is_playing` | "true" or "false" | Play/pause button states |
| `spotify_get_shuffle_state` | "true" or "false" | Shuffle button states |
| `spotify_get_repeat_mode` | "off", "track", or "context" | Repeat button states |
| `spotify_get_context_type` | Context type | Playlist/album indicators |
| `spotify_get_context_uri` | Context URI | Context switching |

</div>

<div align="center">

### Playback Control Tools (7)

</div>

<div align="center">

| Tool | Parameters | Description |
|------|------------|-------------|
| `spotify_play` | device_id?, context_uri?, uris?, position_ms? | Start/resume playback |
| `spotify_pause` | device_id? | Pause playback |
| `spotify_next` | device_id? | Skip to next track |
| `spotify_previous` | device_id? | Skip to previous track |
| `spotify_seek` | position_ms, device_id? | Seek to position |
| `spotify_set_shuffle` | state (bool), device_id? | Toggle shuffle |
| `spotify_set_repeat` | state (track/context/off), device_id? | Set repeat mode |

</div>

<div align="center">

### Volume & Device Control Tools (2)

</div>

<div align="center">

| Tool | Parameters | Description |
|------|------------|-------------|
| `spotify_set_volume` | volume_percent (0-100), device_id? | Set playback volume |
| `spotify_transfer_playback` | device_id, play? | Transfer playback to device |

</div>

<div align="center">

### Queue Management Tools (3)

</div>

<div align="center">

| Tool | Parameters | Description |
|------|------------|-------------|
| `spotify_get_queue` | - | Get current playback queue |
| `spotify_add_to_queue` | uri, device_id? | Add track to queue |
| `spotify_get_recently_played` | limit? | Get recently played tracks |

</div>

<div align="center">

### Search & Discovery Tools (5)

</div>

<div align="center">

| Tool | Parameters | Description |
|------|------------|-------------|
| `spotify_search` | query, type[], limit? | Search for tracks/albums/artists/playlists |
| `spotify_get_track_info` | track_id | Get detailed track information |
| `spotify_get_album_info` | album_id | Get detailed album information |
| `spotify_get_artist_info` | artist_id | Get detailed artist information |
| `spotify_get_artist_top_tracks` | artist_id, market? | Get artist's top tracks |

</div>

<div align="center">

### Library Management Tools (5)

</div>

<div align="center">

| Tool | Parameters | Description |
|------|------------|-------------|
| `spotify_get_saved_tracks` | limit?, offset? | Get user's saved tracks |
| `spotify_save_track` | track_id | Save (like) a track |
| `spotify_remove_saved_track` | track_id | Remove (unlike) a track |
| `spotify_get_playlists` | limit?, offset? | Get user's playlists |
| `spotify_get_playlist` | playlist_id | Get playlist details |

</div>

---

<div align="center">

## Architecture

</div>

```
spotify-mcp-server/
├── src/
│   ├── auth/
│   │   ├── setup.ts              # OAuth authentication flow
│   │   └── token-manager.ts      # Token storage and refresh
│   ├── tools/
│   │   └── spotify-api.ts        # Spotify API wrapper
│   └── index.ts                  # Main MCP server with all 51 tools
├── tests/                        # Comprehensive test suite (94 tests)
├── dist/                         # Compiled JavaScript (generated)
├── package.json
├── tsconfig.json
├── eslint.config.mjs
└── .env                          # Your credentials (not committed)
```

---

<div align="center">

## Token Management

| Token Details |
|:---|
| Tokens are stored in `spotify-tokens.json` (automatically created) |
| Access tokens are **automatically refreshed** when they expire |
| You only need to run `npm run auth` once (or if tokens are revoked) |
| Tokens persist across server restarts |

</div>

---

<div align="center">

## Error Handling

The server provides clear, actionable error messages:

| Error Code | Meaning |
|:---:|:---|
| **401 Unauthorized** | Re-run `npm run auth` |
| **403 Forbidden** | Feature may require Spotify Premium |
| **404 Not Found** | No active device or track |
| **429 Rate Limit** | Too many requests, wait a moment |

</div>

---

<div align="center">

## Development

| Task | Command |
|:---:|:---|
| **Run Tests** | `npm test` (all)<br>`npm run test:watch` (watch mode)<br>`npm run test:coverage` (report) |
| **Run Linter** | `npm run lint` |
| **Clean Build** | `npm run clean && npm run build` |
| **Debugging** | Server logs to stderr |

</div>

---

<div align="center">

## Use Cases

</div>

<div align="center">

### Dynamic HUD Applications

Perfect for creating real-time music displays:

</div>

```javascript
// Get individual values for your HUD components
const trackName = await callTool("spotify_get_track_name");
const artist = await callTool("spotify_get_artist_name");
const progress = await callTool("spotify_get_track_progress_percentage");
const timeRemaining = await callTool("spotify_get_time_remaining_formatted");
const isPlaying = await callTool("spotify_is_playing");
const albumArt = await callTool("spotify_get_album_art_url");
```

<div align="center">

### Music Visualizers

Get precise timing and state info:

</div>

```javascript
const progressMs = await callTool("spotify_get_track_progress_ms");
const durationMs = await callTool("spotify_get_track_duration_ms");
const isPlaying = await callTool("spotify_is_playing");
```

<div align="center">

### AI Music Assistants

Natural language control:

</div>

```
User: "What's playing?"
AI: Uses spotify_get_track_name and spotify_get_artist_name

User: "How much time is left?"
AI: Uses spotify_get_time_remaining_formatted

User: "Skip this song"
AI: Uses spotify_next
```

---

TDQS

B3.4/5.0

Scored across 51 tools

Disambiguation5/5

Each tool has a clearly distinct purpose, with very specific actions and targets. Even though there are many tools for retrieving individual attributes of the current track, their names and descriptions unambiguously indicate what each returns.

Naming Consistency5/5

All tools follow the consistent pattern 'spotify_verb_noun' (e.g., spotify_get_track_name, spotify_set_volume). There are no mixed conventions or deviations.

Tool Count2/5

With 51 tools, the set is overly large for the domain. Many granular getters (e.g., spotify_get_track_name, spotify_get_track_id) could be consolidated into fewer tools, making the surface bloated and harder to navigate.

Completeness3/5

The set covers playback control, current state, search, and basic library management well, but lacks playlist creation/modification and other common operations like following artists or user profile retrieval. Some gaps remain.

Maintenance

ActivityInactive
ResponsivenessNo issues