search_aur
Search the Arch User Repository for packages with smart ranking. Returns package details including votes and maintenance status. Always verify packages before installation.
Instructions
[DISCOVERY] Search the Arch User Repository (AUR) for packages with smart ranking. ⚠️ WARNING: AUR packages are user-produced and potentially unsafe. Returns package info including votes, maintainer, and last update. Always check official repos first using get_official_package_info.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Package search query | |
| limit | No | Maximum number of results (default: 20) | |
| sort_by | No | Sort method: 'relevance' (default), 'votes', 'popularity', or 'modified' | relevance |
Implementation Reference
- src/arch_ops_server/aur.py:31-117 (handler)Core handler function that implements the search_aur tool logic: queries AUR RPC API v5, clamps limits, handles HTTP errors/timeouts/rate limits, applies custom ranking/sorting, formats package info, adds AUR safety warning.async def search_aur(query: str, limit: int = 20, sort_by: str = "relevance") -> Dict[str, Any]: """ Search AUR packages using RPC v5 interface with smart ranking. Args: query: Search term (searches name and description) limit: Maximum results to return (default: 20, max: 50) sort_by: Sorting method - "relevance", "votes", "popularity", "modified" (default: relevance) Returns: Dict with AUR packages and safety warning """ logger.info(f"Searching AUR for: {query} (sort: {sort_by})") # Clamp limit limit = min(limit, MAX_RESULTS) params = { "v": "5", "type": "search", "arg": query } try: async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client: response = await client.get(AUR_RPC_URL, params=params) response.raise_for_status() data = response.json() if data.get("type") == "error": return create_error_response( "AURError", data.get("error", "Unknown AUR error") ) results = data.get("results", []) # Apply smart ranking based on sort_by parameter sorted_results = _apply_smart_ranking(results, query, sort_by) # Limit and format results formatted_results = [ _format_package_info(pkg) for pkg in sorted_results[:limit] ] logger.info(f"Found {len(formatted_results)} AUR packages for '{query}'") # Wrap with safety warning return add_aur_warning({ "query": query, "count": len(formatted_results), "total_found": len(results), "sort_by": sort_by, "results": formatted_results }) except httpx.TimeoutException: logger.error(f"AUR search timed out for query: {query}") return create_error_response( "TimeoutError", f"AUR search timed out for query: {query}", "The AUR server did not respond in time. Try again later." ) except httpx.HTTPStatusError as e: # Handle rate limiting specifically if e.response.status_code == 429: logger.error("AUR rate limit exceeded") return create_error_response( "RateLimitError", "AUR rate limit exceeded", "Too many requests. Please wait before trying again." ) logger.error(f"AUR search HTTP error: {e}") return create_error_response( "HTTPError", f"AUR search failed with status {e.response.status_code}", str(e) ) except Exception as e: logger.error(f"AUR search failed: {e}") return create_error_response( "SearchError", f"Failed to search AUR: {str(e)}" )
- src/arch_ops_server/server.py:587-610 (registration)MCP server tool registration: defines the tool name, detailed description with safety warnings, and JSON input schema with parameters query (required), limit, sort_by.name="search_aur", description="[DISCOVERY] Search the Arch User Repository (AUR) for packages with smart ranking. ⚠️ WARNING: AUR packages are user-produced and potentially unsafe. Returns package info including votes, maintainer, and last update. Always check official repos first using get_official_package_info.", inputSchema={ "type": "object", "properties": { "query": { "type": "string", "description": "Package search query" }, "limit": { "type": "integer", "description": "Maximum number of results (default: 20)", "default": 20 }, "sort_by": { "type": "string", "description": "Sort method: 'relevance' (default), 'votes', 'popularity', or 'modified'", "enum": ["relevance", "votes", "popularity", "modified"], "default": "relevance" } }, "required": ["query"] } ),
- Tool metadata definition categorizing search_aur as discovery tool (read-only, any platform), with related tools for package research/installation workflow."search_aur": ToolMetadata( name="search_aur", category="discovery", platform="any", permission="read", workflow="research", related_tools=[ "get_official_package_info", "analyze_package_metadata_risk", "analyze_pkgbuild_safety", "install_package_secure" ], prerequisite_tools=[] ),
- src/arch_ops_server/server.py:1182-1187 (registration)MCP server tool dispatcher: handles search_aur calls, extracts arguments, invokes the aur.py handler, serializes JSON response.elif name == "search_aur": query = arguments["query"] limit = arguments.get("limit", 20) sort_by = arguments.get("sort_by", "relevance") results = await search_aur(query, limit, sort_by) return [TextContent(type="text", text=json.dumps(results, indent=2))]
- src/arch_ops_server/aur.py:585-645 (helper)Helper function for smart ranking/sorting of AUR search results by relevance (exact/partial name matches prioritized), votes, popularity, or modification date.def _apply_smart_ranking( packages: List[Dict[str, Any]], query: str, sort_by: str ) -> List[Dict[str, Any]]: """ Apply smart ranking to AUR search results. Sorting methods: - relevance: Name match priority, then by votes and popularity - votes: Sort by number of votes (most popular first) - popularity: Sort by AUR popularity metric - modified: Sort by last modification date (most recent first) Args: packages: List of package dicts from AUR RPC query: Original search query for relevance scoring sort_by: Sorting method Returns: Sorted list of packages """ if not packages: return packages query_lower = query.lower() # Relevance scoring: prioritize exact name matches, then partial matches if sort_by == "relevance": def relevance_score(pkg: Dict[str, Any]) -> tuple: name = pkg.get("Name", "").lower() votes = pkg.get("NumVotes", 0) popularity = pkg.get("Popularity", 0.0) # Scoring priority (negative for reverse sort): # 1. Exact name match (highest priority) # 2. Name starts with query # 3. Name contains query # 4. Then by votes and popularity exact_match = -1 if name == query_lower else 0 starts_with = -1 if name.startswith(query_lower) else 0 contains = -1 if query_lower in name else 0 return (exact_match, starts_with, contains, -votes, -popularity) return sorted(packages, key=relevance_score) elif sort_by == "votes": return sorted(packages, key=lambda p: p.get("NumVotes", 0), reverse=True) elif sort_by == "popularity": return sorted(packages, key=lambda p: p.get("Popularity", 0.0), reverse=True) elif sort_by == "modified": return sorted(packages, key=lambda p: p.get("LastModified", 0), reverse=True) else: # Default to relevance if unknown sort method logger.warning(f"Unknown sort method: {sort_by}, using relevance") return _apply_smart_ranking(packages, query, "relevance")