search_tracks
Search Spotify for tracks, albums, artists, or playlists using queries and filters like year, genre, or artist to find specific music content.
Instructions
Search Spotify for tracks, albums, artists, or playlists.
Args:
query: Search query
qtype: Type ('track', 'album', 'artist', 'playlist')
limit: Max results per page (1-50, default 10)
offset: Number of results to skip for pagination (default 0)
year: Filter by year (e.g., '2024')
year_range: Filter by year range (e.g., '2020-2024')
genre: Filter by genre (e.g., 'electronic', 'hip-hop')
artist: Filter by artist name
album: Filter by album name
Returns:
Dict with 'items' (list of tracks) and pagination info ('total', 'limit', 'offset')
Note: Filters use Spotify's search syntax. For large result sets, use offset to paginate.
Example: query='love', year='2024', genre='pop' searches for 'love year:2024 genre:pop'
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| qtype | No | track | |
| limit | No | ||
| offset | No | ||
| year | No | ||
| year_range | No | ||
| genre | No | ||
| artist | No | ||
| album | No |
Implementation Reference
- The primary handler function for the 'search_tracks' MCP tool. It performs Spotify searches via spotipy.client.search(), applies filters, parses results into Track models using parse_track helper, handles pagination, and logs execution. Decorated with @mcp.tool() for automatic FastMCP registration.@log_tool_execution def search_tracks( query: str, qtype: str = "track", limit: int = 10, offset: int = 0, year: str | None = None, year_range: str | None = None, genre: str | None = None, artist: str | None = None, album: str | None = None, ) -> dict[str, Any]: """Search Spotify for tracks, albums, artists, or playlists. Args: query: Search query qtype: Type ('track', 'album', 'artist', 'playlist') limit: Max results per page (1-50, default 10) offset: Number of results to skip for pagination (default 0) year: Filter by year (e.g., '2024') year_range: Filter by year range (e.g., '2020-2024') genre: Filter by genre (e.g., 'electronic', 'hip-hop') artist: Filter by artist name album: Filter by album name Returns: Dict with 'items' (list of tracks) and pagination info ('total', 'limit', 'offset') Note: Filters use Spotify's search syntax. For large result sets, use offset to paginate. Example: query='love', year='2024', genre='pop' searches for 'love year:2024 genre:pop' """ try: limit = max(1, min(50, limit)) # Build filtered query filters = [] if artist: filters.append(f"artist:{artist}") if album: filters.append(f"album:{album}") if year: filters.append(f"year:{year}") if year_range: filters.append(f"year:{year_range}") if genre: filters.append(f"genre:{genre}") full_query = " ".join([query] + filters) if filters else query logger.info( f"🔍 Searching {qtype}s: '{full_query}' (limit={limit}, offset={offset})" ) result = spotify_client.search(q=full_query, type=qtype, limit=limit, offset=offset) tracks = [] items_key = f"{qtype}s" result_section = result.get(items_key, {}) if qtype == "track" and result_section.get("items"): tracks = [parse_track(item) for item in result_section["items"]] else: # Convert other types to track-like format for consistency if result_section.get("items"): for item in result_section["items"]: track = Track( name=item["name"], id=item["id"], artist=item.get("artists", [{}])[0].get("name", "Unknown") if qtype != "artist" else item["name"], external_urls=item.get("external_urls"), ) tracks.append(track) total_results = result_section.get("total", 0) logger.info( f"🔍 Search returned {len(tracks)} items (total available: {total_results})" ) log_pagination_info("search_tracks", total_results, limit, offset) return { "items": tracks, "total": total_results, "limit": result_section.get("limit", limit), "offset": result_section.get("offset", offset), "next": result_section.get("next"), "previous": result_section.get("previous"), } except SpotifyException as e: raise convert_spotify_error(e) from e
- Pydantic BaseModel defining the Track schema used for structuring search results output in search_tracks.class Track(BaseModel): """A Spotify track with metadata.""" name: str id: str artist: str artists: list[str] | None = None album: str | None = None album_id: str | None = None release_date: str | None = None duration_ms: int | None = None popularity: int | None = None external_urls: dict[str, str] | None = None
- Helper function parse_track that converts raw Spotify track dict to Track Pydantic model, used within search_tracks for result processing.def parse_track(item: dict[str, Any]) -> Track: """Parse Spotify track data into Track model.""" album_data = item.get("album", {}) return Track( name=item["name"], id=item["id"], artist=item["artists"][0]["name"] if item.get("artists") else "Unknown", artists=[a["name"] for a in item.get("artists", [])], album=album_data.get("name"), album_id=album_data.get("id"), release_date=album_data.get("release_date"), duration_ms=item.get("duration_ms"), popularity=item.get("popularity"), external_urls=item.get("external_urls"), )
- src/spotify_mcp/fastmcp_server.py:272-272 (registration)FastMCP decorators @mcp.tool() registers search_tracks as an MCP tool, and @log_tool_execution adds logging.@log_tool_execution