Skip to main content
Glama
tschoonj
by tschoonj

search_projects

Find software projects by name substring with optional 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
categoryNo
inrepoNo
limitNo
maintainerNo
notinrepoNo
queryYes

Implementation Reference

  • MCP tool handler for 'search_projects': decorated with @mcp.tool(), processes input parameters, calls RepologyClient.search_projects, applies filters, formats output as JSON.
    @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}"})
  • Helper function to convert the project packages dictionary to formatted JSON string, used in search_projects handler.
    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 to filter project packages by repository, used conditionally in search_projects handler.
    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
  • RepologyClient helper method implementing the actual API search by forwarding to list_projects with search filter.
    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)
  • Pydantic schema/model for Package objects used to validate and serialize the data in tool responses.
    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")

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