zlysunshine's picture
Deploy Gradio MCP client from GitHub Codespaces
966ccd1 verified
Raw
History Blame Contribute Delete
4.62 kB
import atexit
import os
import threading
from typing import Any
import gradio as gr
import spaces
from huggingface_hub import get_token
from smolagents import CodeAgent, InferenceClientModel, MCPClient
# Your existing MCP sentiment server.
MCP_SERVER_URL = os.getenv(
"MCP_SERVER_URL",
"https://zlysunshine-mcp-sentiment.hf.space/gradio_api/mcp/",
)
# This can be changed later through a Space variable.
MODEL_ID = os.getenv(
"MODEL_ID",
"Qwen/Qwen3-Next-80B-A3B-Thinking",
)
_agent: CodeAgent | None = None
_mcp_client: MCPClient | None = None
_initialization_lock = threading.Lock()
def create_agent() -> CodeAgent:
"""
Lazily connect to the remote MCP server and create the agent.
Returns:
A CodeAgent configured with the remote MCP tools.
"""
global _agent
global _mcp_client
if _agent is not None:
return _agent
with _initialization_lock:
if _agent is not None:
return _agent
# On Hugging Face Spaces, this comes from the HF_TOKEN secret.
# In Codespaces, it can fall back to the locally saved HF login.
token = os.getenv("HF_TOKEN") or get_token()
if not token:
raise RuntimeError(
"No Hugging Face token was found. "
"Set HF_TOKEN or run `hf auth login`."
)
client: MCPClient | None = None
try:
client = MCPClient(
{
"url": MCP_SERVER_URL,
"transport": "streamable-http",
},
structured_output=True,
)
tools = client.get_tools()
if not tools:
raise RuntimeError(
"The MCP server connected successfully but returned no tools."
)
print("MCP tools discovered:")
for tool in tools:
print(f"- {tool.name}: {tool.description}")
model = InferenceClientModel(
model_id=MODEL_ID,
token=token,
timeout=120,
max_tokens=1200,
)
agent = CodeAgent(
tools=[*tools],
model=model,
max_steps=4,
additional_authorized_imports=[
"json",
"ast",
],
)
_mcp_client = client
_agent = agent
return agent
except Exception:
if client is not None:
client.disconnect()
raise
def close_mcp_connection() -> None:
"""Close the long-lived MCP connection when the app stops."""
global _mcp_client
if _mcp_client is not None:
try:
_mcp_client.disconnect()
except Exception as error:
print(f"Error while closing MCP client: {error}")
finally:
_mcp_client = None
atexit.register(close_mcp_connection)
@spaces.GPU(duration=20)
def respond(message: str, history: list[dict[str, Any]]) -> str:
"""
Answer a user question using tools from the remote MCP server.
Args:
message: The user's latest chat message.
history: Previous Gradio chat messages.
Returns:
The agent's final response.
"""
del history # The course example treats each request independently.
cleaned_message = message.strip()
if not cleaned_message:
return "Please enter a question."
try:
agent = create_agent()
result = agent.run(cleaned_message)
return str(result)
except Exception as error:
return (
"The MCP client could not complete the request.\n\n"
f"Error type: {type(error).__name__}\n"
f"Details: {error}\n\n"
"Check that the sentiment MCP server is running and that "
"the client Space has an HF_TOKEN secret with inference access."
)
demo = gr.ChatInterface(
fn=respond,
title="Gradio MCP Client Agent",
description=(
"An AI agent that connects to the "
"zlysunshine/mcp-sentiment MCP server and uses its tools."
),
examples=[
(
"You must use the sentiment_analysis tool to analyze: "
"'This MCP course is excellent, but deployment was frustrating.'"
),
(
"Call the sentiment tool for: "
"'I am happy that the application finally works.'"
),
],
)
if __name__ == "__main__":
demo.queue().launch(
server_name="0.0.0.0",
)