Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import os | |
| import json | |
| from typing import List, Dict, Any | |
| try: | |
| from smolagents import InferenceClientModel, CodeAgent, MCPClient | |
| HAS_SMOLAGENTS = True | |
| except ImportError: | |
| HAS_SMOLAGENTS = False | |
| class SimpleMCPClient: | |
| """Simple MCP Client for Hugging Face Spaces""" | |
| def __init__(self): | |
| self.current_client = None | |
| self.current_agent = None | |
| self.conversation_history = [] | |
| # Default MCP server | |
| self.default_server_url = "https://abidlabs-mcp-tool-http.hf.space/gradio_api/mcp/sse" | |
| def connect_to_server(self, server_url: str = None) -> tuple[bool, str]: | |
| """Connect to MCP server""" | |
| url = server_url or self.default_server_url | |
| try: | |
| if HAS_SMOLAGENTS: | |
| # Disconnect existing connection | |
| if self.current_client: | |
| try: | |
| self.current_client.disconnect() | |
| except: | |
| pass | |
| # Create new connection | |
| self.current_client = MCPClient({"url": url}) | |
| tools = self.current_client.get_tools() | |
| # Create agent | |
| model = InferenceClientModel(token=os.getenv("HF_TOKEN")) | |
| self.current_agent = CodeAgent( | |
| tools=[*tools], | |
| model=model, | |
| additional_authorized_imports=["json", "ast", "urllib", "base64"] | |
| ) | |
| return True, f"β Connected successfully! Available tools: {len(tools)}" | |
| else: | |
| # Fallback for when smolagents is not available | |
| return True, "β Connected (simulated - smolagents not available)" | |
| except Exception as e: | |
| return False, f"β Connection failed: {str(e)}" | |
| def chat_with_agent(self, message: str) -> str: | |
| """Chat with the connected agent""" | |
| if not message.strip(): | |
| return "β Please enter a message." | |
| if not self.current_agent and HAS_SMOLAGENTS: | |
| return "β Please connect to a server first." | |
| try: | |
| if HAS_SMOLAGENTS and self.current_agent: | |
| response = str(self.current_agent.run(message)) | |
| else: | |
| # Fallback response | |
| response = f"Simulated response: I received your message '{message}' but cannot process it without smolagents." | |
| # Add to history | |
| self.conversation_history.append({ | |
| "user": message, | |
| "assistant": response | |
| }) | |
| return response | |
| except Exception as e: | |
| error_msg = f"β Error: {str(e)}" | |
| self.conversation_history.append({ | |
| "user": message, | |
| "assistant": error_msg | |
| }) | |
| return error_msg | |
| def get_conversation_history(self) -> List[List[str]]: | |
| """Get conversation history in Gradio ChatInterface format""" | |
| history = [] | |
| for conv in self.conversation_history: | |
| history.append([conv["user"], conv["assistant"]]) | |
| return history | |
| def disconnect(self): | |
| """Disconnect from server""" | |
| if self.current_client and HAS_SMOLAGENTS: | |
| try: | |
| self.current_client.disconnect() | |
| except: | |
| pass | |
| self.current_client = None | |
| self.current_agent = None | |
| # Global client instance | |
| simple_client = SimpleMCPClient() | |
| # Gradio Interface Functions | |
| def connect_wrapper(server_url: str) -> str: | |
| """Wrapper for connection""" | |
| success, message = simple_client.connect_to_server(server_url) | |
| return message | |
| def chat_wrapper(message: str, history: List[List[str]]) -> str: | |
| """Wrapper for chat""" | |
| return simple_client.chat_with_agent(message) | |
| # Pre-defined servers for easy selection | |
| SERVER_OPTIONS = { | |
| "MCP Tools Collection": "https://abidlabs-mcp-tool-http.hf.space/gradio_api/mcp/sse", | |
| # "Sentiment Analyzer": "https://huggingface.co/spaces/Adilbai/MCP-sentiment-analyzer/gradio_api/mcp/sse", # Removed sentiment analyzer | |
| "Custom": "" | |
| } | |
| # Example prompts | |
| EXAMPLE_PROMPTS = [ | |
| "What is the prime factorization of 68?", | |
| "Calculate the square root of 144", | |
| # "Analyze the sentiment of: 'I love this product!'", # Removed sentiment example | |
| "Convert 'Hello World' to base64", | |
| "What tools are available?", | |
| "Help me with a math problem" | |
| ] | |
| # Create Gradio Interface | |
| with gr.Blocks( | |
| theme=gr.themes.Soft(), | |
| title="π Simple MCP Client", | |
| css=""" | |
| .gradio-container { | |
| max-width: 1200px !important; | |
| margin: auto !important; | |
| } | |
| .main-header { | |
| text-align: center; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| font-size: 2.5em; | |
| font-weight: bold; | |
| margin-bottom: 20px; | |
| } | |
| """ | |
| ) as demo: | |
| gr.HTML(""" | |
| <div class="main-header"> | |
| π Simple MCP Client | |
| </div> | |
| <p style="text-align: center; font-size: 1.2em; color: #666; margin-bottom: 30px;"> | |
| Connect to MCP servers and chat with AI agents | |
| </p> | |
| """) | |
| with gr.Tabs(): | |
| # Main Chat Tab | |
| with gr.Tab("π¬ Agent Chat"): | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| # Chat interface | |
| chatbot = gr.Chatbot( | |
| label="π€ MCP Agent Chat", | |
| height=400, | |
| show_label=True | |
| ) | |
| msg = gr.Textbox( | |
| label="Your Message", | |
| placeholder="Type your message here...", | |
| lines=2, | |
| max_lines=5 | |
| ) | |
| with gr.Row(): | |
| send_btn = gr.Button("π€ Send", variant="primary", size="lg") | |
| clear_btn = gr.Button("ποΈ Clear Chat", variant="secondary") | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π Server Connection") | |
| server_select = gr.Dropdown( | |
| choices=list(SERVER_OPTIONS.keys()), | |
| value="MCP Tools Collection" if "MCP Tools Collection" in SERVER_OPTIONS else (list(SERVER_OPTIONS.keys())[0] if SERVER_OPTIONS else "Custom"), # Adjusted default value | |
| label="Select Server" | |
| ) | |
| custom_url = gr.Textbox( | |
| label="Custom Server URL", | |
| placeholder="https://your-server.com/gradio_api/mcp/sse", | |
| visible=(server_select.value == "Custom") # Adjusted visibility based on initial value | |
| ) | |
| connect_btn = gr.Button("π Connect to Server", variant="primary") | |
| connection_status = gr.Textbox( | |
| label="Connection Status", | |
| value="Not connected", | |
| interactive=False, | |
| lines=3 | |
| ) | |
| gr.Markdown("### π― Example Prompts") | |
| example_dropdown = gr.Dropdown( | |
| choices=EXAMPLE_PROMPTS, | |
| label="Select an example", | |
| value=None | |
| ) | |
| # Server Management Tab | |
| with gr.Tab("π₯οΈ Server Management"): | |
| gr.Markdown("## π§ MCP Server Configuration") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("### π Available Servers") | |
| for name, url in SERVER_OPTIONS.items(): | |
| if name != "Custom": | |
| gr.Markdown(f""" | |
| **{name}** | |
| - URL: `{url}` | |
| - Status: {'π’ Available' if url else 'π΄ Not configured'} | |
| """) | |
| with gr.Column(): | |
| gr.Markdown("### β Add Custom Server") | |
| custom_name = gr.Textbox( | |
| label="Server Name", | |
| placeholder="My Custom Server" | |
| ) | |
| custom_server_url = gr.Textbox( | |
| label="Server URL", | |
| placeholder="https://your-mcp-server.com/gradio_api/mcp/sse" | |
| ) | |
| test_connection_btn = gr.Button("π§ͺ Test Connection", variant="secondary") | |
| test_result = gr.Textbox( | |
| label="Test Result", | |
| interactive=False, | |
| lines=2 | |
| ) | |
| # Help & About Tab | |
| with gr.Tab("βΉοΈ Help & About"): | |
| gr.Markdown(""" | |
| ## π Simple MCP Client | |
| This is a streamlined **Model Context Protocol (MCP) Client** for connecting to MCP servers and interacting with AI agents. | |
| ### π Quick Start | |
| 1. **Connect to a Server:** | |
| - Select a pre-configured server from the dropdown | |
| - Click "Connect to Server" | |
| - Wait for connection confirmation | |
| 2. **Start Chatting:** | |
| - Type your message in the text box | |
| - Click "Send" or press Enter | |
| - The AI agent will respond using available MCP tools | |
| 3. **Try Examples:** | |
| - Use the "Example Prompts" dropdown for inspiration | |
| - Different servers have different capabilities | |
| ### π§ Pre-configured Servers | |
| **MCP Tools Collection:** General-purpose tools including math, text processing, and utilities | |
| ### π― Example Use Cases | |
| - **Math Calculations:** "What is the prime factorization of 68?" | |
| - **Text Processing:** "Convert 'Hello World' to base64" | |
| - **Data Analysis:** "Calculate statistics for [1,2,3,4,5]" | |
| ### π§ Technical Requirements | |
| - **smolagents:** For full MCP client functionality | |
| - **Hugging Face Token:** Set `HF_TOKEN` environment variable | |
| - **Internet Connection:** Required for server communication | |
| ### π Troubleshooting | |
| **Connection Issues:** | |
| - Verify server URL is correct | |
| - Check internet connectivity | |
| - Ensure Hugging Face token is valid | |
| **Chat Issues:** | |
| - Make sure you're connected to a server | |
| - Try reconnecting if responses are slow | |
| - Check if the server supports your request type | |
| --- | |
| **Current Status:** | |
| - smolagents Available: 'β Yes' | |
| - MCP Protocol Version: 2024-11-05 | |
| - Client Version: 1.0.0 | |
| """) | |
| # Event Handlers | |
| # Show/hide custom URL input based on server selection | |
| def update_custom_url_visibility(server_name): | |
| return gr.update(visible=(server_name == "Custom")) | |
| server_select.change( | |
| fn=update_custom_url_visibility, | |
| inputs=server_select, | |
| outputs=custom_url | |
| ) | |
| # Connect to server | |
| def connect_to_selected_server(server_name, custom_url_value): | |
| if server_name == "Custom": | |
| url = custom_url_value | |
| else: | |
| url = SERVER_OPTIONS.get(server_name) | |
| if not url: | |
| return "β Please provide a server URL" | |
| return connect_wrapper(url) | |
| connect_btn.click( | |
| fn=connect_to_selected_server, | |
| inputs=[server_select, custom_url], | |
| outputs=connection_status | |
| ) | |
| # Chat functionality | |
| def chat_function(message, history): | |
| if not message.strip(): | |
| return history, "" # Return current history and empty message box | |
| response = simple_client.chat_with_agent(message) | |
| # The history is managed by Gradio's Chatbot by returning a list of lists | |
| # We need to append to the history list passed in and return it | |
| new_history = history + [[message, response]] | |
| return new_history, "" # Return updated history and clear message box | |
| send_btn.click( | |
| fn=chat_function, | |
| inputs=[msg, chatbot], | |
| outputs=[chatbot, msg] | |
| ) | |
| msg.submit( | |
| fn=chat_function, | |
| inputs=[msg, chatbot], | |
| outputs=[chatbot, msg] | |
| ) | |
| # Clear chat | |
| def clear_chat_history(): | |
| simple_client.conversation_history = [] # Clear internal history | |
| return [], "" # Clear chatbot display and message input | |
| clear_btn.click( | |
| fn=clear_chat_history, | |
| inputs=None, # No inputs needed | |
| outputs=[chatbot, msg] # Clear chatbot and message box | |
| ) | |
| # Example prompts | |
| example_dropdown.change( | |
| fn=lambda x: x if x else "", | |
| inputs=example_dropdown, | |
| outputs=msg | |
| ) | |
| # Test connection | |
| def test_custom_connection(url): | |
| if not url.strip(): | |
| return "β Please enter a URL to test" | |
| # Temporarily connect and disconnect to test | |
| original_client = simple_client.current_client | |
| original_agent = simple_client.current_agent | |
| success, message = simple_client.connect_to_server(url) | |
| # Restore original state if it was connected | |
| if original_client: | |
| simple_client.current_client = original_client | |
| simple_client.current_agent = original_agent | |
| else: # if it wasn't connected before, disconnect the test connection | |
| simple_client.disconnect() | |
| return message | |
| test_connection_btn.click( | |
| fn=test_custom_connection, | |
| inputs=custom_server_url, | |
| outputs=test_result | |
| ) | |
| # Auto-connect to default server on startup | |
| def auto_connect(): | |
| """Auto-connect to default server""" | |
| # Ensure default_server_url is valid after changes to SERVER_OPTIONS | |
| default_server_key = "MCP Tools Collection" # Or another default if this is removed | |
| if default_server_key in SERVER_OPTIONS: | |
| url_to_connect = SERVER_OPTIONS[default_server_key] | |
| success, message = simple_client.connect_to_server(url_to_connect) | |
| print(f"Auto-connect to '{default_server_key}': {message}") | |
| elif SERVER_OPTIONS: # Connect to the first available if default is gone | |
| first_server_key = list(SERVER_OPTIONS.keys())[0] | |
| if first_server_key != "Custom": | |
| url_to_connect = SERVER_OPTIONS[first_server_key] | |
| success, message = simple_client.connect_to_server(url_to_connect) | |
| print(f"Auto-connect to '{first_server_key}': {message}") | |
| else: | |
| print("Auto-connect: No default server available to connect.") | |
| else: | |
| print("Auto-connect: No servers configured.") | |
| # Launch configuration | |
| if __name__ == "__main__": | |
| print("π Starting Simple MCP Client...") | |
| print(f"π smolagents available: {HAS_SMOLAGENTS}") | |
| # Update HAS_SMOLAGENTS in Help Tab dynamically | |
| help_tab_index = -1 | |
| for i, tab_item in enumerate(demo.children): | |
| if isinstance(tab_item, gr.layouts.Tabs): | |
| for j, tab_child in enumerate(tab_item.children): | |
| if isinstance(tab_child, gr.layouts.Tab) and tab_child.label == "βΉοΈ Help & About": | |
| help_tab_index = (i,j) | |
| break | |
| if help_tab_index != -1: | |
| break | |
| if help_tab_index != -1: | |
| pass | |
| print("π Auto-connecting to a server...") | |
| auto_connect() | |
| # Determine if running on HF Spaces | |
| is_hf_space = os.getenv("SPACE_ID") is not None | |
| if is_hf_space: | |
| print("π Running on Hugging Face Spaces") | |
| demo.launch() | |
| else: | |
| print("π Web UI: http://localhost:7860") | |
| demo.launch( | |
| server_name="127.0.0.1", | |
| server_port=7860, | |
| show_error=True, | |
| inbrowser=True, | |
| debug=True | |
| ) |