在 Cloud Run 上构建和部署远程 MCP 服务器

本教程介绍了如何使用可流式传输的 HTTP 传输在 Cloud Run 上构建和部署远程模型上下文协议 (MCP) 服务器。借助可流式传输的 HTTP 传输,MCP 服务器可以作为独立进程运行,处理多个客户端连接。

准备工作

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  5. Make sure that billing is enabled for your Google Cloud project.

  6. 在 Google Cloud 项目中设置 Cloud Run 开发环境
  7. 确保您拥有部署服务所需的相应权限,并且您的账号已获授 Cloud Run Admin (roles/run.admin) 和 Service Account User (roles/iam.serviceAccountUser) 角色。
  8. 向您的账号授予 Cloud Run Invoker (roles/run.invoker) 角色。此角色允许远程 MCP 服务器访问 Cloud Run 服务。
  9. 了解如何授予角色

    控制台

    1. 在 Google Cloud 控制台中,前往 IAM 页面。

      前往 IAM
    2. 选择相应项目。
    3. 点击 授予访问权限
    4. 新的主账号字段中,输入您的用户标识符。这通常是用于部署 Cloud Run 服务的 Google 账号电子邮件地址。

    5. 选择角色列表中,选择一个角色。
    6. 如需授予其他角色,请点击 添加其他角色,然后依次添加所需角色。
    7. 点击保存

    gcloud

    如需向您在项目中的账号授予所需的 IAM 角色,请执行以下操作:

       gcloud projects add-iam-policy-binding PROJECT_ID \
           --member=PRINCIPAL \
           --role=ROLE
       

    您需要进行如下替换:

    • PROJECT_NUMBER:您的 Google Cloud 项目编号。
    • PROJECT_ID:您的 Google Cloud 项目 ID。
    • PRINCIPAL:您要向其授予角色的账号的电子邮件地址。
    • ROLE:您要添加到部署者账号的角色。
  10. 如果您通过网域限制组织政策来限制项目的未经身份验证的调用,则您需要按照测试专用服务中的说明访问已部署的服务。

  11. 安装 Uv(Python 软件包和项目管理器)。
  12. 准备 Python 项目

    以下步骤介绍了如何使用 uv 软件包管理器设置 Python 项目

    1. 创建一个名为 mcp-on-cloudrun 的文件夹,用于存储要部署的源代码:

        mkdir mcp-on-cloudrun
        cd mcp-on-cloudrun
      
    2. 使用 uv 工具创建一个 Python 项目,以生成 pyproject.toml 文件:

        uv init --name "mcp-on-cloudrun" --description "Example of deploying an MCP server on Cloud Run" --bare --python 3.10
      

      uv init 命令会创建以下 pyproject.toml 文件:

      [project]
      name = "mcp-server"
      version = "0.1.0"
      description = "Example of deploying an MCP server on Cloud Run"
      readme = "README.md"
      requires-python = ">=3.10"
      dependencies = []
      
    3. 创建以下其他新文件:

      • server.py(适用于 MCP 服务器源代码)
      • test_server.py 来测试远程服务器
      • 用于部署到 Cloud Run 的 Dockerfile
      touch server.py test_server.py Dockerfile
      

      您的项目目录应包含以下结构:

      ├── mcp-on-cloudrun
      │   ├── pyproject.toml
      │   ├── server.py
      │   ├── test_server.py
      │   └── Dockerfile
      

    创建用于数学运算的 MCP 服务器

    为了提供有价值的背景信息,以便改进 LLM 与 MCP 的搭配使用,请使用 FastMCP 设置数学 MCP 服务器。FastMCP 提供了一种使用 Python 快速构建 MCP 服务器和客户端的方法。

    请按照以下步骤创建用于执行加法和减法等数学运算的 MCP 服务器。

    1. 运行以下命令,将 FastMCP 添加为 pyproject.toml 文件中的依赖项:

      uv add fastmcp==2.8.0 --no-sync
      
    2. server.py 文件中添加以下数学 MCP 服务器源代码:

      import asyncio
      import logging
      import os
      
      from fastmcp import FastMCP 
      
      logger = logging.getLogger(__name__)
      logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO)
      
      mcp = FastMCP("MCP Server on Cloud Run")
      
      @mcp.tool()
      def add(a: int, b: int) -> int:
          """Use this to add two numbers together.
      
          Args:
              a: The first number.
              b: The second number.
      
          Returns:
              The sum of the two numbers.
          """
          logger.info(f">>> 🛠️ Tool: 'add' called with numbers '{a}' and '{b}'")
          return a + b
      
      @mcp.tool()
      def subtract(a: int, b: int) -> int:
          """Use this to subtract two numbers.
      
          Args:
              a: The first number.
              b: The second number.
      
          Returns:
              The difference of the two numbers.
          """
          logger.info(f">>> 🛠️ Tool: 'subtract' called with numbers '{a}' and '{b}'")
          return a - b
      
      if __name__ == "__main__":
          logger.info(f"🚀 MCP server started on port {os.getenv('PORT', 8080)}")
          # Could also use 'sse' transport, host="0.0.0.0" required for Cloud Run.
          asyncio.run(
              mcp.run_async(
                  transport="streamable-http",
                  host="0.0.0.0",
                  port=os.getenv("PORT", 8080),
              )
          )
      
    3. 在 Dockerfile 中添加以下代码,以使用 uv 工具运行 server.py 文件:

      # Use the official Python image
      FROM python:3.13-slim
      
      # Install uv
      COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
      
      # Install the project into /app
      COPY . /app
      WORKDIR /app
      
      # Allow statements and log messages to immediately appear in the logs
      ENV PYTHONUNBUFFERED=1
      
      # Install dependencies
      RUN uv sync
      
      EXPOSE $PORT
      
      # Run the FastMCP server
      CMD ["uv", "run", "server.py"]
      

    部署到 Cloud Run

    您可以将 MCP 服务器部署为容器映像源代码

    容器映像

    如需部署打包为容器映像的 MCP 服务器,请按照以下说明操作。

    1. 创建 Artifact Registry 制品库以存储容器映像:

      gcloud artifacts repositories create remote-mcp-servers \
      --repository-format=docker \
      --location=us-central1 \
      --description="Repository for remote MCP servers" \
      --project=PROJECT_ID
      
    2. 使用 Cloud Build 构建容器映像并将其推送到 Artifact Registry:

      gcloud builds submit --region=us-central1 --tag us-central1-docker.pkg.dev/PROJECT_ID/remote-mcp-servers/mcp-server:latest
      
    3. 将 MCP 服务器容器映像部署到 Cloud Run:

      gcloud run deploy mcp-server \
      --image us-central1-docker.pkg.dev/PROJECT_ID/remote-mcp-servers/mcp-server:latest \
      --region=us-central1 \
      --no-allow-unauthenticated
      

    源代码

    您可以从远程 MCP 服务器的来源将其部署到 Cloud Run。

    通过运行以下命令从源代码进行部署:

    gcloud run deploy mcp-server --no-allow-unauthenticated --region=us-central1 --source .
    

    对 MCP 客户端进行身份验证

    如果您使用 --no-allow-unauthenticated 标志部署了服务,则连接到远程 MCP 服务器的任何 MCP 客户端都必须进行身份验证。

    1. 向服务账号授予 Cloud Run Invoker (roles/run.invoker) 角色。此 Identity and Access Management 政策绑定可确保使用强大的安全机制来验证本地 MCP 客户端的身份。

    2. 运行 Cloud Run 代理,以在本地机器上创建通往远程 MCP 服务器的经过身份验证的隧道:

      gcloud run services proxy mcp-server --region=us-central1
      

      如果尚未安装 Cloud Run 代理,此命令会提示您下载该代理。按照提示下载并安装代理。

    Cloud Run 会对流向 http://127.0.0.1:8080 的所有流量进行身份验证,并将请求转发到远程 MCP 服务器。

    测试远程 MCP 服务器

    您可以使用 FastMCP 客户端并访问网址 http://127.0.0.1:8080/mcp 来测试并连接到远程 MCP 服务器。

    如需测试和调用加减机制,请按以下步骤操作:

    1. 在运行测试服务器之前,请运行 Cloud Run 代理

    2. 创建一个名为 test_server.py 的测试文件,并添加以下代码:

      import asyncio
      
      from fastmcp import Client
      
      async def test_server():
          # Test the MCP server using streamable-http transport.
          # Use "/sse" endpoint if using sse transport.
          async with Client("http://localhost:8080/mcp") as client:
              # List available tools
              tools = await client.list_tools()
              for tool in tools:
                  print(f">>> 🛠️  Tool found: {tool.name}")
              # Call add tool
              print(">>> 🪛  Calling add tool for 1 + 2")
              result = await client.call_tool("add", {"a": 1, "b": 2})
              print(f"<<< ✅ Result: {result[0].text}")
              # Call subtract tool
              print(">>> 🪛  Calling subtract tool for 10 - 3")
              result = await client.call_tool("subtract", {"a": 10, "b": 3})
              print(f"<<< ✅ Result: {result[0].text}")
      
      if __name__ == "__main__":
          asyncio.run(test_server())
    3. 在新终端中,运行测试服务器:

      uv run test_server.py
      

      您应该会看到以下输出内容:

       🛠️ Tool found: add
       🛠️ Tool found: subtract
       🪛 Calling add tool for 1 + 2
       ✅ Result: 3
       🪛 Calling subtract tool for 10 - 3
       ✅ Result: 7
      

    后续步骤