如何在 Cloud Run 上部署安全的 Genkit MCP 服务器

1. 简介

概览

在本实验中,您将构建并部署 Model Context Protocol (MCP) 服务器。MCP 服务器可用于为 LLM 提供对外部工具和服务的访问权限。您将它配置为 Cloud Run 上可供多个客户端访问的安全的生产就绪型服务。然后,您将从 Gemini CLI 连接到远程 MCP 服务器。

您将执行的操作

我们将使用 Genkit 创建一个包含两个工具(get_animals_by_speciesget_animal_details)的 zoo MCP 服务器。Genkit 提供了一种使用 Node.js 快速构建 MCP 服务器和客户端的方法。

动物园 MCP 服务器图形

学习内容

  • 将 MCP 服务器部署到 Cloud Run。
  • 通过要求对所有请求进行身份验证来保护服务器的端点,确保只有经过授权的客户端和代理才能与服务器通信。
  • 从 Gemini CLI 连接到安全的 MCP 服务器端点

2. 项目设置

  1. 如果您还没有 Google 账号,则必须先创建一个 Google 账号
    • 请改用个人账号,而非工作账号或学校账号。工作账号和学校账号可能存在限制,导致您无法启用本实验所需的 API。
  2. 登录 Google Cloud 控制台
  3. 在 Cloud 控制台中启用结算功能
    • 完成本实验的 Cloud 资源费用应低于 1 美元。
    • 您可以按照本实验末尾的步骤删除资源,以避免产生更多费用。
    • 新用户符合参与 $300 USD 免费试用计划的条件。
  4. 创建新项目或选择重复使用现有项目。
    • 如果您看到有关项目配额的错误,请重复使用现有项目或删除现有项目以创建新项目。

3. 打开 Cloud Shell Editor

  1. 点击此链接可直接前往 Cloud Shell 编辑器
  2. 如果系统在今天任何时间提示您进行授权,请点击授权继续。点击以授权 Cloud Shell
  3. 如果终端未显示在屏幕底部,请打开它:
    • 点击查看
    • 点击终端在 Cloud Shell 编辑器中打开新终端
  4. 在终端中,使用以下命令设置项目:
    • 格式:
      gcloud config set project [PROJECT_ID]
      
    • 示例:
      gcloud config set project lab-project-id-example
      
    • 如果您不记得项目 ID,请执行以下操作:
      • 您可以使用以下命令列出所有项目 ID:
        gcloud projects list | awk '/PROJECT_ID/{print $2}'
        
      在 Cloud Shell 编辑器终端中设置项目 ID
  5. 您应会看到以下消息:
    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

如果系统提示您进行授权,请点击授权以继续。点击以授权 Cloud Shell

此命令可能需要几分钟时间才能完成,但最终应会生成类似如下所示的成功消息:

Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.

5. 准备 JavaScript 项目

  1. 创建一个名为 mcp-on-cloudrun 的文件夹,用于存储要部署的源代码:
    mkdir mcp-on-cloudrun && cd mcp-on-cloudrun
    
  2. 使用 npm 工具创建一个 Node.js 项目,以生成 package.json 文件:
    npm init es6 -y
    
    npm init 命令会为您的项目创建一个 package.json 文件。
  3. 安装 @modelcontextprotocol/sdkexpresszod 依赖项:
    npm install @modelcontextprotocol/sdk express zod
    

6. 创建动物园 MCP 服务器

为了提供有价值的背景信息,以便改进 LLM 与 MCP 的搭配使用,请使用 Genkit(一种用于处理 Model Context Protocol 的标准框架)设置动物园 MCP 服务器。Genkit 提供了一种使用 Node.js 快速构建 MCP 服务器和客户端的方法。此 MCP 服务器提供有关虚构动物园中动物的数据。为简单起见,我们将数据存储在内存中。对于生产 MCP 服务器,您可能需要提供来自数据库或 API 等来源的数据。

  1. 运行以下命令,将 Genkit 添加为 package.json 文件中的依赖项:
    npm install genkit
    
    这会将 package-lock.json 文件添加到您的项目中。
  2. 运行以下命令,在 package.json 文件中添加 Genkit AI MCP 库:
    npm install @genkit-ai/mcp
    
  3. 为 MCP 服务器源代码创建并打开新的 index.js 文件:
    cloudshell edit index.js
    
    cloudshell edit 命令会在终端上方的编辑器中打开 index.js 文件。
  4. index.js 文件中添加以下动物园 MCP 服务器源代码:
    import express from 'express';
    import { genkit, z } from 'genkit';
    import { createMcpServer } from '@genkit-ai/mcp';
    import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
    
    // Dictionary of animals at the zoo
    const 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"
        }
    ];
    
    // Initialize Genkit
    const ai = genkit({});
    
    // Define tools using Genkit
    ai.defineTool(
        {
            name: 'get_animals_by_species',
            description: "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.",
            inputSchema: z.object({ species: z.string() }),
        },
        async ({ species }) => {
            console.log(`>>> 🛠️ Tool: 'get_animals_by_species' called for '${species}'`);
            const animals = ZOO_ANIMALS.filter(animal => animal.species.toLowerCase() === species.toLowerCase());
            return animals;
        }
    );
    
    ai.defineTool(
        {
            name: 'get_animal_details',
            description: "Retrieves the details of a specific animal by its name.",
            inputSchema: z.object({ name: z.string() }),
        },
        async ({ name }) => {
            console.log(`>>> 🛠️ Tool: 'get_animal_details' called for '${name}'`);
            const animal = ZOO_ANIMALS.find(a => a.name.toLowerCase() === name.toLowerCase());
            return animal;
        }
    );
    
    // Create Genkit MCP server wrapper
    const mcpWrapper = createMcpServer(ai, {
        name: 'zoo-animal-server',
        version: '1.0.0',
    });
    
    // HTTP server mode
    const app = express();
    app.use(express.json());
    
    // Initialize Genkit MCP server once
    const mcpServerPromise = mcpWrapper.setup().then(() => mcpWrapper.server);
    
    app.post('/mcp', async (req, res) => {
        console.log('/mcp Received:', req.body);
        console.log('Using HTTP transport mode.');
    
        const server = await mcpServerPromise;
    
        const transport = new StreamableHTTPServerTransport({
            sessionIdGenerator: undefined,
        });
    
        if (!server) {
            console.error('MCP Server not initialized correctly.');
            res.sendStatus(500);
            return;
        }
    
        await server.connect(transport);
        await transport.handleRequest(req, res, req.body);
    
        res.on('close', () => {
            console.log('Request closed');
            transport.close();
        });
    });
    
    app.get('/mcp', async (req, res) => {
        console.log('Received GET MCP request');
        res.sendStatus(405);
    });
    
    app.delete('/mcp', async (req, res) => {
        console.log('Received DELETE MCP request');
        res.sendStatus(405);
    });
    
    // Start the server
    const PORT = process.env.PORT || 8080;
    app.listen(PORT, () => {
        console.log(`Zoo Animal MCP server listening on port ${PORT}`);
    });
    

您的代码已完成!现在,您可以将 MCP 服务器部署到 Cloud Run 了。

7. 部署到 Cloud Run

现在,直接从源代码将 MCP 服务器部署到 Cloud Run。

  1. 创建名为 mcp-server-sa 的服务账号:
    gcloud iam service-accounts create mcp-server-sa --display-name="MCP Server Service Account"
    
  2. 运行 gcloud 命令,将应用部署到 Cloud Run
    gcloud run deploy zoo-mcp-server \
        --service-account=mcp-server-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
        --no-allow-unauthenticated \
        --region=europe-west1 \
        --source=. \
        --labels=dev-tutorial=codelab-mcp
    
    使用 --no-allow-unauthenticated 标志可要求进行身份验证。这对于确保安全性至关重要。如果您不需要进行身份验证,则任何人都可以调用您的 MCP 服务器,并可能会对您的系统造成损害。
  3. 确认已创建新的 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 [europe-west1] will be created.
    
    Do you want to continue (Y/n)?
    
    输入 Y 并按 Enter,系统会为您的部署创建一个 Artifact Registry 代码库。这是存储 Cloud Run 服务的 MCP 服务器 Docker 容器所必需的。
  4. 几分钟后,您会看到类似以下内容的消息:
    Service [zoo-mcp-server] revision [zoo-mcp-server-12345-abc] has been deployed and is serving 100 percent of traffic.
    

您已部署 MCP 服务器。现在,您可以使用该功能了。

8. 将远程 MCP 服务器添加到 Gemini CLI

现在,您已成功部署远程 MCP 服务器,可以使用 Google Code Assist 或 Gemini CLI 等各种应用连接到该服务器。在本部分中,我们将使用 Gemini CLI 与新的远程 MCP 服务器建立连接。

  1. 向您的用户账号授予调用远程 MCP 服务器的权限
    gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
        --member=user:$(gcloud config get-value account) \
        --role='roles/run.invoker'
    
  2. 使用以下命令,将您的 Google Cloud 凭证和项目编号保存在环境变量中,以便在 Gemini 设置文件中使用:
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    export ID_TOKEN=$(gcloud auth print-identity-token)
    
  3. 打开 Gemini CLI 设置文件
    cloudshell edit ~/.gemini/settings.json
    
  4. 替换 Gemini CLI 设置文件以添加 Cloud Run MCP 服务器
    {
        "ide": {
            "hasSeenNudge": true
        },
        "mcpServers": {
            "zoo-remote": {
                "httpUrl": "https://zoo-mcp-server-$PROJECT_NUMBER.europe-west1.run.app/mcp",
                "headers": {
                    "Authorization": "Bearer $ID_TOKEN"
                }
            }
        },
        "security": {
            "auth": {
                "selectedType": "cloud-shell"
            }
        }
    }
    

  1. 在 Cloud Shell 中启动 Gemini CLI
    gemini
    
    您可能需要按 Enter 接受一些默认设置。Gemini CLI 初始视图
  2. 让 Gemini 列出其上下文中可用的 MCP 工具
    /mcp
    
  3. 向 Gemini 提问,让它帮忙寻找动物的位置
    Where can I find penguins?
    
    Gemini CLI 应该知道要使用 zoo-remote MCP 服务器,并询问您是否允许执行 MCP。
  4. 使用向下键,然后按 Enter 选择
    Yes, always allow all tools from server "zoo-remote"
    
    Gemini CLI 允许使用 zoo-remote 工具

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

Gemini CLI 显示 Zoo MCP 服务器结果

您已完成!您已成功将远程 MCP 服务器部署到 Cloud Run,并使用 Gemini CLI 对其进行了测试。

准备好结束会话时,请输入 /quit,然后按 Enter 退出 Gemini 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

  1. 输入 /quit,然后按 Enter 退出 Gemini CLI。
  2. 在终端中设置项目
    gcloud config set project [PROJECT_ID]
    
  3. 重新运行 Google Cloud 凭据命令以获取新的 ID_TOKEN,因为您的凭据可能已过期。
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    export ID_TOKEN=$(gcloud auth print-identity-token)
    

9. (可选)验证服务器日志中的工具调用

如需验证 Cloud Run MCP 服务器是否被调用,请检查服务日志。

gcloud run services logs read zoo-mcp-server --region europe-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 提示可以为经常运行的提示创建简写,从而加快工作流程。

Gemini CLI 会自动将 MCP 提示转换为自定义斜杠命令,以便您可以通过输入 /prompt_name(其中 prompt_name 是 MCP 提示的名称)来调用 MCP 提示。

创建 MCP 提示,以便您通过在 Gemini CLI 中输入 /find animal 快速找到动物园中的动物。

  1. 将以下代码添加到 index.js 文件中的 // Create Genkit MCP server wrapper 行上方:
    ai.definePrompt(
        {
            name: 'find',
            description: 'Find which exhibit and trail a specific animal is located.',
            inputSchema: z.object({ animal: z.string() }),
        },
        async ({ animal }) => {
            console.log(`>>> 💬 Prompt: 'find' called'`);
            return {
                messages: [
                    {
                        role: 'user',
                        content: [
                            { text: `Please find the exhibit and trail information for ${animal} in the zoo. Respond with '[animal] can be found in the [exhibit] on the [trail].' Example: Penguins can be found in The Arctic Exhibit on the Polar Path.` }
                        ]
                    }
                ]
            };
        }
    );
    
  2. 将应用重新部署到 Cloud Run
    gcloud run deploy zoo-mcp-server \
        --service-account=mcp-server-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
        --no-allow-unauthenticated \
        --region=europe-west1 \
        --source=. \
        --labels=dev-tutorial=codelab-mcp
    
  3. 刷新远程 MCP 服务器的 ID_TOKEN
    export ID_TOKEN=$(gcloud auth print-identity-token)
    
  4. 部署应用的新版本后,启动 Gemini CLI。
    gemini
    
  5. 在提示中使用您创建的新自定义命令:
    /find --animal="lions"
    

您应该会看到 Gemini CLI 调用 get_animals_by_species 工具,并按照 MCP 提示的指示设置回答格式!

╭───────────────────────────╮
│  > /find --animal="lion"  │
╰───────────────────────────╯

 ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✔  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 可更快获得回答

借助 Gemini CLI,您可以选择要使用的模型。

  • Gemini 2.5 Pro 是 Google 最先进的思考模型,能够推理代码、数学和 STEM 领域中的复杂问题,还能使用长上下文分析大型数据集、代码库和文档。
  • Gemini 2.5 Flash 在性价比方面是 Google 的最佳模型,可提供全面的功能。2.5 Flash 最适合大规模处理、低延迟、高数据量且需要思考的任务,以及智能体应用场景。
  • Gemini 2.5 Flash Lite 是 Google 速度最快的 Flash 模型,经过优化,可实现高成本效益和高吞吐量。

由于与寻找动物园动物相关的请求不需要思考或推理,因此可以尝试使用速度更快的模型来加快处理速度。

创建 MCP 提示,以便您通过在 Gemini CLI 中输入 /find animal 快速找到动物园中的动物。

  1. 部署应用的新版本后,启动 Gemini CLI。
    gemini --model=gemini-2.5-flash-lite
    
  2. 在提示中使用您创建的新自定义命令:
    /find --animal="lions"
    

您应该仍然会看到 Gemini CLI 调用 get_animals_by_species 工具,并按照 MCP 提示的指示设置回答格式,但回答应该会更快显示!

╭───────────────────────────╮
│  > /find --animal="lion"  │
╰───────────────────────────╯

 ╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✔  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.

可用于自我测试的拓展目标

如需增加难度,请尝试按照相同的步骤创建提示,让模型返回动物园中特定动物物种的趣闻。

或者,为了进一步测试所学知识,您可以想出一个自己会经常使用的工具,并部署第二个远程 MCP 服务器。然后将其添加到 Gemini CLI 设置中,看看是否有效。

调试

如果您看到类似以下内容的错误:

✕ Unknown command: /find --animal="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)

12. 总结

恭喜!您已成功部署并连接到安全的远程 MCP 服务器。

继续执行下一个实验

本实验是三部分系列实验中的第一个实验。在第二个实验中,您将使用通过 ADK 代理创建的 MCP 服务器。

在 Cloud Run 上使用 MCP 服务器和 ADK 代理

(可选)清理

如果您不打算继续学习下一个实验,并且想要清理已创建的内容,可以删除您的云项目,以免产生额外费用。

虽然 Cloud Run 不会对未在使用中的服务计费,但您可能仍然需要支付将容器映像存储在 Artifact Registry 中而产生的相关费用。删除 Cloud 项目后,系统即会停止对该项目中使用的所有资源计费。

如果您愿意,可以删除项目:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

您可能还需要从 Cloud Shell 磁盘中删除不必要的资源。您可以:

  1. 删除 Codelab 项目目录:
    rm -rf ~/mcp-on-cloudrun
    
  2. 警告!接下来执行的操作无法撤消!如果您想删除 Cloud Shell 中的所有内容以释放空间,可以删除整个主目录。请务必将要保留的所有内容保存到其他位置。
    sudo rm -rf $HOME