Spotify CLI player powered by Laravel Zero and spotifyd. Controls Spotify playback from the terminal. Play music, manage the queue, search the catalog, control volume and playback modes.
The server has 15 well-named tools with mostly complete descriptions and basic schemas. Naming is strong (verb_noun patterns: current, devices, pause, play, queue_add, queue_show, repeat, resume, search, session_adjust, session_start, session_status, shuffle, skip, volume). Most descriptions are present and in the 50-200 char range recommended for LLM optimization. However, several critical gaps limit production readiness: (1) Parameter schemas are incomplete, many tools lack explicit input schema definitions visible in source; (2) Output schemas are undocumented, responses are free-text or partially structured with no documented return types; (3) Error handling lacks recovery guidance, no indication of retryable vs fatal errors, no suggestions for what to do on failure; (4) No tool annotations beyond IsReadOnly/IsIdempotent visible on some tools; (5) Session-based tools (session_start, session_adjust, session_status) create implicit state management not reflected in tool contracts. CurrentTool and DevicesTool exemplify the pattern: clear names, good descriptions, but Response.text() returns unstructured output with no documented schema. PlayTool shows schema() method exists but source is truncated. SearchTool declares input types (query string, type enum, limit int) but output structure is not visible in provided code. Most tools inherit HandlesAuthErrors trait, suggesting consistent error handling, but error response content is not visible. The average tool description length appears ~120-150 chars (within baseline), but several tools like pause, resume, devices are quite terse (25-40 chars), below the 50-char minimum for LLM clarity.
Get the currently playing track, artist, album, progress, and playback state
List available Spotify playback devices
Pause Spotify playback
Search for and play a song, artist, album, or playlist on Spotify
Search for a track and add it to the Spotify queue
Show upcoming tracks in the Spotify queue
Set repeat mode: off (no repeat), track (repeat current song), or context (repeat album/playlist)
Output schemas completely undocumented. Tools return Response.text() with free-form strings (e.g., CurrentTool returns 'Track by Artist\nAlbum: X\nProgress: Y / Z\n...'). LLMs cannot plan downstream calls or extract structured data when output format is unknown. This violates pattern:response-shaper and pattern:tool.
Minimal parameter descriptions on several tools. 'pause' has {} input (no parameters, no description of what it acts on, current playback assumed). 'resume' similarly provides no schema or description of scope. According to rubric, parameters without descriptions cannot exceed 20 points for description and 0 for schema.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 61 | 2026-07-28+ | v2 |
Resume Spotify playback from where it was paused
Search the Spotify catalog for tracks, artists, albums, or playlists
Adjust the current music session. Give feedback like "more energy", "too intense", "add some jazz", "shift to something darker" and the AI will adapt the remaining session.
Start a music session. Describe the vibe you want (e.g. "chill focus for coding", "start mellow then build to high energy") and AI agents will plan phases, pick tracks, and queue everything to Spotify.
Check the current music session status — what phase you are in, what is playing, and how much time is left.
Toggle or set shuffle mode. Omit enabled to toggle.
Skip to the next or previous track
Get or set Spotify volume. Omit level to get current volume.
Implicit session state not reflected in tool signatures. session_start creates a session context; session_adjust and session_status operate on that context, but no session_id parameter is visible in input schemas. This creates hidden dependencies and makes tools non-composable, an LLM cannot tell if session_adjust applies to the session just started or a different one.
Error handling invisible in provided code. HandlesAuthErrors trait is used, but error responses are not shown. No evidence of retryable vs fatal error classification (pattern:error-classification), recovery guidance (pattern:recovery-guide), or actionable error messages. LLM cannot distinguish between transient failures (retry) and permanent issues (ask user).
Sparse descriptions on write operations. 'pause' and 'resume' descriptions are under 30 chars. 'Pause Spotify playback' does not explain scope (pause on current device? all devices?), confirmation behavior, or idempotency.
Optional parameter semantics unclear. 'volume' tool has optional 'level' parameter (get if omitted, set if provided). 'shuffle' has optional 'enabled' parameter (toggle if omitted, set if provided). Descriptions should explicitly state: 'Omit level to read current volume; provide level (0-100) to set it.'
No documented parameter ranges or constraints. 'search' limit defaults to 5 but description says '(1-20)' without min/max in schema. 'volume' level should be 0-100, 'session_start' duration should have bounds.
Tool annotations incomplete. Only IsReadOnly and IsIdempotent visible on some tools (CurrentTool, DevicesTool, RepeatTool use them). Destructive tools (pause, play, skip, volume, repeat) and those with side effects should declare destructiveHint or similar. Per current MCP spec, tool annotations improve LLM decision-making.
No pagination or result limits documented. 'search' returns up to 20 results (inferred from limit param), 'queue_show' and 'devices' do not declare limits. Per mxe:enforce-result-limits, large result sets blow context. Should document: 'Returns up to N items; if more exist, return a next_cursor for pagination.'