search_hex_projects
Search Hex projects by matching regex patterns in project titles. Retrieve JSON results with customizable limits and offsets for efficient project discovery.
Instructions
Search for Hex projects using regex pattern matching on project titles.
Args:
search_pattern: Regex pattern to search for in project titles
limit: Maximum number of projects to return (default: 100)
offset: Number of projects to skip for pagination (default: 0)
Returns:
JSON string with matching projects
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| offset | No | ||
| search_pattern | Yes |
Implementation Reference
- src/hex_mcp/server.py:77-158 (handler)The main handler function for the 'search_hex_projects' tool. It is decorated with @mcp.tool() which registers it with the MCP server. The function implements regex-based searching of Hex projects by title, fetching projects in batches via the Hex API with dynamic batch sizing, rate limit handling via backoff, and returns paginated JSON results.@mcp.tool() async def search_hex_projects(search_pattern: str, limit: int = 100, offset: int = 0) -> str: """Search for Hex projects using regex pattern matching on project titles. Args: search_pattern: Regex pattern to search for in project titles limit: Maximum number of projects to return (default: 100) offset: Number of projects to skip for pagination (default: 0) Returns: JSON string with matching projects """ # Set a reasonable batch size for fetching projects - balance between # reducing API calls and not fetching too much at once batch_size = min(100, limit) # Don't request more than needed matched_projects = [] current_offset = offset total_fetched = 0 max_projects_to_search = 1000 # Safeguard against searching too many projects try: # Compile the regex pattern pattern = re.compile(search_pattern, re.IGNORECASE) # Continue fetching until we have enough matches or run out of projects while len(matched_projects) < limit and total_fetched < max_projects_to_search: # Adjust batch size dynamically based on match rate to minimize API calls if total_fetched > 0: match_rate = len(matched_projects) / total_fetched if match_rate > 0: # Estimate how many more projects we need to fetch remaining_matches_needed = limit - len(matched_projects) estimated_total_needed = remaining_matches_needed / match_rate # Adjust batch size based on estimate, with minimum of 20 and max of 100 batch_size = min(max(20, int(estimated_total_needed * 1.2)), 100) # Add 20% buffer params = {"limit": batch_size, "offset": current_offset} try: response = await hex_request("GET", "/projects", params=params) projects = response.get("values", []) # If no more projects, break if not projects: break # Filter projects by title using the regex pattern for project in projects: if "title" in project and pattern.search(project["title"]): matched_projects.append(project) if len(matched_projects) >= limit: break # Update for next batch total_fetched += len(projects) current_offset += len(projects) # Check pagination info pagination = response.get("pagination", {}) if not pagination.get("after"): break except httpx.HTTPStatusError as e: # If it's not a rate limit error that backoff can handle, raise it if e.response.status_code != 429: raise # Prepare the response with pagination info result = { "values": matched_projects[:limit], "total_matched": len(matched_projects), "total_searched": total_fetched, "has_more": len(matched_projects) >= limit or total_fetched >= max_projects_to_search, } return json.dumps(result) except re.error as e: return json.dumps({"error": f"Invalid regex pattern: {str(e)}"}) except Exception as e: return json.dumps({"error": f"Error searching projects: {str(e)}"})