An MCP server that provides tools to interact with Spotify API, enabling playback control, search, playlist management, and user personalization features
This MCP server has significant quality gaps across naming, descriptions, and schemas. All 21 tools are explicitly defined in main.py with @mcp.tool() decorators and have basic docstrings, but descriptions are uniformly generic (10-20 chars) and lack actionable LLM-optimization guidance. Input schemas are inferred from Python function signatures (using fastmcp's automatic schema generation from type hints) but are not explicitly visible in the source code as JSON Schema objects. Parameters lack detailed constraint descriptions, enums are missing where appropriate, and output schemas are completely undocumented. Error handling is absent, all tools return raw string responses with no structured error classification or recovery guidance. The tool set is well-scoped (21 focused Spotify operations) but lacks the polish and LLM-alignment expected of production tools.
Add tracks to a playlist
Add a track to the queue
Get top tracks for an artist
Get information about the currently playing track
Get detailed information about a Spotify item
FastMCP tool to get user playlists using SpotifyClient.
Get current playback information
Generic, LLM-unfriendly descriptions (10 - 25 chars). Examples: 'Skip to next track in queue' (27 chars), 'Get current playback information' (31 chars), 'Go back to previous track' (25 chars). Too terse to guide LLM selection and lack context about when to call vs similar tools (e.g., next_track vs skip_tracks). Descriptions should be 50 - 200 chars, explaining WHAT, WHEN, and any prerequisites.
Input schemas are not explicitly documented or visible in source code. Schemas are inferred from Python type hints via fastmcp's automatic schema generation. This violates the principle that tool definitions must be completely visible and machine-readable. JSON Schema constraints (min/max, enums, patterns) cannot be verified.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 44 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 38 | - | v1 |
Get the current queue of tracks
Get Spotify recommendations based on seeds
Get user's top artists from Spotify
Skip to next track in queue
FastMCP tool to pause playback on spotify.
Go back to previous track
Reorder tracks in queue by moving a track to a different position
Search Spotify for tracks, artists, albums, or playlists.
Seek to position in current track
Set repeat mode for playback
Skip multiple tracks at once
FastMCP tool to resume playback on the currently active Spotify device.
Start playback of a specific track on Spotify
Start playback of a specific playlist
Missing enum constraints on parameters that accept one of a known set. Examples: 'type' in search_spotify (should be enum: track|artist|album|playlist), 'state' in set_repeat_mode (should be enum: track|context|off), 'time_range' in get_top_artists (should be enum: short_term|medium_term|long_term). Free-form strings invite hallucinated values.
Output schemas are completely undocumented. All tools return 'str' with no schema definition. LLMs cannot plan downstream calls or extract structured data. Examples: get_my_playlists should document returning a list of playlist objects with {name, tracks, id}; search_spotify should document the search result structure; get_recommendations should document recommendation fields.
No error handling or recovery guidance. All tools return raw string responses (either success message or generic 'Error fetching X: {str(e)}'). LLMs receive no classification of errors as retryable, user-fixable, or fatal. Examples: start_playback returns generic error if no device is active; seek_position returns error if track duration is exceeded; add_to_queue returns error if track_id is invalid. Each needs actionable recovery (e.g., 'No active device. Try calling get_playback_state() first to see available devices.').
Parameter descriptions are minimal or missing. Examples: 'position_ms' in seek_position lacks units and range (must be 0 - track_duration); 'type' in get_item_info lacks the enum constraint (track|album|artist|playlist); 'track_uri' in start_playback_track lacks format example (spotify:track:XXXXXX); 'device_id' in multiple tools lacks documentation of when it's required vs optional. Descriptions should answer: What is this? What format? What range? What happens if omitted?
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). These are recommended patterns in the current MCP spec for guiding agent behavior. Destructive tools like delete should be marked. Read-only tools (get_*, search_*) should be marked for safe retry logic.
No pagination support for result-heavy tools. get_my_playlists, get_recommendations, get_queue, search_spotify should support limit/offset and return result counts. Without pagination, large results risk exhausting the context window. Current search_spotify has a limit param (good) but returns everything without a total count or next_cursor.
Spotify API authentication credentials (SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET, SPOTIFY_REDIRECT_URI) are loaded from environment variables in spotify.py. While this is correct pattern (server-side secret injection), the implementation does not validate these are set before initialization. A missing credential will cause a runtime error on first tool call rather than early feedback.
No validation of input parameters. Examples: seek_position(position_ms) does not validate position_ms >= 0 or <= track duration; set_repeat_mode(state) does not validate state ∈ {track, context, off}; skip_tracks(num_skips) does not validate num_skips > 0. Invalid inputs silently fail with generic error messages.