Skip to main content
Glama
elad12390

Web Research Assistant

by elad12390

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
NameRequiredDescriptionDefault
queryYes
reasoningYes
registryNonpm
max_resultsNo

Implementation Reference

  • 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
  • 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)
  • 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)
  • 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
  • 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()

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/elad12390/web-research-assistant'

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