MCP (Model Context Protocol) Server with Spotipy integration for music control via Spotify.
- ✅ 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
- Python 3.12+
- Spotify Developer account
- Registered application in Spotify Developer Dashboard
- Clone the repository:
git clone https://github.com/jadilson12/spotify-mcp-server
cd spotify-mcp-server- Install dependencies:
make install- Configure environment variables:
cp env.example .envEdit 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- Go to Spotify Developer Dashboard
- Log in with your Spotify account (or create one if you don't have it)
- Click "Create App" button
- 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"
- App name:
- Click "Save"
- After creating the app, you'll be redirected to your app dashboard
- Copy the Client ID (visible on the main page)
- Click "Show Client Secret" and copy the Client Secret
⚠️ Keep these credentials secure! Never share them publicly.
- In your app dashboard, go to "Edit Settings"
- Under "Redirect URIs", add:
http://localhost:8888/callback - Click "Add" and then "Save"
- In your app dashboard, go to "Edit Settings"
- Under "User Management", you'll see the scopes section
- Important: The following scopes will be requested during authentication:
user-read-playback-state- Read playback stateuser-modify-playback-state- Control playbackuser-read-currently-playing- Current trackplaylist-read-private- Private playlistsuser-library-read- User libraryuser-top-read- Top artists and tracksuser-read-recently-played- Recently played tracksuser-follow-read- Followed artistsuser-read-email- User emailuser-read-private- Private information
- Copy the
env.examplefile to.env - 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- Start the server:
make dev - The first time you use the API, you'll be redirected to Spotify for authentication
- Accept the permissions requested by Spotify
- You should now be able to control your Spotify music!
- Never commit your
.envfile to version control - Keep your credentials private and secure
- Use different apps for development and production
- Regularly rotate your client secret if needed
make devThe server will be available at:
- API: http://localhost:8000
- Documentation: http://localhost:8000/docs
- Health Check: http://localhost:8000/health
# 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:6277BEFORE running make run-inspector, ALWAYS execute:
# Kill MCP ports (REQUIRED)
lsof -ti:6274 | xargs kill -9 && lsof -ti:6277 | xargs kill -9Why 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
- After Modifying Code:
pkill -f "python.*mcp-server" && sleep 2 && make dev- To Test with MCP Inspector:
lsof -ti:6274 | xargs kill -9 && lsof -ti:6277 | xargs kill -9
make run-inspectormake 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 helpplay_music- Play musicsearch_tracks- Search tracksget_current_track- Current trackget_playlists- List playlistsget_recommendations- Recommendationsget_user_profile- User profileget_devices- Available devicesget_queue- Playback queueget_genres- Music genresget_audio_features- Audio characteristics
spotify://playback/current- Current playbackspotify://playlists- User playlistsspotify://devices- Devicesspotify://genres- Genresspotify://profile- User profilespotify://playback/queue- Playback queue
spotify://playlist/{playlist_id}- Specific playlistspotify://track/{track_id}- Specific trackspotify://artist/{artist_id}- Specific artistspotify://album/{album_id}- Specific albumspotify://search/{query}- Search results
POST /auth- Authenticate with SpotifyPOST /auth/reauth- Re-authenticate with configured credentials
GET /current-track- Get current trackPOST /play- Play musicPOST /pause- Pause musicPOST /next- Next trackPOST /previous- Previous trackPOST /volume/{volume}- Adjust volume (0-100)POST /seek/{position_ms}- Seek to specific positionPOST /shuffle- Toggle shuffle modePOST /repeat- Toggle repeat mode
GET /playlists- Get user playlistsGET /playlist/{playlist_id}- Get playlist tracksGET /albums- Get user saved albumsGET /tracks- Get user saved tracks
GET /artists- Get user favorite artistsGET /tracks/top- Get most played tracks
GET /queue- Get current playback queuePOST /queue/add- Add track to queue
GET /devices- Get available devicesPOST /devices/{device_id}/transfer- Transfer playback
GET /search/{query}- Search tracksGET /recommendations- Get personalized recommendationsGET /genres- Get available music genres
GET /user/profile- Get user profileGET /audio-features/{track_id}- Get audio features
GET /- Server statusGET /health- Health check
curl -X POST "http://localhost:8000/play" \
-H "Content-Type: application/json" \
-d '{"track_uri": "spotify:track:4iV5W9uYEdYUVa79Axb7Rh"}'curl "http://localhost:8000/search/bohemian%20rhapsody?limit=5"curl -X POST "http://localhost:8000/volume/50"curl "http://localhost:8000/current-track"curl "http://localhost:8000/playlists"curl "http://localhost:8000/playlist/37i9dQZF1DXcBWIGoYBM5M"curl "http://localhost:8000/tracks"curl "http://localhost:8000/artists"curl "http://localhost:8000/recommendations?seed_artists=4gzpq5DPGxSnKTe4SA8HAU&limit=10"curl -X POST "http://localhost:8000/shuffle"curl -X POST "http://localhost:8000/queue/add?track_uri=spotify:track:4iV5W9uYEdYUVa79Axb7Rh"curl "http://localhost:8000/devices"curl -X POST "http://localhost:8000/seek/30000"curl -X POST "http://localhost:8000/auth/reauth"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
| Job | Description | Status |
|---|---|---|
| Test | Run all tests on Python 3.12 & 3.13 | |
| Lint | Code quality and formatting checks | |
| Security | Secrets detection and security validation | |
| Build | Package building and distribution |
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
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# 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 .✅ 60 tests PASSING | ⏱️ ~0.38s | 🔧 100% Functional
# Run all tests (recommended)
make test-pytest
# Or use pytest directly
python -m pytest tests/ -v --tb=short --color=yes- ✅ 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)
- ✅
spotify_assistant- Intelligent music assistant - ✅
spotify_usage_guide- Feature usage guide - ✅
spotify_troubleshooting- Problem solving
- ✅
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
- ✅ Correct tool structure
- ✅ Valid descriptions in all tools
- ✅ Error handling implemented
- ✅ Volume request validation
- ✅ Search request validation
- ✅ Server completeness (tools, prompts, resources)
# 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===================================== 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 ======================================
tests/
├── test_main.py # All MCP server tests
├── __init__.py # Module initialization
└── README.md # Test documentation
- 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- 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- ALWAYS run tests after modifying code
- Use
make test-pytestfor fast and reliable execution - Tests don't require real Spotify authentication
- Tests focus on structure and feature availability
make lint # Check code quality
make format # Format code automaticallymcp-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
# Quick solution
lsof -ti:6274 | xargs kill -9
lsof -ti:6277 | xargs kill -9# Reinstall dependencies
make install# Complete restart
pkill -f "python.*mcp-server" && sleep 2 && make devIf you receive error 403 with message "Insufficient client scope":
- Verify all required scopes are configured
- Re-authenticate with Spotify using
/authendpoint - Make sure you accepted all requested permissions
/artistsand/tracks/top- Requireuser-top-read/recommendations- Require at least one valid seed/user/profile- Requireuser-read-emailanduser-read-private
- 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/reauthendpoint to re-authenticate if necessary
- ALWAYS restart server after modifying
mcp-server.py - ALWAYS kill ports before running Inspector (6274 and 6277)
- ALWAYS verify ports are free before running
make run-inspector - Check logs to identify problems
- Use
make devfor local development - Keep
.envproperly configured
We welcome contributions! Please follow these steps:
- Fork the project
- Create a feature branch:
git checkout -b feature/AmazingFeature
- Make your changes and test locally:
make test-pytest # Run tests make lint # Check code quality make format # Format code
- Commit your changes:
git commit -m 'Add some AmazingFeature' - Push to your branch:
git push origin feature/AmazingFeature
- Open a Pull Request
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
- Never commit
.envfiles or credentials - Use placeholders in examples (e.g.,
your_client_id_here) - Follow the security checklist in
SECURITY.md - Test locally before pushing
- 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
This project is under MIT license. See the LICENSE file for more details.
If you encounter any problems or have questions:
- Check if Spotify credentials are correct
- Make sure Spotify is running on some device
- Check server logs for more details
- Open an issue in the repository
🎵 Music is life! Let's make an amazing MCP server! 🚀