search_and_add_show
Search for TV shows using natural language descriptions and optionally add them to Sonarr automatically when only one result is found.
Instructions
Search for TV shows using natural language description and optionally add to Sonarr.
Args: description: Natural language description of the TV show (e.g., "British time travel show with the Doctor") auto_add: If True and only one result found, automatically add to Sonarr
Returns: List of matching TV shows with metadata
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| description | Yes | ||
| auto_add | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/arr_assistant_mcp/main.py:387-387 (registration)Registration of the 'search_and_add_show' tool via @mcp.tool decorator (FastMCP).
@mcp.tool - src/arr_assistant_mcp/main.py:387-431 (handler)The handler function for the 'search_and_add_show' tool. Searches Sonarr via natural language description, returns top 5 results as MediaSearchResult objects, and optionally auto-adds if only one result found.
@mcp.tool async def search_and_add_show( description: str, auto_add: bool = False ) -> list[MediaSearchResult]: """ Search for TV shows using natural language description and optionally add to Sonarr. Args: description: Natural language description of the TV show (e.g., "British time travel show with the Doctor") auto_add: If True and only one result found, automatically add to Sonarr Returns: List of matching TV shows with metadata """ if not config: raise ValueError("Server not configured. Please set up Sonarr API key.") async with MediaServerAPI(config) as api: # Search for TV shows using Sonarr lookup tv_results = await api.search_sonarr_shows(description) results = [] for show in tv_results[:5]: # Limit to top 5 results result = MediaSearchResult( title=show.get("title") or "Unknown", year=show.get("year"), overview=show.get("overview") or "No overview available", tmdb_id=show.get("tmdbId"), tvdb_id=show.get("tvdbId"), poster_path=show.get("remotePoster"), media_type="tv" ) results.append(result) # Auto-add if requested and only one result if auto_add and len(results) == 1: show = results[0] if show.tvdb_id: add_result = await api.add_series_to_sonarr(show.tvdb_id, show.title) logger.info("Auto-add result for '%s': %s", show.title, add_result.model_dump()) else: logger.warning(f"Cannot auto-add '{show.title}' - no TVDB ID available") return results - src/arr_assistant_mcp/main.py:37-44 (schema)Schema/model for the search result returned by search_and_add_show (and other search tools).
class MediaSearchResult(BaseModel): title: str year: int | None = None overview: str tmdb_id: int | None = None tvdb_id: int | None = None poster_path: str | None = None media_type: str # "movie" or "tv" - Helper method on MediaServerAPI that queries Sonarr's /api/v3/series/lookup endpoint to search for TV shows by term.
async def search_sonarr_shows(self, query: str) -> list[dict[str, Any]]: """Search for TV shows using Sonarr's built-in lookup""" url = f"{self.config.sonarr_url}/api/v3/series/lookup" headers = {"X-Api-Key": self.config.sonarr_api_key} params = {"term": query} logger.info(f"Sonarr lookup request: {url} with term='{query}'") try: response = await self.client.get(url, params=params, headers=headers) logger.info(f"Sonarr response status: {response.status_code}") if response.status_code == 401: logger.error("Sonarr authentication failed - check your API key") raise Exception("Sonarr authentication failed - verify your API key is correct") elif response.status_code == 404: logger.error("Sonarr lookup endpoint not found") raise Exception("Sonarr lookup endpoint not found") response.raise_for_status() results = response.json() logger.info(f"Sonarr returned {len(results)} results for query '{query}'") if results: logger.info(f"First result: {results[0].get('title')} ({results[0].get('year', 'No year')})") return results except Exception as e: logger.error(f"Sonarr lookup error for query '{query}': {e}") raise - Helper method on MediaServerAPI that adds a TV series to Sonarr via POST /api/v3/series, called during auto-add in search_and_add_show.
async def add_series_to_sonarr( self, tvdb_id: int, title: str, root_folder: str | None = None, ) -> AddMediaResponse: """Add TV series to Sonarr using TVDB ID""" url = f"{self.config.sonarr_url}/api/v3/series" headers = {"X-Api-Key": self.config.sonarr_api_key} payload = { "title": title, "tvdbId": tvdb_id, "qualityProfileId": self.config.quality_profile_id, "monitored": True, "seasonFolder": True, "addOptions": { "searchForMissingEpisodes": True } } # Set root folder (parameter > config > auto-detect) if root_folder: payload["rootFolderPath"] = root_folder logger.info(f"Using specified root folder: {root_folder}") elif self.config.sonarr_root_folder: payload["rootFolderPath"] = self.config.sonarr_root_folder logger.info(f"Using configured root folder: {self.config.sonarr_root_folder}") else: # Auto-detect first available root folder root_folders = await self.get_sonarr_root_folders() if root_folders: payload["rootFolderPath"] = root_folders[0]["path"] logger.info(f"Using auto-detected Sonarr root folder: {root_folders[0]['path']}") else: logger.warning("No Sonarr root folders found - series may fail to add") try: response = await self.client.post(url, json=payload, headers=headers) if response.status_code == 201: result = response.json() return AddMediaResponse( success=True, message=f"Successfully added '{title}' to Sonarr", media_id=result.get("id") ) else: return AddMediaResponse( success=False, message=f"Failed to add series: {response.text}" ) except Exception as e: logger.error(f"Sonarr API error: {e}") return AddMediaResponse( success=False, message=f"Error communicating with Sonarr: {str(e)}" )