Skip to main content
Glama
tschoonj

Repology MCP Server

by tschoonj

search_projects

Find software projects by name with filters for maintainer, category, and repository presence to locate packages across distributions.

Instructions

Search for projects by name substring.

Args:
    query: Search term to match against project names
    limit: Maximum number of results (default: 10, max: 100)
    maintainer: Optional maintainer email filter
    category: Optional category filter
    inrepo: Optional repository presence filter
    notinrepo: Optional repository absence filter

Returns:
    JSON formatted list of matching projects with their packages

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes
limitNo
maintainerNo
categoryNo
inrepoNo
notinrepoNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The primary MCP tool handler for 'search_projects'. Decorated with @mcp.tool(), it processes inputs, enforces the limit, calls RepologyClient.search_projects, applies optional repo filtering, formats results as JSON, and handles errors.
    @mcp.tool()
    async def search_projects(
        query: str,
        limit: int = 10,
        maintainer: Optional[str] = None,
        category: Optional[str] = None,
        inrepo: Optional[str] = None,
        notinrepo: Optional[str] = None,
        ctx: Context[ServerSession, AppContext] = None,
    ) -> str:
        """Search for projects by name substring.
    
        Args:
            query: Search term to match against project names
            limit: Maximum number of results (default: 10, max: 100)
            maintainer: Optional maintainer email filter
            category: Optional category filter
            inrepo: Optional repository presence filter
            notinrepo: Optional repository absence filter
    
        Returns:
            JSON formatted list of matching projects with their packages
        """
        if limit > 100:
            limit = 100
    
        try:
            client = ctx.request_context.lifespan_context.repology_client
    
            # Build filters
            filters = {}
            if maintainer:
                filters["maintainer"] = maintainer
            if category:
                filters["category"] = category
            if inrepo:
                filters["inrepo"] = inrepo
            if notinrepo:
                filters["notinrepo"] = notinrepo
    
            project_packages = await client.search_projects(
                query=query, limit=limit, **filters
            )
    
            # Apply client-side repository filtering if inrepo is specified
            if inrepo and project_packages:
                project_packages = _filter_project_packages_by_repo(
                    project_packages, inrepo
                )
    
            if not project_packages:
                return json.dumps({"message": f"No projects found matching '{query}'"})
    
            return _project_packages_to_json(project_packages)
    
        except RepologyAPIError as e:
            await ctx.error(f"Repology API error: {e}")
            return json.dumps({"error": str(e)})
        except Exception as e:
            await ctx.error(f"Unexpected error searching projects: {e}")
            return json.dumps({"error": f"Unexpected error: {e}"})
  • RepologyClient helper method implementing the search logic by adding 'search' filter to list_projects call. Directly invoked by the MCP handler.
    async def search_projects(
        self, query: str, limit: int = 10, **filters: Any
    ) -> ProjectPackages:
        """Search for projects by name.
    
        Args:
            query: Search term to match against project names
            limit: Maximum number of results
            **filters: Additional filters
    
        Returns:
            Dictionary mapping project names to package lists
        """
        # Use the search filter in list_projects
        filters["search"] = query
        return await self.list_projects(limit=min(limit, 200), **filters)
  • Server-side helper function to serialize project packages dictionary into pretty-printed JSON, used by the handler for response formatting.
    def _project_packages_to_json(project_packages: Dict[str, List[Package]]) -> str:
        """Convert project packages dict to formatted JSON string."""
        result = {}
        for project_name, packages in project_packages.items():
            result[project_name] = [pkg.model_dump() for pkg in packages]
        return json.dumps(result, indent=2)
  • Helper function for additional client-side filtering of results by repository when 'inrepo' parameter is provided in the tool call.
    def _filter_project_packages_by_repo(
        project_packages: Dict[str, List[Package]], repo: str
    ) -> Dict[str, List[Package]]:
        """Filter project packages to only include those from a specific repository."""
        filtered = {}
        for project_name, packages in project_packages.items():
            filtered_packages = _filter_packages_by_repo(packages, repo)
            if (
                filtered_packages
            ):  # Only include projects that have packages in the specified repo
                filtered[project_name] = filtered_packages
        return filtered
  • Pydantic BaseModel for Package data structure used for input validation and output serialization in search_projects results (ProjectPackages = Dict[str, List[Package]]).
    class Package(BaseModel):
        """A package in a repository."""
    
        repo: str = Field(description="Repository name")
        subrepo: Optional[str] = Field(None, description="Subrepository name")
        srcname: Optional[str] = Field(None, description="Source package name")
        binname: Optional[str] = Field(None, description="Binary package name")
        binnames: Optional[List[str]] = Field(None, description="All binary package names")
        visiblename: str = Field(description="Package name as shown by Repology")
        version: str = Field(description="Package version (sanitized)")
        origversion: Optional[str] = Field(None, description="Original package version")
        status: Literal[
            "newest",
            "devel",
            "unique",
            "outdated",
            "legacy",
            "rolling",
            "noscheme",
            "incorrect",
            "untrusted",
            "ignored",
        ] = Field(description="Package status")
        summary: Optional[str] = Field(None, description="Package description")
        categories: Optional[List[str]] = Field(None, description="Package categories")
        licenses: Optional[List[str]] = Field(None, description="Package licenses")
        maintainers: Optional[List[str]] = Field(None, description="Package maintainers")

Tool Definition Quality

Score is being calculated. Check back soon.

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/tschoonj/repology-mcp-server'

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