Gradio Agents & MCP 黑客马拉松
获奖者Gradio Agents & MCP 黑客马拉松
获奖者本指南将介绍如何启动您的 Gradio 应用程序,使其作为 MCP 服务器运行。
核心要点:只需在 .launch()
中设置 mcp_server=True
即可。
如果尚未安装,请安装带有 MCP 额外功能的 Gradio。
pip install "gradio[mcp]"
这将安装必要的依赖项,包括 mcp
包。此外,您需要一个支持使用 MCP 协议进行工具调用的 LLM 应用程序,例如 Claude Desktop、Cursor 或 Cline(这些被称为“MCP 客户端”)。
MCP(模型控制协议)服务器是一种标准化方式,用于公开工具,以便 LLM 可以使用它们。工具可以为 LLM 提供其本身不具备的功能,例如生成图像或计算数字的素数因子的能力。
众所周知,LLM 不擅长计算单词中的字母数(例如,“strawberry”中“r”的数量)。但如果我们为它们配备一个工具来帮助呢?让我们从编写一个简单的 Gradio 应用程序开始,它可以计算单词或短语中的字母数。
import gradio as gr
def letter_counter(word, letter):
"""
Count the number of occurrences of a letter in a word or text.
Args:
word (str): The input text to search through
letter (str): The letter to search for
Returns:
str: A message indicating how many times the letter appears
"""
word = word.lower()
letter = letter.lower()
count = word.count(letter)
return count
demo = gr.Interface(
fn=letter_counter,
inputs=[gr.Textbox("strawberry"), gr.Textbox("r")],
outputs=[gr.Number()],
title="Letter Counter",
description="Enter text and a letter to count how many times the letter appears in the text."
)
if __name__ == "__main__":
demo.launch(mcp_server=True)
请注意,我们已:(1) 为函数添加了详细的文档字符串,以及 (2) 在 .launch()
中设置了 mcp_server=True
。这就是您的 Gradio 应用作为 MCP 服务器所需的一切!现在,当您运行此应用时,它将:
MCP 服务器将可通过以下地址访问:
http://your-server:port/gradio_api/mcp/sse
Gradio 自动将 letter_counter
函数转换为可供 LLM 使用的 MCP 工具。函数的文档字符串和参数的类型提示将用于生成工具及其参数的描述。函数的名称将用作工具的名称。您提供给输入组件的任何初始值(例如,上述 gr.Textbox
组件中的“strawberry”和“r”)将用作默认值,如果您的 LLM 未为该特定输入参数指定值。
现在,您只需将此 URL 端点添加到您的 MCP 客户端(例如 Claude Desktop、Cursor 或 Cline),这通常意味着将此配置粘贴到设置中:
{
"mcpServers": {
"gradio": {
"url": "http://your-server:port/gradio_api/mcp/sse"
}
}
}
(顺便说一句,您可以通过访问 Gradio 应用程序页脚中的“查看 API”链接,然后点击“MCP”来找到要复制粘贴的确切配置。)
如上所示,使用 mcp_server
参数
demo.launch(mcp_server=True)
使用环境变量
export GRADIO_MCP_SERVER=True
文件处理:服务器自动处理文件数据转换,包括:
将 base64 编码的字符串转换为文件数据
处理图像文件并以正确格式返回
管理临时文件存储
强烈建议将输入图像和文件作为完整 URL(“http://...”或“https:/...”)传递,因为 MCP 客户端并非总能正确处理本地文件。
{
"mcpServers": {
"gradio": {
"url": "https://abidlabs-mcp-tools.hf.space/gradio_api/mcp/sse"
}
}
}
如果您想将现有空间用作 MCP 服务器,您需要做三件事:
.launch()
中添加 mcp_server=True
。就这么简单!
您可以使用公共空间或私有空间作为 MCP 服务器。如果您想使用私有空间作为 MCP 服务器(或使用您自己配额的 ZeroGPU 空间),那么您在发出请求时需要提供您的 Hugging Face token。为此,只需在配置中将其添加为标头,如下所示:
{
"mcpServers": {
"gradio": {
"url": "https://abidlabs-mcp-tools.hf.space/gradio_api/mcp/sse",
"headers": {
"Authorization": "Bearer <YOUR-HUGGING-FACE-TOKEN>"
}
}
}
}
您可能希望更精确地认证用户,或者让他们提供其他类型的凭据或令牌,以便为不同的用户提供自定义体验。
Gradio 允许您访问已发出工具调用的底层 starlette.Request
对象,这意味着您可以访问标头、原始 IP 地址或作为网络请求一部分的任何其他信息。为此,只需在函数中添加一个 gr.Request
类型的参数,Gradio 将自动将请求对象作为参数注入。
这是一个例子:
import gradio as gr
def echo_headers(x, request: gr.Request):
return str(dict(request.headers))
gr.Interface(echo_headers, "textbox", "textbox").launch(mcp_server=True)
此 MCP 服务器将简单地忽略用户输入并回显用户请求中的所有标头。可以使用相同的想法构建更复杂的应用程序。有关更多信息,请参阅 gr.Request
文档(请注意,只会存在 gr.Request
对象的核心 Starlette 属性,例如 Gradio 的 .session_hash
等属性将不存在)。
到目前为止,我们所有的 MCP 工具都对应于 UI 中的事件监听器。这对于直接更新 UI 的函数来说工作良好,但如果您希望公开一个“纯逻辑”函数,该函数应该返回原始数据(例如 JSON 对象)而不直接导致 UI 更新,则可能无法工作。
为了公开此类 MCP 工具,您可以使用 gr.api
创建一个纯 Gradio API 端点(请参阅此处完整的文档)。以下是创建用于切片列表的 MCP 工具的示例:
import gradio as gr
def slice_list(lst: list, start: int, end: int) -> list:
"""
A tool that slices a list given a start and end index.
Args:
lst: The list to slice.
start: The start index.
end: The end index.
Returns:
The sliced list.
"""
return lst[start:end]
with gr.Blocks() as demo:
gr.Markdown(
"""
This is a demo of a MCP-only tool.
This tool slices a list.
This tool is MCP-only, so it does not have a UI.
"""
)
gr.api(
slice_list
)
_, url, _ = demo.launch(mcp_server=True)
请注意,如果您使用此方法,您的函数签名必须完全类型化,包括返回值,因为这些签名用于确定 MCP 工具的类型信息。
上述方法提供了一种简单的方式,可以将任何 Gradio 应用程序用作 MCP 服务器。但仍有一些限制需要注意:
无法在 MCP 工具调用中识别特定用户。这意味着您无法在 Gradio 应用程序中存储调用之间的用户状态。如果您在应用程序中使用 gr.State
组件,它将始终以其原始默认值传递。
您无法选择 Gradio 中要公开为工具的特定端点(所有 show_api=True
的端点都被视为工具),也无法更改工具的描述,除非您更改函数的文档字符串。
如果您需要克服这些限制,您将需要创建一个自定义 MCP 服务器来调用您的 Gradio 应用程序,我们将在下面进行描述。
在某些情况下,您可能需要手动创建一个 MCP 服务器,该服务器内部调用 Gradio 应用程序。当您希望执行以下操作时,此方法非常有用:
由于有了 Gradio Python 客户端和 MCP Python SDK,这非常容易实现。以下是创建连接到 HuggingFace Spaces 上托管的各种 Gradio 应用程序的自定义 MCP 服务器的示例,使用 stdio
协议:
from mcp.server.fastmcp import FastMCP
from gradio_client import Client
import sys
import io
import json
mcp = FastMCP("gradio-spaces")
clients = {}
def get_client(space_id: str) -> Client:
"""Get or create a Gradio client for the specified space."""
if space_id not in clients:
clients[space_id] = Client(space_id)
return clients[space_id]
@mcp.tool()
async def generate_image(prompt: str, space_id: str = "ysharma/SanaSprint") -> str:
"""Generate an image using Flux.
Args:
prompt: Text prompt describing the image to generate
space_id: HuggingFace Space ID to use
"""
client = get_client(space_id)
result = client.predict(
prompt=prompt,
model_size="1.6B",
seed=0,
randomize_seed=True,
width=1024,
height=1024,
guidance_scale=4.5,
num_inference_steps=2,
api_name="/infer"
)
return result
@mcp.tool()
async def run_dia_tts(prompt: str, space_id: str = "ysharma/Dia-1.6B") -> str:
"""Text-to-Speech Synthesis.
Args:
prompt: Text prompt describing the conversation between speakers S1, S2
space_id: HuggingFace Space ID to use
"""
client = get_client(space_id)
result = client.predict(
text_input=f"""{prompt}""",
audio_prompt_input=None,
max_new_tokens=3072,
cfg_scale=3,
temperature=1.3,
top_p=0.95,
cfg_filter_top_k=30,
speed_factor=0.94,
api_name="/generate_audio"
)
return result
if __name__ == "__main__":
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
mcp.run(transport='stdio')
此服务器公开了两个工具:
run_dia_tts
- 为给定文本记录生成对话,格式为 [S1]第一句。[S2]第二句。[S1]...
generate_image
- 使用快速文本到图像模型生成图像要将此 MCP 服务器与 Claude Desktop(作为 MCP 客户端)一起使用:
gradio_mcp_server.py
)pip install mcp gradio-client
~/Library/Application Support/Claude/claude_desktop_config.json
(macOS) 或 %APPDATA%\Claude\claude_desktop_config.json
(Windows) 配置 Claude Desktop 以使用您的服务器{
"mcpServers": {
"gradio-spaces": {
"command": "python",
"args": [
"/absolute/path/to/gradio_mcp_server.py"
]
}
}
}
现在,当您询问 Claude 关于生成图像或转录音频时,它可以使用您基于 Gradio 的工具来完成这些任务。
MCP 协议仍处于早期阶段,您可能会遇到连接到您构建的 MCP 服务器的问题。我们通常建议使用 MCP Inspector 工具尝试连接和调试您的 MCP 服务器。
以下是一些可能有所帮助的建议:
1. 确保您为函数提供了类型提示和有效的文档字符串
如前所述,Gradio 会读取您函数的文档字符串和输入参数的类型提示,以生成工具和参数的描述。一个有效的函数和文档字符串看起来像这样(注意“Args:”块及其下方缩进的参数名称):
def image_orientation(image: Image.Image) -> str:
"""
Returns whether image is portrait or landscape.
Args:
image (Image.Image): The image to check.
"""
return "Portrait" if image.height > image.width else "Landscape"
注意:您可以通过访问 http://your-server:port/gradio_api/mcp/schema
URL 预览为您的 MCP 服务器创建的模式。
2. 尝试接受输入参数为 str
一些 MCP 客户端不识别数字或其他复杂类型的参数,但我们测试过的所有 MCP 客户端都接受 str
输入参数。如有疑问,请将输入参数更改为 str
,然后在函数中将其转换为特定类型,如下例所示:
def prime_factors(n: str):
"""
Compute the prime factorization of a positive integer.
Args:
n (str): The integer to factorize. Must be greater than 1.
"""
n_int = int(n)
if n_int <= 1:
raise ValueError("Input must be an integer greater than 1.")
factors = []
while n_int % 2 == 0:
factors.append(2)
n_int //= 2
divisor = 3
while divisor * divisor <= n_int:
while n_int % divisor == 0:
factors.append(divisor)
n_int //= divisor
divisor += 2
if n_int > 1:
factors.append(n_int)
return factors
3. 确保您的 MCP 客户端支持 SSE
一些 MCP 客户端,特别是 Claude Desktop,尚不支持基于 SSE 的 MCP 服务器。在这种情况下,您可以使用 mcp-remote 等工具。首先安装 Node.js。然后,将以下内容添加到您自己的 MCP 客户端配置中:
{
"mcpServers": {
"gradio": {
"command": "npx",
"args": [
"mcp-remote",
"http://your-server:port/gradio_api/mcp/sse"
]
}
}
}
4. 重启您的 MCP 客户端和 MCP 服务器
一些 MCP 客户端要求您在每次更新 MCP 配置后重新启动它们。其他时候,如果 MCP 客户端和服务器之间的连接断开,您可能需要重新启动 MCP 服务器。如果所有其他方法都失败了,请尝试重新启动您的 MCP 客户端和 MCP 服务器!