1. 简介
概览
在本实验中,您将构建和部署 Model Context Protocol (MCP) 服务器。MCP 服务器有助于为 LLM 提供对外部工具和服务的访问权限。您将 MCP 服务器配置为 Cloud Run 上安全且可用于生产用途的服务,该服务可供多个客户端访问。然后,您将从 Antigravity CLI 连接到远程 MCP 服务器。
您将执行的操作
我们将使用 FastMCP 创建一个具有两个工具的 zoo MCP 服务器 :get_animals_by_species 和 get_animal_details。FastMCP 提供了一种使用 Python 快速构建 MCP 服务器和客户端的方法。

学习内容
- 将 MCP 服务器部署到 Cloud Run。
- 通过要求对所有请求进行身份验证来保护服务器的端点,确保只有经过授权的客户端和智能体才能与服务器通信。
- 从 Antigravity CLI 连接到安全的 MCP 服务器端点
2. 项目设置
- 如果您还没有 Google 账号,则必须先创建一个 Google 账号。
- 请使用个人账号,而不是工作或学校账号。工作和学校账号可能会受到限制,导致您无法启用本实验所需的 API。
- 登录 Google Cloud 控制台。
- 创建新项目,或选择重复使用现有项目。
- 如果您看到有关项目配额的错误,请重复使用现有项目或删除现有项目以创建新项目。
3. 打开 Cloud Shell Editor
- 点击此链接可直接前往 Cloud Shell Editor
- 如果系统在今天任何时间提示您授权,请点击授权以继续。

- 如果终端未显示在屏幕底部,请打开它:
- 点击查看
- 点击终端

- 在终端中,使用以下命令设置项目:
- 格式:
gcloud config set project [PROJECT_ID] - 示例:
gcloud config set project lab-project-id-example - 如果您不记得项目 ID,可以执行以下操作:
- 您可以使用以下命令列出所有项目 ID:
gcloud projects list | awk '/PROJECT_ID/{print $2}'

- 您可以使用以下命令列出所有项目 ID:
- 格式:
- 您应会看到以下消息:
如果您看到Updated property [core/project].
WARNING并被问到Do you want to continue (Y/n)?,则可能是输入的项目 ID 不正确。按n,按Enter,然后尝试再次运行gcloud config set project命令。
4. 启用 API
在终端中,启用以下 API:
gcloud services enable \
run.googleapis.com \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com
如果系统提示您授权,请点击授权以继续。
此命令可能需要几分钟才能完成,但最终应生成类似于以下内容的成功消息:
Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.
5. 准备 Python 项目
- 创建一个名为
mcp-on-cloudrun的文件夹,用于存储要部署的源代码:mkdir mcp-on-cloudrun && cd mcp-on-cloudrun - 使用
uv工具创建一个 Python 项目,以生成pyproject.toml文件:uv init --description "Example of deploying an MCP server on Cloud Run" --bare --python 3.13uv init命令会为您的项目创建一个pyproject.toml文件。如需查看该文件的内容,请运行以下命令: 输出应如下所示:cat pyproject.toml[project] name = "mcp-on-cloudrun" version = "0.1.0" description = "Example of deploying an MCP server on Cloud Run" requires-python = ">=3.13" dependencies = []
6. 创建 zoo MCP 服务器
为了提供有价值的背景信息,以便改进 LLM 与 MCP 的搭配使用,请使用 FastMCP 设置 zoo MCP 服务器。FastMCP 是一个用于处理 Model Context Protocol 的标准框架。FastMCP 提供了一种使用 Python 快速构建 MCP 服务器和客户端的方法。此 MCP 服务器提供有关虚构动物园中动物的数据。为简单起见,我们将数据存储在内存中。对于生产 MCP 服务器,您可能需要提供来自数据库或 API 等来源的数据。
- 运行以下命令,将 FastMCP 添加为
pyproject.toml文件中的依赖项: 这会将uv add fastmcp==2.12.4 --no-syncuv.lock文件添加到您的项目中。 - 为 MCP 服务器源代码创建并打开新的
server.py文件:cloudshell edit ~/mcp-on-cloudrun/server.pycloudshell edit命令会在终端上方的编辑器中打开server.py文件。 - 在
server.py文件中添加以下 zoo MCP 服务器源代码:import asyncio import logging import os from typing import List, Dict, Any from fastmcp import FastMCP logger = logging.getLogger(__name__) logging.basicConfig(format="[%(levelname)s]: %(message)s", level=logging.INFO) mcp = FastMCP("Zoo Animal MCP Server 🦁🐧🐻") # Dictionary of animals at the zoo ZOO_ANIMALS = [ { "species": "lion", "name": "Leo", "age": 7, "enclosure": "The Big Cat Plains", "trail": "Savannah Heights" }, { "species": "lion", "name": "Nala", "age": 6, "enclosure": "The Big Cat Plains", "trail": "Savannah Heights" }, { "species": "lion", "name": "Simba", "age": 3, "enclosure": "The Big Cat Plains", "trail": "Savannah Heights" }, { "species": "lion", "name": "King", "age": 8, "enclosure": "The Big Cat Plains", "trail": "Savannah Heights" }, { "species": "penguin", "name": "Waddles", "age": 2, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "penguin", "name": "Pip", "age": 4, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "penguin", "name": "Skipper", "age": 5, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "penguin", "name": "Chilly", "age": 3, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "penguin", "name": "Pingu", "age": 6, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "penguin", "name": "Noot", "age": 1, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "elephant", "name": "Ellie", "age": 15, "enclosure": "The Pachyderm Sanctuary", "trail": "Savannah Heights" }, { "species": "elephant", "name": "Peanut", "age": 12, "enclosure": "The Pachyderm Sanctuary", "trail": "Savannah Heights" }, { "species": "elephant", "name": "Dumbo", "age": 5, "enclosure": "The Pachyderm Sanctuary", "trail": "Savannah Heights" }, { "species": "elephant", "name": "Trunkers", "age": 10, "enclosure": "The Pachyderm Sanctuary", "trail": "Savannah Heights" }, { "species": "bear", "name": "Smokey", "age": 10, "enclosure": "The Grizzly Gulch", "trail": "Polar Path" }, { "species": "bear", "name": "Grizzly", "age": 8, "enclosure": "The Grizzly Gulch", "trail": "Polar Path" }, { "species": "bear", "name": "Barnaby", "age": 6, "enclosure": "The Grizzly Gulch", "trail": "Polar Path" }, { "species": "bear", "name": "Bruin", "age": 12, "enclosure": "The Grizzly Gulch", "trail": "Polar Path" }, { "species": "giraffe", "name": "Gerald", "age": 4, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "giraffe", "name": "Longneck", "age": 5, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "giraffe", "name": "Patches", "age": 3, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "giraffe", "name": "Stretch", "age": 6, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "antelope", "name": "Speedy", "age": 2, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "antelope", "name": "Dash", "age": 3, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "antelope", "name": "Gazelle", "age": 4, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "antelope", "name": "Swift", "age": 5, "enclosure": "The Tall Grass Plains", "trail": "Savannah Heights" }, { "species": "polar bear", "name": "Snowflake", "age": 7, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "polar bear", "name": "Blizzard", "age": 5, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "polar bear", "name": "Iceberg", "age": 9, "enclosure": "The Arctic Exhibit", "trail": "Polar Path" }, { "species": "walrus", "name": "Wally", "age": 10, "enclosure": "The Walrus Cove", "trail": "Polar Path" }, { "species": "walrus", "name": "Tusker", "age": 12, "enclosure": "The Walrus Cove", "trail": "Polar Path" }, { "species": "walrus", "name": "Moby", "age": 8, "enclosure": "The Walrus Cove", "trail": "Polar Path" }, { "species": "walrus", "name": "Flippers", "age": 9, "enclosure": "The Walrus Cove", "trail": "Polar Path" } ] @mcp.tool() def get_animals_by_species(species: str) -> List[Dict[str, Any]]: """ Retrieves all animals of a specific species from the zoo. Can also be used to collect the base data for aggregate queries of animals of a specific species - like counting the number of penguins or finding the oldest lion. Args: species: The species of the animal (e.g., 'lion', 'penguin'). Returns: A list of dictionaries, where each dictionary represents an animal and contains details like name, age, enclosure, and trail. """ logger.info(f">>> 🛠️ Tool: 'get_animals_by_species' called for '{species}'") return [animal for animal in ZOO_ANIMALS if animal["species"].lower() == species.lower()] @mcp.tool() def get_animal_details(name: str) -> Dict[str, Any]: """ Retrieves the details of a specific animal by its name. Args: name: The name of the animal. Returns: A dictionary with the animal's details (species, name, age, enclosure, trail) or an empty dictionary if the animal is not found. """ logger.info(f">>> 🛠️ Tool: 'get_animal_details' called for '{name}'") for animal in ZOO_ANIMALS: if animal["name"].lower() == name.lower(): return animal return {} if __name__ == "__main__": port = int(os.getenv("PORT", 8080)) logger.info(f"🚀 MCP server started on port {port}") asyncio.run( mcp.run_async( transport="http", host="0.0.0.0", port=port, ) )
您的代码已完成!现在可以将 MCP 服务器部署到 Cloud Run 了。
7. 部署至 Cloud Run
现在,直接从源代码将 MCP 服务器部署到 Cloud Run。
- 创建并打开新的
Dockerfile以部署到 Cloud Run:cloudshell edit ~/mcp-on-cloudrun/Dockerfile - 在 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"] - 创建一个名为
mcp-server-sa的服务账号:gcloud iam service-accounts create mcp-server-sa --display-name="MCP Server Service Account" - 运行
gcloud命令,将应用部署到 Cloud Run 使用cd ~/mcp-on-cloudrun gcloud run deploy zoo-mcp-server \ --service-account=mcp-server-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --no-allow-unauthenticated \ --region=us-west1 \ --source=. \ --labels=dev-tutorial=codelab-mcp--no-allow-unauthenticated标志来要求进行身份验证。这对于安全至关重要。如果您不要求进行身份验证,任何人都可以调用您的 MCP 服务器,并可能对您的系统造成损害。 - 确认创建新的 Artifact Registry 代码库。由于您是首次从源代码部署到 Cloud Run,因此您会看到:
输入Deploying from source requires an Artifact Registry Docker repository to store built containers. A repository named [cloud-run-source-deploy] in region [us-west1] will be created. Do you want to continue (Y/n)?
Y并按Enter,系统会为您的部署创建一个 Artifact Registry 代码库。这是存储 Cloud Run 服务的 MCP 服务器 Docker 容器所必需的。 - 几分钟后,您会看到类似以下内容的消息:
Service [zoo-mcp-server] revision [zoo-mcp-server-12345-abc] has been deployed and is serving 100 percent of traffic.
您已部署 MCP 服务器。现在可以使用它了。
8. 将远程 MCP 服务器添加到 Antigravity CLI
现在,您已成功部署远程 MCP 服务器,可以使用各种应用(例如 Google Code Assist 或 Antigravity CLI)连接到该服务器。在本部分中,我们将使用 Antigravity CLI 与新的远程 MCP 服务器建立连接。
- 向您的用户账号授予调用远程 MCP 服务器的权限
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \ --member=user:$(gcloud config get-value account) \ --role='roles/run.invoker' - 使用以下命令,将您的 Google Cloud 凭据和项目编号保存在环境变量中,以便在 Antigravity 设置文件中使用:
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)") export ID_TOKEN=$(gcloud auth print-identity-token) - 如果尚未创建
.gemini/antigravity-cli文件夹,请创建一个mkdir -p ~/.gemini/antigravity-cli - 将远程 MCP 服务器写入 Antigravity CLI MCP 配置文件:
cat > ~/.gemini/antigravity-cli/mcp_config.json << EOF { "mcpServers": { "zoo-remote": { "serverUrl": "https://zoo-mcp-server-${PROJECT_NUMBER}.us-west1.run.app/mcp", "headers": { "Authorization": "Bearer ${ID_TOKEN}" } } } } EOF - 启动 Antigravity CLI:
agy
- 使用 Antigravity CLI 进行身份验证:首次启动时,需要进行身份验证。选择 OAuth(按
Enter)。
- 点击链接(如果无法点击,请在 Cloud Shell 中突出显示网址以复制,然后将其粘贴到浏览器中)
- 登录您的 Google 账号
- 复制代码
- 将代码粘贴到 Cloud Shell Editor 终端中
- 按
Enter。
- 按
Enter接受一些默认设置。 - 让 Antigravity CLI 列出其上下文中可用的 MCP 工具
按/mcpESC返回到提示框。 - 让 Antigravity CLI 帮忙寻找动物园中的动物
Antigravity CLI 应该知道要使用Where can I find penguins?zoo-remoteMCP 服务器,并询问您是否允许执行 MCP。 - 使用向下箭头,然后按
Enter进行选择Yes, always allow all tools from server "zoo-remote"

输出应显示正确答案,并显示一个框,表明使用了 MCP 服务器。

您已完成!您已成功将远程 MCP 服务器部署到 Cloud Run,并使用 Antigravity CLI 对其进行了测试。
准备好结束会话后,输入 /exit,然后按 Enter 退出 Antigravity CLI。
调试
如果您看到类似这样的错误:
🔍 Attempting OAuth discovery for 'zoo-remote'... ❌ 'zoo-remote' requires authentication but no OAuth configuration found Error connecting to MCP server 'zoo-remote': MCP server 'zoo-remote' requires authentication. Please configure OAuth or check server settings.
可能是 ID 令牌已超时,需要重新设置 ID_TOKEN。
- 输入
/exit,然后按Enter退出 Antigravity CLI。 - 在终端中设置项目
gcloud config set project [PROJECT_ID] - 重新运行 Google Cloud 凭据命令以获取新的
ID_TOKEN(因为您的凭据可能已过期),并重写配置文件:export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)") export ID_TOKEN=$(gcloud auth print-identity-token) cat > ~/.gemini/antigravity-cli/mcp_config.json << EOF
{ "mcpServers": { "zoo-remote": { "serverUrl": "https://zoo-mcp-server-${PROJECT_NUMBER}.us-west1.run.app/mcp", "headers": { "Authorization": "Bearer ${ID_TOKEN}" } } } } EOF ```
9. (可选)验证服务器日志中的工具调用
如需验证 Cloud Run MCP 服务器是否被调用,请检查服务日志。
gcloud run services logs read zoo-mcp-server --region us-west1 --limit=5
您应该会看到一个输出日志,确认已进行工具调用。🛠️
2025-08-05 19:50:31 INFO: 169.254.169.126:39444 - "POST /mcp HTTP/1.1" 200 OK 2025-08-05 19:50:31 [INFO]: Processing request of type CallToolRequest 2025-08-05 19:50:31 [INFO]: >>> 🛠️ Tool: 'get_animals_by_species' called for 'penguin'
10. (可选)向服务器添加 MCP 提示
MCP 提示可以为经常运行的提示创建简写,从而加快工作流程。
Antigravity CLI 会自动将 MCP 提示转换为 自定义斜杠命令,以便您可以通过输入 /prompt_name 来调用 MCP 提示,其中 prompt_name 是您的 MCP 提示的名称。
创建一个 MCP 提示,以便您可以通过在 Antigravity CLI 中输入 /find animal 来快速查找动物园中的动物。
- 将此代码添加到
server.py文件中的主保护语句 (if __name__ == "__main__":) 上方@mcp.prompt() def find(animal: str) -> str: """ Find which exhibit and trail a specific animal might be located. """ return ( f"Please find the exhibit and trail information for {animal} in the zoo. " f"Respond with '[animal] can be found in the [exhibit] on the [trail].'" f"Example: Penguins can be found in The Arctic Exhibit on the Polar Path." ) - 将应用重新部署到 Cloud Run
gcloud run deploy zoo-mcp-server \ --region=us-west1 \ --source=. \ --labels=dev-tutorial=codelab-mcp - 刷新 ID_TOKEN 并重新创建配置文件:
export ID_TOKEN=$(gcloud auth print-identity-token) export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)") cat > ~/.gemini/antigravity-cli/mcp_config.json << EOF
{ "mcpServers": { "zoo-remote": { "serverUrl": "https://zoo-mcp-server-${PROJECT_NUMBER}.us-west1.run.app/mcp", "headers": { "Authorization": "Bearer ${ID_TOKEN}" } } } } EOF ```
- 部署应用的新版本后,启动 Antigravity CLI。
agy - 在提示中使用您创建的新自定义命令:
/find lions
您应该会看到 Antigravity CLI 调用 get_animals_by_species 工具,并按照 MCP 提示的指示设置回答格式!
╭───────────────────────────╮
│ > /find lions │
╰───────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✔ get_animals_by_species (zoo-remote MCP Server) get_animals_by_species (zoo-remote MCP Server) │
│ │
│ [{"species":"lion","name":"Leo","age":7,"enclosure":"The Big Cat │
│ Plains","trail":"Savannah │
│ Heights"},{"species":"lion","name":"Nala","age":6,"enclosure":"The Big Cat │
│ Plains","trail":"Savannah │
│ Heights"},{"species":"lion","name":"Simba","age":3,"enclosure":"The Big Cat │
│ Plains","trail":"Savannah │
│ Heights"},{"species":"lion","name":"King","age":8,"enclosure":"The Big Cat │
│ Plains","trail":"Savannah Heights"}] │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Lions can be found in The Big Cat Plains on the Savannah Heights.
11. (可选)使用 Gemini Flash Lite 获得更快的响应
Antigravity CLI 可让您选择使用的模型和工作量。
由于与查找动物园中的动物相关的请求不需要思考或推理,因此请尝试使用更快的模型来加快速度。
在上一部分中,您创建了一个 MCP 提示,以便您可以通过在 Antigravity CLI 中输入 /find animal 来快速查找动物园中的动物。
- 部署应用的新版本后,启动 Antigravity CLI。
agy --model=gemini-3.6-flash --effort=low - 在提示中使用您创建的新自定义命令:
/find lions
您应该仍然会看到 Antigravity CLI 调用 get_animals_by_species 工具,并按照 MCP 提示的指示设置回答格式,但答案应该会更快显示!
╭───────────────────────────╮
│ > /find lions │
╰───────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✔ get_animals_by_species (zoo-remote MCP Server) get_animals_by_species (zoo-remote MCP Server) │
│ │
│ [{"species":"lion","name":"Leo","age":7,"enclosure":"The Big Cat │
│ Plains","trail":"Savannah │
│ Heights"},{"species":"lion","name":"Nala","age":6,"enclosure":"The Big Cat │
│ Plains","trail":"Savannah │
│ Heights"},{"species":"lion","name":"Simba","age":3,"enclosure":"The Big Cat │
│ Plains","trail":"Savannah │
│ Heights"},{"species":"lion","name":"King","age":8,"enclosure":"The Big Cat │
│ Plains","trail":"Savannah Heights"}] │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Lions can be found in The Big Cat Plains on the Savannah Heights.
调试
如果您看到类似这样的错误:
✕ Unknown command: /find lions
尝试运行 /mcp,如果输出 zoo-remote - Disconnected,您可能需要重新部署,或再次运行以下命令:
gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
--member=user:$(gcloud config get-value account) \
--role='roles/run.invoker'
export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
export ID_TOKEN=$(gcloud auth print-identity-token)
cat > ~/.gemini/antigravity-cli/mcp_config.json << EOF
{
"mcpServers": {
"zoo-remote": {
"serverUrl": "https://zoo-mcp-server-${PROJECT_NUMBER}.us-west1.run.app/mcp",
"headers": {
"Authorization": "Bearer ${ID_TOKEN}"
}
}
}
}
EOF
12. 总结
恭喜!您已成功部署并连接到安全的远程 MCP 服务器。
继续学习下一项实验
本实验是三部分系列实验中的第一项实验。在第二项实验中,您将使用您创建的 MCP 服务器和 ADK 智能体。
在 Cloud Run 上使用 MCP 服务器和 ADK 智能体
(可选)清理
如果您不打算继续学习下一项实验,并且想要清理已创建的内容,可以删除云项目,以免产生额外费用。
虽然 Cloud Run 不会对未在使用中的服务计费,但您可能仍然需要支付将容器映像存储在 Artifact Registry 中而产生的相关费用。删除 Cloud 项目后,系统即会停止对该项目中使用的所有资源计费。
如果您愿意,可以删除项目:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
您可能还需要从 cloudshell 磁盘中删除不必要的资源。您可以:
- 删除 Codelab 项目目录:
rm -rf ~/mcp-on-cloudrun - 警告!此操作无法撤消!如果您想删除 Cloud Shell 中的所有内容以释放空间,可以删除整个主目录。请注意,您要保留的所有内容都已保存在其他位置。
sudo rm -rf $HOME