Skip to content

jadilson12/spotify-mcp-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

19 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Spotipy MCP Server

CI/CD Pipeline Python 3.12 Python 3.13 License: MIT Tests

MCP (Model Context Protocol) Server with Spotipy integration for music control via Spotify.

πŸš€ Features

  • βœ… Playback control (play, pause, next, previous)
  • βœ… Volume adjustment
  • βœ… Music search
  • βœ… Get current track
  • βœ… Playlist management
  • βœ… Complete REST API
  • βœ… Automatic documentation (Swagger)
  • βœ… Complete MCP integration with tools and resources

πŸ“‹ Prerequisites

  • Python 3.12+
  • Spotify Developer account
  • Registered application in Spotify Developer Dashboard

πŸ› οΈ Installation

  1. Clone the repository:
git clone https://github.com/jadilson12/spotify-mcp-server
cd spotify-mcp-server
  1. Install dependencies:
make install
  1. Configure environment variables:
cp env.example .env

Edit the .env file with your Spotify credentials:

SPOTIFY_CLIENT_ID=your_client_id_here
SPOTIFY_CLIENT_SECRET=your_client_secret_here
SPOTIFY_REDIRECT_URI=http://localhost:8888/callback

🎡 Spotify Configuration

πŸ“‹ Step-by-Step Tutorial: Getting Spotify Credentials

Step 1: Access Spotify Developer Dashboard

  1. Go to Spotify Developer Dashboard
  2. Log in with your Spotify account (or create one if you don't have it)

Step 2: Create a New Application

  1. Click "Create App" button
  2. Fill in the application details:
    • App name: Spotify MCP Server (or any name you prefer)
    • App description: MCP Server for Spotify music control
    • Website: http://localhost:8000 (optional)
    • Redirect URI: http://localhost:8888/callback
    • API/SDKs: Select "Web API"
  3. Click "Save"

Step 3: Get Your Credentials

  1. After creating the app, you'll be redirected to your app dashboard
  2. Copy the Client ID (visible on the main page)
  3. Click "Show Client Secret" and copy the Client Secret
  4. ⚠️ Keep these credentials secure! Never share them publicly.

Step 4: Configure Redirect URIs

  1. In your app dashboard, go to "Edit Settings"
  2. Under "Redirect URIs", add: http://localhost:8888/callback
  3. Click "Add" and then "Save"

Step 5: Configure Required Scopes

  1. In your app dashboard, go to "Edit Settings"
  2. Under "User Management", you'll see the scopes section
  3. Important: The following scopes will be requested during authentication:
    • user-read-playback-state - Read playback state
    • user-modify-playback-state - Control playback
    • user-read-currently-playing - Current track
    • playlist-read-private - Private playlists
    • user-library-read - User library
    • user-top-read - Top artists and tracks
    • user-read-recently-played - Recently played tracks
    • user-follow-read - Followed artists
    • user-read-email - User email
    • user-read-private - Private information

Step 6: Update Your .env File

  1. Copy the env.example file to .env
  2. Replace the placeholder values with your actual credentials:
SPOTIFY_CLIENT_ID=your_actual_client_id_here
SPOTIFY_CLIENT_SECRET=your_actual_client_secret_here
SPOTIFY_REDIRECT_URI=http://localhost:8888/callback

Step 7: Test Your Configuration

  1. Start the server: make dev
  2. The first time you use the API, you'll be redirected to Spotify for authentication
  3. Accept the permissions requested by Spotify
  4. You should now be able to control your Spotify music!

πŸ” Security Tips

  • Never commit your .env file to version control
  • Keep your credentials private and secure
  • Use different apps for development and production
  • Regularly rotate your client secret if needed

πŸš€ Usage

Start the server:

make dev

The server will be available at:

πŸ› οΈ Development Guide

πŸ”„ Essential Commands

# Complete server restart
pkill -f "python.*mcp-server" && sleep 2 && make dev

# Kill MCP ports (REQUIRED before run-inspector)
lsof -ti:6274 | xargs kill -9 && lsof -ti:6277 | xargs kill -9

# Check ports in use
lsof -i:6274 && lsof -i:6277

⚠️ IMPORTANT: Always Kill Ports!

BEFORE running make run-inspector, ALWAYS execute:

# Kill MCP ports (REQUIRED)
lsof -ti:6274 | xargs kill -9 && lsof -ti:6277 | xargs kill -9

Why is this necessary?

  • MCP Inspector uses ports 6274 (UI) and 6277 (Proxy)
  • If ports are occupied, Inspector cannot start
  • Previous processes may have left ports in use

🎯 Development Workflow

  1. After Modifying Code:
pkill -f "python.*mcp-server" && sleep 2 && make dev
  1. To Test with MCP Inspector:
lsof -ti:6274 | xargs kill -9 && lsof -ti:6277 | xargs kill -9
make run-inspector

Available commands:

make dev              # Start development server
make install          # Install dependencies
make clean            # Clean temporary files
make test             # Run tests
make lint             # Check code quality
make format           # Format code
make run-inspector    # Run MCP Inspector
make help             # Show help

🎡 MCP Features

Available Tools:

  • play_music - Play music
  • search_tracks - Search tracks
  • get_current_track - Current track
  • get_playlists - List playlists
  • get_recommendations - Recommendations
  • get_user_profile - User profile
  • get_devices - Available devices
  • get_queue - Playback queue
  • get_genres - Music genres
  • get_audio_features - Audio characteristics

Available Resources:

  • spotify://playback/current - Current playback
  • spotify://playlists - User playlists
  • spotify://devices - Devices
  • spotify://genres - Genres
  • spotify://profile - User profile
  • spotify://playback/queue - Playback queue

Resource Templates:

  • spotify://playlist/{playlist_id} - Specific playlist
  • spotify://track/{track_id} - Specific track
  • spotify://artist/{artist_id} - Specific artist
  • spotify://album/{album_id} - Specific album
  • spotify://search/{query} - Search results

πŸ“š API Endpoints

Authentication

  • POST /auth - Authenticate with Spotify
  • POST /auth/reauth - Re-authenticate with configured credentials

Playback

  • GET /current-track - Get current track
  • POST /play - Play music
  • POST /pause - Pause music
  • POST /next - Next track
  • POST /previous - Previous track
  • POST /volume/{volume} - Adjust volume (0-100)
  • POST /seek/{position_ms} - Seek to specific position
  • POST /shuffle - Toggle shuffle mode
  • POST /repeat - Toggle repeat mode

Playlists and Albums

  • GET /playlists - Get user playlists
  • GET /playlist/{playlist_id} - Get playlist tracks
  • GET /albums - Get user saved albums
  • GET /tracks - Get user saved tracks

Artists and Top Tracks

  • GET /artists - Get user favorite artists
  • GET /tracks/top - Get most played tracks

Playback Queue

  • GET /queue - Get current playback queue
  • POST /queue/add - Add track to queue

Devices

  • GET /devices - Get available devices
  • POST /devices/{device_id}/transfer - Transfer playback

Search and Recommendations

  • GET /search/{query} - Search tracks
  • GET /recommendations - Get personalized recommendations
  • GET /genres - Get available music genres

User and Analysis

  • GET /user/profile - Get user profile
  • GET /audio-features/{track_id} - Get audio features

System

  • GET / - Server status
  • GET /health - Health check

πŸ”§ Usage Examples

Play a specific track:

curl -X POST "http://localhost:8000/play" \
  -H "Content-Type: application/json" \
  -d '{"track_uri": "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"}'

Search tracks:

curl "http://localhost:8000/search/bohemian%20rhapsody?limit=5"

Adjust volume:

curl -X POST "http://localhost:8000/volume/50"

Get current track:

curl "http://localhost:8000/current-track"

Get user playlists:

curl "http://localhost:8000/playlists"

Get tracks from a specific playlist:

curl "http://localhost:8000/playlist/37i9dQZF1DXcBWIGoYBM5M"

Get saved tracks:

curl "http://localhost:8000/tracks"

Get favorite artists:

curl "http://localhost:8000/artists"

Get recommendations based on artists:

curl "http://localhost:8000/recommendations?seed_artists=4gzpq5DPGxSnKTe4SA8HAU&limit=10"

Toggle shuffle:

curl -X POST "http://localhost:8000/shuffle"

Add track to queue:

curl -X POST "http://localhost:8000/queue/add?track_uri=spotify:track:4iV5W9uYEdYUVa79Axb7Rh"

Get available devices:

curl "http://localhost:8000/devices"

Seek to specific position (30 seconds):

curl -X POST "http://localhost:8000/seek/30000"

Re-authenticate with Spotify:

curl -X POST "http://localhost:8000/auth/reauth"

πŸš€ CI/CD Pipeline

πŸ“Š Pipeline Status

Our CI/CD pipeline ensures code quality and security:

  • βœ… Tests: 60 tests passing on Python 3.12 & 3.13
  • βœ… Linting: Code quality checks with flake8
  • βœ… Formatting: Black and isort formatting validation
  • βœ… Security: Secrets detection and .env file validation
  • βœ… Build: Package building and artifact generation

πŸ”„ Pipeline Jobs

Job Description Status
Test Run all tests on Python 3.12 & 3.13 Test
Lint Code quality and formatting checks Lint
Security Secrets detection and security validation Security
Build Package building and distribution Build

πŸ›‘οΈ Security Checks

The pipeline includes comprehensive security validation:

  • πŸ” TruffleHog: Advanced secret scanner for detecting credentials
  • πŸ•΅οΈ detect-secrets: Multi-pattern secret detection with baseline
  • πŸ” Pattern Matching: Custom regex patterns for sensitive data
  • πŸ“ File Validation: Checks for committed sensitive files (.env, .key, .pem)
  • βš™οΈ Gitignore Validation: Ensures sensitive file patterns are ignored
  • 🌐 URL Scanning: Detects hardcoded cloud service URLs
  • πŸ“Š Security Reports: Generates detailed security scan artifacts

Protected Patterns:

  • API keys and tokens
  • Passwords and secrets
  • Base64/Hex encoded strings
  • AWS, Google, Azure credentials
  • Private keys and certificates
  • Spotify client credentials

πŸ“‹ Local Pipeline Testing

Test the pipeline locally before pushing:

# Run all pipeline checks locally
make test-pytest    # Tests
make lint          # Linting
make format        # Formatting
make security      # Security checks

πŸ” Security Commands

# Run security checks
make security       # Basic security validation

# Full security scan (requires tools)
pip install detect-secrets truffleHog3
detect-secrets scan --all-files
trufflehog3 --format json .

πŸ§ͺ Tests

βœ… 60 tests PASSING | ⏱️ ~0.38s | πŸ”§ 100% Functional

πŸš€ Run Tests

# Run all tests (recommended)
make test-pytest

# Or use pytest directly
python -m pytest tests/ -v --tb=short --color=yes

πŸ“‹ Test Coverage

πŸ”§ MCP Tools Tests (36 tests)

  • βœ… Playback control (play_music, pause_music, next_track, previous_track)
  • βœ… Volume management (set_volume)
  • βœ… Search and discovery (search_tracks, search_artists, search_albums, search_playlists)
  • βœ… Playlists and albums (get_playlists, get_playlist_tracks, get_album_tracks)
  • βœ… Profile and preferences (get_user_profile, get_top_tracks, get_top_artists)
  • βœ… Personal library (get_saved_tracks, get_saved_albums, get_followed_artists)
  • βœ… Devices and queue (get_devices, get_queue, add_to_queue)
  • βœ… Recommendations (get_recommendations, get_genres, get_audio_features)
  • βœ… Navigation (skip_to_next, skip_to_previous, seek_to_position)
  • βœ… History (get_recently_played)
  • βœ… Related artists (get_related_artists, get_artist_top_tracks, get_artist_albums)

πŸ’¬ MCP Prompts Tests (6 tests)

  • βœ… spotify_assistant - Intelligent music assistant
  • βœ… spotify_usage_guide - Feature usage guide
  • βœ… spotify_troubleshooting - Problem solving

πŸ“š MCP Resources Tests (12 tests)

  • βœ… spotify://playback/current - Current playback state
  • βœ… spotify://playlists/user - User playlists
  • βœ… spotify://devices/available - Available devices
  • βœ… spotify://genres/available - Music genres
  • βœ… spotify://user/profile - User profile
  • βœ… spotify://playback/queue - Playback queue
  • βœ… spotify://user/top-tracks - Top tracks
  • βœ… spotify://user/top-artists - Top artists
  • βœ… spotify://user/recently-played - Recently played
  • βœ… spotify://user/saved-tracks - Saved tracks
  • βœ… spotify://user/saved-albums - Saved albums
  • βœ… spotify://user/followed-artists - Followed artists

πŸ”§ Functionality Tests (3 tests)

  • βœ… Correct tool structure
  • βœ… Valid descriptions in all tools
  • βœ… Error handling implemented

πŸ“Š Validation Tests (2 tests)

  • βœ… Volume request validation
  • βœ… Search request validation

πŸ”— Integration Test (1 test)

  • βœ… Server completeness (tools, prompts, resources)

🎯 Available Test Commands

# Run all tests
make test-pytest           # Using pytest (recommended)

# Specific tests (future)
make test-tools            # Tools tests only
make test-prompts          # Prompts tests only
make test-resources        # Resources tests only
make test-integration      # Integration tests only
make test-coverage         # Check coverage

# Test with detailed output
python -m pytest tests/ -v -s --tb=long

πŸ“ˆ Latest Test Results

===================================== test session starts =====================================
collected 60 items

TestMCPServerBasics βœ… (4/4)
TestMCPTools βœ… (36/36)
TestMCPPrompts βœ… (6/6)
TestMCPResources βœ… (12/12)
TestToolFunctionality βœ… (2/2)
TestErrorHandling βœ… (1/1)
TestDataValidation βœ… (2/2)
TestIntegration βœ… (1/1)

===================================== 60 passed in 0.38s ======================================

πŸ” Test Structure

tests/
β”œβ”€β”€ test_main.py          # All MCP server tests
β”œβ”€β”€ __init__.py           # Module initialization
└── README.md            # Test documentation

πŸ§ͺ How to Add New Tests

  1. For new tool:
@pytest.mark.asyncio
async def test_new_tool_exists(self):
    """Test if new tool exists"""
    tools = await app.get_tools()
    assert 'new_tool' in tools
  1. For new resource:
@pytest.mark.asyncio
async def test_new_resource_exists(self):
    """Test if new resource exists"""
    resources = await app.get_resources()
    assert 'spotify://new/resource' in resources

⚠️ Important for Tests

  • ALWAYS run tests after modifying code
  • Use make test-pytest for fast and reliable execution
  • Tests don't require real Spotify authentication
  • Tests focus on structure and feature availability

πŸ” Linting and Formatting

make lint    # Check code quality
make format  # Format code automatically

πŸ“ Project Structure

mcp-server/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ mcp-server.py    # Main MCP server
β”‚   β”œβ”€β”€ service.py       # Spotify logic
β”‚   β”œβ”€β”€ server.py        # FastAPI server
β”‚   └── config.py        # Configuration
β”œβ”€β”€ tests/               # Tests
β”œβ”€β”€ makefile             # Development commands
β”œβ”€β”€ pyproject.toml       # Project configuration

β”œβ”€β”€ env.example          # Environment variables example
└── README.md           # This file

⚠️ Common Issues

Error: "PORT IS IN USE"

# Quick solution
lsof -ti:6274 | xargs kill -9
lsof -ti:6277 | xargs kill -9

Error: "ModuleNotFoundError"

# Reinstall dependencies
make install

Server not responding

# Complete restart
pkill -f "python.*mcp-server" && sleep 2 && make dev

Error 403 - Insufficient Permission

If you receive error 403 with message "Insufficient client scope":

  1. Verify all required scopes are configured
  2. Re-authenticate with Spotify using /auth endpoint
  3. Make sure you accepted all requested permissions

Endpoints Requiring Specific Permissions

  • /artists and /tracks/top - Require user-top-read
  • /recommendations - Require at least one valid seed
  • /user/profile - Require user-read-email and user-read-private

Known Issues

  • Recommendations (404): The recommendations API may return 404 in some cases. This can be due to:
    • Temporary Spotify API issues
    • Invalid or not found seeds
    • Authentication problems
  • Solution: Use /auth/reauth endpoint to re-authenticate if necessary

πŸ”§ Important Tips

  1. ALWAYS restart server after modifying mcp-server.py
  2. ALWAYS kill ports before running Inspector (6274 and 6277)
  3. ALWAYS verify ports are free before running make run-inspector
  4. Check logs to identify problems
  5. Use make dev for local development
  6. Keep .env properly configured

🀝 Contributing

We welcome contributions! Please follow these steps:

πŸš€ Development Workflow

  1. Fork the project
  2. Create a feature branch:
    git checkout -b feature/AmazingFeature
  3. Make your changes and test locally:
    make test-pytest    # Run tests
    make lint          # Check code quality
    make format        # Format code
  4. Commit your changes:
    git commit -m 'Add some AmazingFeature'
  5. Push to your branch:
    git push origin feature/AmazingFeature
  6. Open a Pull Request

βœ… CI/CD Requirements

All contributions must pass our CI/CD pipeline:

  • Tests: All 60 tests must pass
  • Linting: Code must pass flake8 checks
  • Formatting: Code must be properly formatted with Black
  • Security: No secrets or sensitive files committed
  • Build: Package must build successfully

πŸ›‘οΈ Security Guidelines

  • Never commit .env files or credentials
  • Use placeholders in examples (e.g., your_client_id_here)
  • Follow the security checklist in SECURITY.md
  • Test locally before pushing

πŸ“‹ Code Quality Standards

  • Python 3.12+ compatibility
  • Type hints for all functions
  • Docstrings for all public functions
  • Error handling for all external API calls
  • Tests for new functionality

πŸ“„ License

This project is under MIT license. See the LICENSE file for more details.

πŸ†˜ Support

If you encounter any problems or have questions:

  1. Check if Spotify credentials are correct
  2. Make sure Spotify is running on some device
  3. Check server logs for more details
  4. Open an issue in the repository

πŸ”— Useful Links


🎡 Music is life! Let's make an amazing MCP server! πŸš€

About

MCP Server with Spotipy integration for music control via Spotify

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors