search_tracks
Search Spotify for tracks, albums, artists, or playlists using keywords, genre, year, and other filters. Get paginated results to browse through large collections.
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
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| qtype | No | track | |
| limit | No | ||
| offset | No | ||
| year | No | ||
| year_range | No | ||
| genre | No | ||
| artist | No | ||
| album | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- Main handler function for the search_tracks tool. Decorated with @mcp.tool() and @log_tool_execution. Accepts query, qtype, limit, offset, year, year_range, genre, artist, album parameters. Builds filtered query using Spotify search syntax, calls spotify_client.search(), parses results using parse_track() for tracks or constructs Track objects for other types, and returns paginated results.
@mcp.tool() @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 model defining the output schema for track data returned by 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 - src/spotify_mcp/fastmcp_server.py:271-271 (registration)Registration via the @mcp.tool() decorator on the FastMCP instance, which automatically registers search_tracks as an MCP tool.
@mcp.tool() - Helper function used by search_tracks to parse raw Spotify track data into the Track Pydantic model.
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"), )