Spaces:
Sleeping
Sleeping
| """ | |
| Admin Panel UI Component | |
| Interactive UI for managing MCP server deployments. | |
| """ | |
| import gradio as gr | |
| from mcp_tools.deployment_tools import ( | |
| deploy_mcp_server, | |
| list_deployments, | |
| delete_deployment, | |
| get_deployment_status | |
| ) | |
| def create_admin_panel(): | |
| """ | |
| Create the admin panel UI component. | |
| Returns: | |
| gr.Blocks: Admin panel interface | |
| """ | |
| with gr.Blocks() as panel: | |
| gr.Markdown("## ⚙️ Deployment Management") | |
| gr.Markdown("Deploy and manage your MCP servers") | |
| # Quick Deploy Section | |
| with gr.Accordion("➕ Quick Deploy", open=True): | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| server_name = gr.Textbox( | |
| label="Server Name", | |
| placeholder="my-mcp-server", | |
| info="Unique name for your MCP server" | |
| ) | |
| code = gr.Code( | |
| language="python", | |
| label="MCP Tools Code", | |
| lines=12, | |
| value='''from fastmcp import FastMCP | |
| mcp = FastMCP("cat-facts") | |
| @mcp.tool() | |
| def get_cat_fact() -> str: | |
| """Get a random cat fact from an API""" | |
| import requests | |
| response = requests.get("https://catfact.ninja/fact") | |
| return response.json()["fact"] | |
| @mcp.tool() | |
| def add_numbers(a: int, b: int) -> int: | |
| """Add two numbers together""" | |
| return a + b | |
| ''' | |
| ) | |
| with gr.Column(scale=1): | |
| packages = gr.Textbox( | |
| label="Extra Packages", | |
| placeholder="requests, pandas", | |
| value="requests", | |
| info="Comma-separated pip packages" | |
| ) | |
| description = gr.Textbox( | |
| label="Description", | |
| lines=2, | |
| placeholder="Optional description" | |
| ) | |
| # New metadata fields | |
| with gr.Row(): | |
| category = gr.Textbox( | |
| label="Category", | |
| placeholder="e.g., Weather, Finance", | |
| value="Uncategorized", | |
| scale=1 | |
| ) | |
| version = gr.Textbox( | |
| label="Version", | |
| value="1.0.0", | |
| scale=1 | |
| ) | |
| tags = gr.Textbox( | |
| label="Tags (comma-separated)", | |
| placeholder="e.g., api, data, utilities" | |
| ) | |
| author = gr.Textbox( | |
| label="Author", | |
| value="Anonymous" | |
| ) | |
| deploy_btn = gr.Button("🚀 Deploy", variant="primary", size="lg") | |
| deploy_output = gr.JSON(label="Deployment Result") | |
| # Helper function to parse tags | |
| def deploy_with_metadata(name, code_val, pkgs, desc, cat, tag_str, auth, ver): | |
| """Deploy with metadata, parsing tags from comma-separated string""" | |
| tag_list = [t.strip() for t in tag_str.split(",") if t.strip()] if tag_str else [] | |
| return deploy_mcp_server( | |
| server_name=name, | |
| mcp_tools_code=code_val, | |
| extra_pip_packages=pkgs, | |
| description=desc, | |
| category=cat, | |
| tags=tag_list, | |
| author=auth, | |
| version=ver | |
| ) | |
| # Wire up deploy button | |
| deploy_btn.click( | |
| fn=deploy_with_metadata, | |
| inputs=[server_name, code, packages, description, category, tags, author, version], | |
| outputs=deploy_output, | |
| api_visibility="private" # Don't expose UI handler as MCP tool | |
| ) | |
| # Deployments Table Section | |
| gr.Markdown("### 📋 Active Deployments") | |
| with gr.Row(): | |
| refresh_btn = gr.Button("🔄 Refresh", size="sm", scale=0) | |
| search_box = gr.Textbox( | |
| label="Search", | |
| placeholder="Filter by name...", | |
| scale=2 | |
| ) | |
| category_filter = gr.Dropdown( | |
| label="Filter by Category", | |
| choices=["All Categories"], | |
| value="All Categories", | |
| scale=1 | |
| ) | |
| deployments_df = gr.Dataframe( | |
| headers=["ID", "Name", "Category", "Tags", "Version", "Author", "Status", "Created"], | |
| datatype=["str", "str", "str", "str", "str", "str", "str", "str"], | |
| interactive=False, | |
| wrap=True, | |
| label="Deployments" | |
| ) | |
| # Quick Actions Section | |
| with gr.Accordion("⚡ Quick Actions", open=False): | |
| with gr.Row(): | |
| deployment_selector = gr.Dropdown( | |
| label="Select Deployment", | |
| choices=[], | |
| interactive=True | |
| ) | |
| action_selector = gr.Dropdown( | |
| label="Action", | |
| choices=["View Status", "Delete (confirm required)"], | |
| value="View Status", | |
| interactive=True | |
| ) | |
| execute_btn = gr.Button("Execute", variant="secondary") | |
| action_output = gr.JSON(label="Action Result") | |
| # Functions | |
| def load_deployments(): | |
| """Load all deployments into the table""" | |
| result = list_deployments() | |
| if result["success"]: | |
| data = [] | |
| dropdown_choices = [] | |
| categories = set(["All Categories"]) | |
| for dep in result["deployments"]: | |
| # Format tags | |
| tags_str = ", ".join(dep.get("tags", [])) if dep.get("tags") else "—" | |
| data.append([ | |
| dep.get("deployment_id", "")[:16] + "...", # Shortened ID | |
| dep.get("server_name", "Unknown"), | |
| dep.get("category", "Uncategorized"), | |
| tags_str, | |
| dep.get("version", "1.0.0"), | |
| dep.get("author", "Anonymous"), | |
| dep.get("status", "unknown"), | |
| dep.get("created_at", "")[:10] if dep.get("created_at") else "N/A" # Date only | |
| ]) | |
| dropdown_choices.append( | |
| (dep["server_name"], dep["deployment_id"]) | |
| ) | |
| # Collect unique categories | |
| if dep.get("category"): | |
| categories.add(dep["category"]) | |
| return data, gr.Dropdown(choices=dropdown_choices), gr.Dropdown(choices=sorted(list(categories))) | |
| return [], gr.Dropdown(choices=[]), gr.Dropdown(choices=["All Categories"]) | |
| def execute_action(deployment_id, action): | |
| """Execute selected action on deployment""" | |
| if not deployment_id: | |
| return {"success": False, "error": "Select a deployment first"} | |
| if "Delete" in action: | |
| return delete_deployment(deployment_id=deployment_id, confirm=True) | |
| elif "View Status" in action: | |
| return get_deployment_status(deployment_id=deployment_id) | |
| return {"success": False, "error": "Unknown action"} | |
| def filter_deployments(search_term, category_val): | |
| """Filter deployments by search term and category""" | |
| result = list_deployments() | |
| if not result["success"]: | |
| return [] | |
| filtered_data = [] | |
| for dep in result["deployments"]: | |
| # Check search term | |
| search_match = (not search_term or | |
| search_term.lower() in dep["server_name"].lower() or | |
| search_term.lower() in dep["deployment_id"].lower()) | |
| # Check category filter | |
| category_match = (category_val == "All Categories" or | |
| dep.get("category", "Uncategorized") == category_val) | |
| if search_match and category_match: | |
| tags_str = ", ".join(dep.get("tags", [])) if dep.get("tags") else "—" | |
| filtered_data.append([ | |
| dep.get("deployment_id", "")[:16] + "...", | |
| dep.get("server_name", "Unknown"), | |
| dep.get("category", "Uncategorized"), | |
| tags_str, | |
| dep.get("version", "1.0.0"), | |
| dep.get("author", "Anonymous"), | |
| dep.get("status", "unknown"), | |
| dep.get("created_at", "")[:10] if dep.get("created_at") else "N/A" | |
| ]) | |
| return filtered_data | |
| # Wire up events | |
| refresh_btn.click( | |
| fn=load_deployments, | |
| outputs=[deployments_df, deployment_selector, category_filter], | |
| api_visibility="private" # Don't expose UI handler as MCP tool | |
| ) | |
| search_box.change( | |
| fn=filter_deployments, | |
| inputs=[search_box, category_filter], | |
| outputs=deployments_df, | |
| api_visibility="private" # Don't expose UI handler as MCP tool | |
| ) | |
| category_filter.change( | |
| fn=filter_deployments, | |
| inputs=[search_box, category_filter], | |
| outputs=deployments_df, | |
| api_visibility="private" # Don't expose UI handler as MCP tool | |
| ) | |
| execute_btn.click( | |
| fn=execute_action, | |
| inputs=[deployment_selector, action_selector], | |
| outputs=action_output, | |
| api_visibility="private" # Don't expose UI handler as MCP tool | |
| ) | |
| # Load deployments on panel load | |
| panel.load( | |
| fn=load_deployments, | |
| outputs=[deployments_df, deployment_selector, category_filter], | |
| api_visibility="private" # Don't expose UI handler as MCP tool | |
| ) | |
| return panel | |