Skip to main content
Glama
boristopalov

Spotify MCP Server

by boristopalov

SpotifyPlayback

Control Spotify playback: get current track info, start or resume music, pause playback, or skip tracks using the Spotify MCP Server.

Instructions

Manages the current playback with the following actions: - get: Get information about user's current track. - start: Starts of resumes playback. - pause: Pauses current playback. - skip: Skips current track.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction to perform: 'get', 'start', 'pause' or 'skip'.
track_idNoSpecifies track to play for 'start' action. If omitted, resumes current playback.
num_skipsNoNumber of tracks to skip for `skip` action.

Implementation Reference

  • Handler logic for the 'SpotifyPlayback' tool inside handle_call_tool(), dispatching actions to Spotify API client methods: get_current_track(), start_playback(), pause_playback(), skip_track().
    case "Playback":
        action = arguments.get("action")
        match action:
            case "get":
                logger.info("Attempting to get current track")
                curr_track = spotify_client.get_current_track()
                if curr_track:
                    logger.info(f"Current track retrieved: {curr_track.get('name', 'Unknown')}")
                    return [types.TextContent(
                        type="text",
                        text=json.dumps(curr_track, indent=2)
                    )]
                logger.info("No track currently playing")
                return [types.TextContent(
                    type="text",
                    text="No track playing."
                )]
            case "start":
                logger.info(f"Starting playback with arguments: {arguments}")
                spotify_client.start_playback(track_id=arguments.get("track_id"))
                logger.info("Playback started successfully")
                return [types.TextContent(
                    type="text",
                    text="Playback starting with no errors."
                )]
            case "pause":
                logger.info("Attempting to pause playback")
                spotify_client.pause_playback()
                logger.info("Playback paused successfully")
                return [types.TextContent(
                    type="text",
                    text="Playback paused successfully."
                )]
            case "skip":
                num_skips = int(arguments.get("num_skips", 1))
                logger.info(f"Skipping {num_skips} tracks.")
                spotify_client.skip_track(n=num_skips)
                return [types.TextContent(
                    type="text",
                    text="Skipped to next track."
                )]
  • Pydantic model defining the input schema for SpotifyPlayback tool, used to generate the tool schema via model_json_schema().
    class Playback(ToolModel):
        """Manages the current playback with the following actions:
        - get: Get information about user's current track.
        - start: Starts of resumes playback.
        - pause: Pauses current playback.
        - skip: Skips current track.
        """
        action: str = Field(description="Action to perform: 'get', 'start', 'pause' or 'skip'.")
        track_id: Optional[str] = Field(default=None, description="Specifies track to play for 'start' action. If omitted, resumes current playback.")
        num_skips: Optional[int] = Field(default=1, description="Number of tracks to skip for `skip` action.")
  • Registers the SpotifyPlayback tool (as 'SpotifyPlayback') by including Playback.as_tool() in the list returned by list_tools().
    @server.list_tools()
    async def handle_list_tools() -> list[types.Tool]:
        """List available tools."""
        logger.info("Listing available tools")
        tools = [
            Playback.as_tool(),
            Search.as_tool(),
            Queue.as_tool(),
            GetInfo.as_tool(),
        ]
        logger.info(f"Available tools: {[tool.name for tool in tools]}")
        return tools
  • Core helper method get_current_track() in SpotifyClient, called by 'get' action.
    def get_current_track(self) -> Optional[Dict]:
        """Get information about the currently playing track"""
        try:
            # current_playback vs current_user_playing_track?
            current = self.sp.current_user_playing_track()
            if not current:
                self.logger.info("No playback session found")
                return None
            if current.get('currently_playing_type') != 'track':
                self.logger.info("Current playback is not a track")
                return None
    
            track_info = utils.parse_track(current['item'])
            if 'is_playing' in current:
                track_info['is_playing'] = current['is_playing']
    
            self.logger.info(
                f"Current track: {track_info.get('name', 'Unknown')} by {track_info.get('artist', 'Unknown')}")
            return track_info
        except Exception as e:
            self.logger.error("Error getting current track info", exc_info=True)
            raise
  • Core helper method start_playback() in SpotifyClient, called by 'start' action to start/resume playback with optional track_id. Includes validation decorator. (excerpt omitted for length)
    def start_playback(self, track_id=None, device=None):
        """
        Starts track playback. If track_id is omitted, resumes current playback.
        - track_id: ID of track to play, or None.
        """
        try:
            if not track_id:
                if self.is_track_playing():
                    self.logger.info("No track_id provided and playback already active.")
                    return
                if not self.get_current_track():
                    raise ValueError("No track_id provided and no current playback to resume.")
    
            uris = [f'spotify:track:{track_id}'] if track_id else None
            device_id = device.get('id') if device else None
    
            result = self.sp.start_playback(uris=uris, device_id=device_id)
            self.logger.info(f"Playback started successfully{' for track_id: ' + track_id if track_id else ''}")
            return result
        except Exception as e:
            self.logger.error(f"Error starting playback: {str(e)}", exc_info=True)
            raise

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/boristopalov/spotify-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server