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

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

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()
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It describes the search behavior and cross-registry scope, which is helpful. However, it doesn't disclose important behavioral traits like rate limits, authentication needs, pagination, or what the output contains (though an output schema exists). For a search tool with no annotations, this leaves gaps in understanding operational constraints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded: the first sentence states the core purpose, followed by usage guidelines, and then illustrative examples. Every sentence adds value without redundancy. The structure flows logically from general to specific, making it easy for an agent to parse quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (4 parameters, no annotations, but with an output schema), the description is fairly complete. It covers purpose, usage, and parameter semantics reasonably well. The existence of an output schema reduces the need to explain return values. However, without annotations, it could benefit from more behavioral details like performance or limitations, but it's adequate for a search tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It adds meaningful context for parameters: 'keywords or description' clarifies the 'query' parameter, and examples show usage of 'reasoning' and 'registry'. However, it doesn't explain 'max_results' or the enum values for 'registry'. The description provides good semantic value for 2-3 parameters but misses details on others, partially compensating for the schema gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose with specific verbs ('search for packages') and resources ('packages by keywords or description across registries'). It distinguishes from siblings like 'package_info' (which likely provides details on a known package) by emphasizing discovery of unknown packages. The description explicitly contrasts with knowing the package name versus needing to find packages that solve problems.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use this tool: 'to find packages that solve a specific problem or provide certain functionality' and 'Perfect for discovering libraries when you know what you need but not the package name.' It implicitly distinguishes from siblings like 'package_info' (for known packages) and 'web_search' (broader searches). The examples reinforce this context by showing use cases for backend frameworks and data processing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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