An MCP server that provides tools for controlling and querying Spotify playback, searching tracks, and managing user profiles. Supports OAuth 2.0 authentication via Spotify and Better Auth.
This Spotify MCP server has significant gaps in definition quality. While all 9 tools are explicitly registered with names and descriptions, the implementation lacks critical schema documentation, parameter descriptions, and error handling guidance. Most tools have empty input schemas (no parameters defined), making it impossible for LLMs to understand what inputs they accept. Descriptions are present but generic and do not explain when to use each tool or what it returns. The server uses a stateful session model (`(server as any)._currentSession`) which is problematic for protocol compliance. No input validation, error recovery guidance, or output schema documentation is visible.
Get information about the user's currently playing track on Spotify
Get the user's Spotify profile information
Pause the user's Spotify playback
Play a specific track by name. Searches for the track and plays the first result.
Resume the user's Spotify playback
Search for tracks on Spotify
Set the volume for the user's Spotify playback
Most tools (7 of 9) have NO input schema at all. Five tools (getCurrentlyPlaying, pausePlayback, resumePlayback, skipToNext, skipToPrevious, getUserProfile) have empty {} schemas. Per hard scoring rules, schema score MUST be 0 for tools with no/empty schemas. This prevents LLMs from understanding what inputs these tools accept.
Parameter descriptions are missing from tool schemas. setVolume has a 'volume' parameter but the inputSchema only shows Zod type `z.number()` with no inline description. searchTracks and playTrack have similar issues, the description text 'Maximum number of results to return (1-50, default 10)' appears in the evaluation prompt but not in visible schema definitions. LLMs cannot read Zod validators; they only see JSON Schema with explicit 'description' fields.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-21 | F | 45 | <=2025-11-25 | v2 |
| 2026-03-09 | D | 51 | - | v1 |
Skip to the next track in the user's Spotify queue
Skip to the previous track in the user's Spotify queue
Stateful session management via `(server as any)._currentSession` violates MCP spec statelessness. All 9 tools depend on this hidden session state. Modern MCP (2026-07-28) requires each request to be self-contained and carry authentication via protocol metadata, not server-side state. This breaks compatibility with stateless MCP clients and makes the server non-portable across multiple concurrent agents.
No error recovery guidance. Tools return generic errors like 'No authenticated session found' and 'No track found' but do not tell the LLM what to do next. Per pattern:recovery-guide, error messages should suggest next steps (e.g., 'No authenticated session found. Re-authenticate and retry.' or 'No track found for X. Try: searchTracks(X) first to find available tracks.').
Output schemas are undocumented. Tools return Content arrays with untyped text blocks (e.g., getCurrentlyPlaying returns 4 text blocks about the track). LLMs cannot parse or structure this untyped output. Per pattern:response-shaper, document return structure so agents know what fields to expect and can chain results into downstream tools.
No idempotency guarantees or confirmation for destructive operations. pausePlayback, resumePlayback, skipToNext, skipToPrevious, setVolume, and playTrack are write operations that modify user playback state. No dry-run, confirmation, or idempotency hints (destructiveHint in tool annotations) are present. If an agent retries due to timeout/ambiguity, the operation may execute twice.
No tool annotations. Tools lack readOnlyHint and destructiveHint flags. Modern MCP (2026-07-28) expects tools to declare these properties so agents can reason about safety and idempotency. Example: pausePlayback should have destructiveHint: true.
Spotify credentials/tokens are presumably stored server-side and accessed via session state, but no explicit pattern:secret-injection is documented. If authentication tokens are ever exposed in parameters, error messages, or responses, they leak into LLM logs. Verify tokens are never returned in tool responses and access is always server-side.
searchTracks returns a hardcoded limit result (validLimit = Math.max(1, Math.min(50, limit || 10))) but does not return pagination metadata (total count, next_cursor). Per pattern:paginated-result, large result sets should include pagination info so agents can fetch additional pages if needed.