search_movies
Find movies by title using Radarr's lookup to prepare for adding them to your collection.
Instructions
Search for movies by title using Radarr's built-in lookup.
Args: title: Movie title only (e.g., "The Matrix" or "Primer")
Returns: Dict with search results
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/arr_assistant_mcp/main.py:308-364 (handler)The MCP tool handler for 'search_movies'. It takes a movie title, validates config, calls search_radarr_movies, and returns results as MediaSearchResult dicts.
@mcp.tool async def search_movies(title: str) -> dict[str, Any]: """ Search for movies by title using Radarr's built-in lookup. Args: title: Movie title only (e.g., "The Matrix" or "Primer") Returns: Dict with search results """ logger.info(f"Searching for movies: '{title}'") if not config: error_msg = "Server not configured. Please set up Radarr API key." logger.error(error_msg) return {"error": error_msg, "results": []} if not config.radarr_api_key: error_msg = "Radarr API key not configured" logger.error(error_msg) return {"error": error_msg, "results": []} try: async with MediaServerAPI(config) as api: logger.info(f"Searching Radarr for: {title}") radarr_results = await api.search_radarr_movies(title) logger.info(f"Radarr returned {len(radarr_results)} results") if not radarr_results: return { "message": f"No movies found matching '{title}'", "results": [], "searched_query": title } results = [] for movie in radarr_results[:10]: # Show more results since we're not auto-adding result = MediaSearchResult( title=movie.get("title") or "Unknown", year=movie.get("year"), overview=movie.get("overview") or "No overview available", tmdb_id=movie.get("tmdbId"), poster_path=movie.get("remotePoster"), media_type="movie" ) results.append(result) return { "results": [r.model_dump() for r in results], "total_found": len(results), "searched_query": title } except Exception as e: error_msg = f"Error during movie search: {str(e)}" logger.error(error_msg, exc_info=True) return {"error": error_msg, "results": []} - src/arr_assistant_mcp/main.py:37-44 (schema)Pydantic model MediaSearchResult used as the output schema for movie search results.
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" - src/arr_assistant_mcp/main.py:52-52 (registration)The FastMCP server instance creation; the @mcp.tool decorator on the handler function registers 'search_movies' as a tool.
mcp = FastMCP("Arr Assistant MCP Server") - Helper method in MediaServerAPI that actually queries Radarr's /api/v3/movie/lookup endpoint to search for movies.
async def search_radarr_movies(self, query: str) -> list[dict[str, Any]]: """Search for movies using Radarr's built-in lookup (uses their TMDb access)""" url = f"{self.config.radarr_url}/api/v3/movie/lookup" headers = {"X-Api-Key": self.config.radarr_api_key} params = {"term": query} logger.info(f"Radarr lookup request: {url} with term='{query}'") try: response = await self.client.get(url, params=params, headers=headers) logger.info(f"Radarr response status: {response.status_code}") if response.status_code == 401: logger.error("Radarr authentication failed - check your API key") raise Exception("Radarr authentication failed - verify your API key is correct") elif response.status_code == 404: logger.error("Radarr lookup endpoint not found") raise Exception("Radarr lookup endpoint not found") response.raise_for_status() results = response.json() logger.info(f"Radarr 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"Radarr lookup error for query '{query}': {e}") raise - src/arr_assistant_mcp/main.py:22-55 (helper)ServerConfig dataclass used to validate Radarr API key configuration before performing searches.
@dataclass class ServerConfig: radarr_url: str radarr_api_key: str sonarr_url: str sonarr_api_key: str quality_profile_id: int = 1 radarr_root_folder: str | None = None sonarr_root_folder: str | None = None def __post_init__(self) -> None: self.radarr_url = self.radarr_url.rstrip("/") self.sonarr_url = self.sonarr_url.rstrip("/") # Response models 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" class AddMediaResponse(BaseModel): success: bool message: str media_id: int | None = None # Initialize FastMCP server mcp = FastMCP("Arr Assistant MCP Server") # Global config (will be set via environment or config file) config: ServerConfig | None = None