Skip to main content
Glama
tschoonj

Repology MCP Server

by tschoonj

list_projects

Retrieve and filter software projects from package repositories to identify packages by maintainer, category, repository status, or version issues.

Instructions

List projects with optional filtering.

Args:
    start_from: Project name to start listing from
    limit: Maximum number of results (default: 10, max: 200)
    maintainer: Filter by maintainer email
    category: Filter by category
    inrepo: Filter by repository presence
    notinrepo: Filter by repository absence
    repos: Filter by number of repositories (e.g., "1", "5-", "-5", "2-7")
    families: Filter by number of repository families
    newest: Show only newest projects
    outdated: Show only outdated projects
    problematic: Show only problematic projects

Returns:
    JSON formatted dictionary of projects and their packages

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
start_fromNo
limitNo
maintainerNo
categoryNo
inrepoNo
notinrepoNo
reposNo
familiesNo
newestNo
outdatedNo
problematicNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The MCP tool handler function for 'list_projects'. It enforces limits, builds filters, calls RepologyClient.list_projects, applies client-side repo filtering if needed, formats output as JSON, and handles errors.
    @mcp.tool()
    async def list_projects(
        start_from: Optional[str] = None,
        limit: int = 10,
        maintainer: Optional[str] = None,
        category: Optional[str] = None,
        inrepo: Optional[str] = None,
        notinrepo: Optional[str] = None,
        repos: Optional[str] = None,
        families: Optional[str] = None,
        newest: Optional[bool] = None,
        outdated: Optional[bool] = None,
        problematic: Optional[bool] = None,
        ctx: Context[ServerSession, AppContext] = None,
    ) -> str:
        """List projects with optional filtering.
    
        Args:
            start_from: Project name to start listing from
            limit: Maximum number of results (default: 10, max: 200)
            maintainer: Filter by maintainer email
            category: Filter by category
            inrepo: Filter by repository presence
            notinrepo: Filter by repository absence
            repos: Filter by number of repositories (e.g., "1", "5-", "-5", "2-7")
            families: Filter by number of repository families
            newest: Show only newest projects
            outdated: Show only outdated projects
            problematic: Show only problematic projects
    
        Returns:
            JSON formatted dictionary of projects and their packages
        """
        if limit > 200:
            limit = 200
    
        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
            if repos:
                filters["repos"] = repos
            if families:
                filters["families"] = families
            if newest:
                filters["newest"] = "1"
            if outdated:
                filters["outdated"] = "1"
            if problematic:
                filters["problematic"] = "1"
    
            project_packages = await client.list_projects(
                start_from=start_from, 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": "No projects found matching the criteria"})
    
            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 listing projects: {e}")
            return json.dumps({"error": f"Unexpected error: {e}"})
  • The @mcp.tool() decorator registers the list_projects function as an MCP tool on the FastMCP server instance.
    @mcp.tool()
  • RepologyClient.list_projects method: Fetches project list from Repology API with pagination and filters, validates packages with Pydantic models.
    async def list_projects(
        self,
        start_from: Optional[str] = None,
        end_at: Optional[str] = None,
        limit: int = 200,
        **filters: Any,
    ) -> ProjectPackages:
        """List projects with optional filtering.
    
        Args:
            start_from: Project name to start from (inclusive)
            end_at: Project name to end at (inclusive)
            limit: Maximum number of projects (max 200)
            **filters: Additional filters (maintainer, category, inrepo, etc.)
    
        Returns:
            Dictionary mapping project names to package lists
        """
        # Build endpoint path
        if start_from and end_at:
            endpoint = f"projects/{quote(start_from)}/..{quote(end_at)}/"
        elif start_from:
            endpoint = f"projects/{quote(start_from)}/"
        elif end_at:
            endpoint = f"projects/..{quote(end_at)}/"
        else:
            endpoint = "projects/"
    
        # Add query parameters for filters
        params = {}
        for key, value in filters.items():
            if value is not None:
                params[key] = value
    
        try:
            data = await self._make_request(endpoint, params)
    
            if not isinstance(data, dict):
                raise RepologyAPIError(f"Expected dict, got {type(data)}")
    
            result = {}
            for project_name, packages_data in data.items():
                packages = []
                for item in packages_data:
                    try:
                        packages.append(Package.model_validate(item))
                    except ValidationError as e:
                        print(f"Warning: Failed to validate package data: {e}")
                        continue
                result[project_name] = packages
    
            return result
    
        except Exception as e:
            raise RepologyAPIError(f"Failed to list projects: {e}")
  • Helper function to convert the project packages dictionary to indented JSON string for the tool response.
    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 client-side filtering of project packages by repository after API 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 model for Package data structure used in list_projects output validation and serialization.
    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