Spaces:
Running
Running
| """ | |
| Simple HuggingFace MCP Spaces Finder Module - Corrected Version | |
| A minimal module to discover MCP servers on HuggingFace Spaces. | |
| Fixed to fetch ALL available MCP servers using proper pagination. | |
| Usage: | |
| from mcp_spaces_finder import create_simple_mcp_selector | |
| # One-liner in your Gradio app | |
| dropdown, textbox = create_simple_mcp_selector() | |
| """ | |
| import gradio as gr | |
| from huggingface_hub import list_spaces | |
| import time | |
| from typing import List, Tuple | |
| class SimpleMCPFinder: | |
| """Simple MCP spaces finder with caching and proper pagination.""" | |
| def __init__(self, cache_duration: int = 300): | |
| self.cache = None | |
| self.cache_time = None | |
| self.cache_duration = cache_duration | |
| def get_mcp_spaces(self) -> List[str]: | |
| """Get list of ALL running MCP space IDs using proper pagination.""" | |
| # Check cache | |
| if (self.cache is not None and | |
| self.cache_time is not None and | |
| time.time() - self.cache_time < self.cache_duration): | |
| return self.cache | |
| print("Fetching ALL MCP spaces...") | |
| # Get ALL MCP spaces by setting a much higher limit | |
| # The HF API supports pagination, so we set limit high enough to get all | |
| spaces = list(list_spaces( | |
| filter="mcp-server", | |
| sort="likes", | |
| direction=-1, | |
| limit=5000, # Increased from 1000 to capture all ~2500 spaces | |
| full=True | |
| )) | |
| # Extract just the space IDs | |
| space_ids = [space.id for space in spaces] | |
| # Cache results | |
| self.cache = space_ids | |
| self.cache_time = time.time() | |
| print(f"Found {len(space_ids)} MCP spaces") | |
| return space_ids | |
| def get_mcp_spaces_paginated(self) -> List[str]: | |
| """Alternative method: Get ALL MCP spaces using explicit pagination if needed.""" | |
| # Check cache | |
| if (self.cache is not None and | |
| self.cache_time is not None and | |
| time.time() - self.cache_time < self.cache_duration): | |
| return self.cache | |
| print("Fetching ALL MCP spaces with pagination...") | |
| all_space_ids = [] | |
| limit_per_page = 1000 | |
| # Keep fetching until we get all spaces | |
| # Note: HuggingFace API handles pagination internally with the iterator | |
| try: | |
| spaces = list(list_spaces( | |
| filter="mcp-server", | |
| sort="likes", | |
| direction=-1, | |
| limit=None, # No limit to get all | |
| full=True | |
| )) | |
| all_space_ids = [space.id for space in spaces] | |
| except Exception as e: | |
| print(f"Error with unlimited fetch, trying with high limit: {e}") | |
| # Fallback to high limit | |
| spaces = list(list_spaces( | |
| filter="mcp-server", | |
| sort="likes", | |
| direction=-1, | |
| limit=5000, # High limit as fallback | |
| full=True | |
| )) | |
| all_space_ids = [space.id for space in spaces] | |
| # Cache results | |
| self.cache = all_space_ids | |
| self.cache_time = time.time() | |
| print(f"Found {len(all_space_ids)} MCP spaces total") | |
| return all_space_ids | |
| # Global instance | |
| _finder = SimpleMCPFinder() | |
| def create_simple_mcp_selector( | |
| dropdown_label: str = "π€ Select MCP Server", | |
| textbox_label: str = "Selected MCP Server", | |
| placeholder: str = "No server selected" | |
| ) -> Tuple[gr.Dropdown, gr.Textbox]: | |
| """ | |
| Create a simple MCP selector with dropdown and textbox. | |
| Args: | |
| dropdown_label (str): Label for the dropdown | |
| textbox_label (str): Label for the textbox | |
| placeholder (str): Placeholder text when nothing selected | |
| Returns: | |
| Tuple[gr.Dropdown, gr.Textbox]: The dropdown and textbox components | |
| """ | |
| # Get MCP spaces | |
| spaces = _finder.get_mcp_spaces() | |
| # Create dropdown with space choices | |
| dropdown = gr.Dropdown( | |
| choices=spaces, | |
| label=f"{dropdown_label} ({len(spaces)} available)", | |
| value=None, | |
| allow_custom_value=True, # Allow users to type custom space IDs | |
| info="Choose from discovered MCP spaces or type a custom space ID" | |
| ) | |
| # Create textbox to display selection | |
| textbox = gr.Textbox( | |
| label=textbox_label, | |
| value=placeholder, | |
| interactive=False | |
| ) | |
| # Connect dropdown to textbox | |
| def update_textbox(selected_value): | |
| return selected_value if selected_value else placeholder | |
| dropdown.change( | |
| fn=update_textbox, | |
| inputs=[dropdown], | |
| outputs=[textbox] | |
| ) | |
| return dropdown, textbox | |
| def refresh_mcp_spaces(): | |
| """Clear cache to force refresh.""" | |
| _finder.cache = None | |
| _finder.cache_time = None | |
| def test_space_exists(space_id: str) -> bool: | |
| """Test if a specific space exists in our discovered list.""" | |
| spaces = _finder.get_mcp_spaces() | |
| return space_id in spaces | |
| def debug_search_for_spaces(space_ids: List[str]): | |
| """Debug function to check if specific spaces are found.""" | |
| spaces = _finder.get_mcp_spaces() | |
| print(f"Total MCP spaces found: {len(spaces)}") | |
| for space_id in space_ids: | |
| if space_id in spaces: | |
| print(f"β Found: {space_id}") | |
| else: | |
| print(f"β Missing: {space_id}") | |
| # Show first 10 spaces for reference | |
| print(f"\nFirst 10 spaces found:") | |
| for i, space in enumerate(spaces[:10]): | |
| print(f" {i+1}. {space}") | |
| if __name__ == "__main__": | |
| # Test the specific spaces you mentioned | |
| test_spaces = [ | |
| "ysharma/Kokoro-TTS-mcp-test", | |
| "ysharma/ltx-video-distilled", | |
| "ysharma/dalle-3-xl-lora-v2" | |
| ] | |
| print("Testing MCP space discovery...") | |
| debug_search_for_spaces(test_spaces) | |