package_search
Search for software packages by functionality across multiple registries to find libraries that solve specific development problems.
Instructions
Search for packages by keywords or description across registries.
Use this to find packages that solve a specific problem or provide certain functionality.
Perfect for discovering libraries when you know what you need but not the package name.
Examples:
- package_search("web framework", reasoning="Need backend framework", registry="npm")
- package_search("json parsing", reasoning="Data processing", registry="pypi")
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| reasoning | Yes | ||
| registry | No | npm | |
| max_results | No |
Implementation Reference
- src/searxng_mcp/server.py:566-621 (handler)MCP tool handler for 'package_search'. Calls PackageRegistryClient.search_packages, formats results with _format_package_search_results, handles errors and tracks usage.@mcp.tool() async def package_search( query: Annotated[ str, "Search keywords (e.g., 'web framework', 'json parser', 'machine learning')", ], reasoning: Annotated[str, "Why you're searching for packages (required for analytics)"], registry: Annotated[ Literal["npm", "pypi", "crates", "go"], "Package registry to search (npm, pypi, crates, go)", ] = "npm", max_results: Annotated[int, "Maximum number of results to return (1-10)"] = 5, ) -> str: """ Search for packages by keywords or description across registries. Use this to find packages that solve a specific problem or provide certain functionality. Perfect for discovering libraries when you know what you need but not the package name. Examples: - package_search("web framework", reasoning="Need backend framework", registry="npm") - package_search("json parsing", reasoning="Data processing", registry="pypi") """ start_time = time.time() success = False error_msg = None result = "" try: max_results = max(1, min(max_results, 10)) # Clamp to 1-10 packages = await registry_client.search_packages(query, registry, max_results) result = _format_package_search_results(packages, query, registry) result = clamp_text(result, MAX_RESPONSE_CHARS) success = True except Exception as exc: # noqa: BLE001 error_msg = str(exc) result = f"Search failed for '{query}' on {registry}: {exc}" finally: # Track usage response_time = (time.time() - start_time) * 1000 tracker.track_usage( tool_name="package_search", reasoning=reasoning, parameters={ "query": query, "registry": registry, "max_results": max_results, }, response_time_ms=response_time, success=success, error_message=error_msg, response_size=len(result.encode("utf-8")), ) return result
- src/searxng_mcp/server.py:540-564 (helper)Helper function to format the list of PackageInfo objects into a human-readable string for the tool response.def _format_package_search_results(packages: list[PackageInfo], query: str, registry: str) -> str: """Format package search results into readable text.""" if not packages: return f"No packages found for '{query}' on {registry}.\n\nTry different keywords or check another registry." lines = [ f"Search Results for '{query}' on {registry}:", "─" * 50, ] for i, pkg in enumerate(packages, 1): lines.append(f"{i}. {pkg.name}") if pkg.version != "unknown": lines.append(f" Version: {pkg.version}") if pkg.downloads: lines.append(f" Downloads: {pkg.downloads}") if pkg.description: # Truncate long descriptions desc = pkg.description[:100] + "..." if len(pkg.description) > 100 else pkg.description lines.append(f" Description: {desc}") lines.append("") # blank line between results return "\n".join(lines)
- src/searxng_mcp/registry.py:36-49 (helper)Core helper method in PackageRegistryClient that dispatches to registry-specific search functions (_search_npm, etc.) based on the registry parameter.async def search_packages( self, query: str, registry: str, max_results: int = 5 ) -> list[PackageInfo]: """Search for packages by description/keywords.""" if registry == "npm": return await self._search_npm(query, max_results) elif registry == "pypi": return await self._search_pypi(query, max_results) elif registry == "crates": return await self._search_crates(query, max_results) else: # go return await self._search_go(query, max_results)
- src/searxng_mcp/registry.py:12-27 (schema)Dataclass schema defining the structure of package information used throughout the package search functionality.@dataclass(slots=True) class PackageInfo: """Structured package metadata from various registries.""" name: str registry: str version: str description: str license: str | None downloads: str | None last_updated: str repository: str | None homepage: str | None dependencies_count: int | None security_issues: int
- src/searxng_mcp/server.py:26-34 (registration)Import and instantiation of PackageRegistryClient used by the package_search tool.from .registry import PackageInfo, PackageRegistryClient from .search import SearxSearcher from .service_health import ServiceHealthChecker from .tracking import get_tracker mcp = FastMCP("web-research-assistant") searcher = SearxSearcher() crawler_client = CrawlerClient() registry_client = PackageRegistryClient()