Skip to main content
Glama
omniwaifu

arr-assistant-mcp

by omniwaifu

search_and_add_show

Search for TV shows using natural language queries and add matching results to Sonarr for automated downloading.

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

TableJSON Schema
NameRequiredDescriptionDefault
descriptionYes
auto_addNo

Implementation Reference

  • The primary handler function decorated with @mcp.tool, implementing the search_and_add_show tool logic: searches Sonarr for TV shows by description, returns formatted results, and conditionally auto-adds the show.
    @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.") api = MediaServerAPI(config) # 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", "Unknown"), year=show.get("year"), overview=show.get("overview", "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, show.tmdb_id) logger.info(f"Auto-add result: {add_result}") else: logger.warning(f"Cannot auto-add '{show.title}' - no TVDB ID available") return results
  • Pydantic model defining the output schema for search results used by the search_and_add_show tool.
    class MediaSearchResult(BaseModel): title: str year: Optional[int] = None overview: str tmdb_id: Optional[int] = None tvdb_id: Optional[int] = None poster_path: Optional[str] = None media_type: str # "movie" or "tv"
  • Helper method in MediaServerAPI class that performs the Sonarr API search for TV shows, called by the tool handler.
    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 e
  • Helper method in MediaServerAPI class that adds a TV series to Sonarr using TVDB ID, called conditionally by the tool handler for auto-add.
    async def add_series_to_sonarr(self, tvdb_id: int, title: str, root_folder: Optional[str] = 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)}" )
  • Pydantic model for response from add operations, used in the auto-add helper.
    class AddMediaResponse(BaseModel): success: bool message: str media_id: Optional[int] = None

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/omniwaifu/arr-assistant-mcp'

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