Gradio Agents & MCP 黑客马拉松

获奖者
Gradio logo
  1. 其他教程
  2. 使用 Gradio 构建 MCP 服务器

使用 Gradio 构建 MCP 服务器

本指南将介绍如何启动您的 Gradio 应用程序,使其作为 MCP 服务器运行。

核心要点:只需在 .launch() 中设置 mcp_server=True 即可。

先决条件

如果尚未安装,请安装带有 MCP 额外功能的 Gradio。

pip install "gradio[mcp]"

这将安装必要的依赖项,包括 mcp 包。此外,您需要一个支持使用 MCP 协议进行工具调用的 LLM 应用程序,例如 Claude Desktop、Cursor 或 Cline(这些被称为“MCP 客户端”)。

什么是 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 服务器所需的一切!现在,当您运行此应用时,它将:

  1. 启动常规 Gradio Web 界面
  2. 启动 MCP 服务器
  3. 在控制台中打印 MCP 服务器 URL

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”来找到要复制粘贴的确切配置。)

Gradio 与 MCP 集成的关键特性

  1. 工具转换:您的 Gradio 应用中的每个 API 端点都会自动转换为一个 MCP 工具,并具有相应的名称、描述和输入模式。要查看工具和模式,请访问 http://your-server:port/gradio_api/mcp/schema 或点击 Gradio 应用页脚中的“查看 API”链接,然后点击“MCP”。
  1. 环境变量支持。有两种方法可以启用 MCP 服务器功能:
  • 如上所示,使用 mcp_server 参数

    demo.launch(mcp_server=True)
  • 使用环境变量

    export GRADIO_MCP_SERVER=True
  1. 文件处理:服务器自动处理文件数据转换,包括:

    • 将 base64 编码的字符串转换为文件数据

    • 处理图像文件并以正确格式返回

    • 管理临时文件存储

      强烈建议将输入图像和文件作为完整 URL(“http://...”或“https:/...”)传递,因为 MCP 客户端并非总能正确处理本地文件。

  1. Hugging Face Spaces 上的托管 MCP 服务器:您可以在 Hugging Face Spaces 上免费发布您的 Gradio 应用程序,这将允许您拥有一个免费的托管 MCP 服务器。以下是此类 Space 的示例:https://hugging-face.cn/spaces/abidlabs/mcp-tools。请注意,您可以将此配置添加到您的 MCP 客户端,以便立即开始使用此 Space 中的工具:
{
  "mcpServers": {
    "gradio": {
      "url": "https://abidlabs-mcp-tools.hf.space/gradio_api/mcp/sse"
    }
  }
}

转换现有空间

如果您想将现有空间用作 MCP 服务器,您需要做三件事:

  1. 首先,如果它不是您自己的空间,请复制该空间。这将允许您对应用程序进行更改。如果该空间需要 GPU,请将复制空间的硬件设置为与原始空间相同。您可以将其设为公共空间或私有空间,因为这两种类型都可以用作 MCP 服务器,如下所述。
  2. 然后,为您希望 LLM 能够作为工具调用的函数添加文档字符串。文档字符串应与上述示例代码的格式相同。
  3. 最后,在 .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 的工具

到目前为止,我们所有的 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 服务器。但仍有一些限制需要注意:

  1. 无法在 MCP 工具调用中识别特定用户。这意味着您无法在 Gradio 应用程序中存储调用之间的用户状态。如果您在应用程序中使用 gr.State 组件,它将始终以其原始默认值传递。

  2. 您无法选择 Gradio 中要公开为工具的特定端点(所有 show_api=True 的端点都被视为工具),也无法更改工具的描述,除非您更改函数的文档字符串。

如果您需要克服这些限制,您将需要创建一个自定义 MCP 服务器来调用您的 Gradio 应用程序,我们将在下面进行描述。

自定义 MCP 服务器

在某些情况下,您可能需要手动创建一个 MCP 服务器,该服务器内部调用 Gradio 应用程序。当您希望执行以下操作时,此方法非常有用:

  • 选择更大的 Gradio 应用程序中的特定端点作为工具
  • 自定义工具呈现给 LLM 的方式(例如,更改工具名称、模式或描述)
  • 当工具被调用时启动 Gradio 应用程序 MCP 服务器(如果您在本地运行多个 Gradio 应用程序并希望节省内存/GPU)
  • 使用不同于 SSE 的 MCP 协议

由于有了 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')

此服务器公开了两个工具:

  1. run_dia_tts - 为给定文本记录生成对话,格式为 [S1]第一句。[S2]第二句。[S1]...
  2. generate_image - 使用快速文本到图像模型生成图像

要将此 MCP 服务器与 Claude Desktop(作为 MCP 客户端)一起使用:

  1. 将代码保存到一个文件(例如 gradio_mcp_server.py
  2. 安装所需的依赖项:pip install mcp gradio-client
  3. 通过编辑配置文件在 ~/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"
            ]
        }
    }
}
  1. 重启 Claude Desktop

现在,当您询问 Claude 关于生成图像或转录音频时,它可以使用您基于 Gradio 的工具来完成这些任务。

MCP 服务器故障排除

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 服务器!