Cloud Run で安全な Genkit MCP サーバーをデプロイする方法

1. はじめに

概要

このラボでは、Model Context Protocol(MCP)サーバーを構築してデプロイします。MCP サーバーは、LLM に外部ツールやサービスへのアクセス権を付与する際に役立ちます。このサービスは、複数のクライアントからアクセスできる安全な本番環境対応のサービスとして Cloud Run に構成します。次に、Gemini CLI からリモート MCP サーバーに接続します。

演習内容

ここでは、Genkit を使用して、get_animals_by_speciesget_animal_details という 2 つのツールを持つ zoo MCP サーバーを作成します。Genkit は、Node.js で MCP のサーバーとクライアントを迅速に構築するためのツールです。

Zoo MCP サーバーのグラフィック

学習内容

  • MCP サーバーを Cloud Run にデプロイします。
  • すべてのリクエストに認証を要求してサーバーのエンドポイントを保護し、承認されたクライアントとエージェントのみが通信できるようにします。
  • Gemini CLI からセキュアな MCP サーバー エンドポイントに接続する

2. プロジェクトの設定

  1. Google アカウントをまだお持ちでない場合は、Google アカウントを作成する必要があります。
    • 仕事用または学校用アカウントではなく、個人アカウントを使用します。職場用アカウントと学校用アカウントには、このラボに必要な API を有効にできない制限が設定されている場合があります。
  2. Google Cloud コンソールにログインします。
  3. Cloud コンソールで課金を有効にします
    • このラボを完了するのにかかる Cloud リソースの費用は 1 米ドル未満です。
    • このラボの最後の手順に沿ってリソースを削除すると、それ以上の料金は発生しません。
    • 新規ユーザーは、300 米ドル分の無料トライアルをご利用いただけます。
  4. 新しいプロジェクトを作成するか、既存のプロジェクトを再利用します。
    • プロジェクトの割り当てに関するエラーが表示された場合は、既存のプロジェクトを再利用するか、既存のプロジェクトを削除して新しいプロジェクトを作成します。

3. Cloud Shell エディタを開く

  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. zoo MCP サーバーを作成する

LLM の使用を改善するための重要なコンテキストを MCP によって提供するには、Genkit(Model Context Protocol を使用するための標準フレームワーク)を使用して動物園 MCP サーバーを設定します。Genkit は、Node.js で MCP のサーバーとクライアントを迅速に構築するためのツールです。この MCP サーバーは、架空の動物園に登場する動物に関するデータを提供します。わかりやすくするため、データをメモリに保存します。本番環境の MCP サーバーでは、データベースや API などのソースからデータを提供することをおすすめします。

  1. 次のコマンドを実行して、package.json ファイルに Genkit を依存関係として追加します。
    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 へのデプロイ

次に、ソースコードから直接 Cloud Run に MCP サーバーをデプロイします。

  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. Gemini CLI にリモート MCP サーバーを追加する

リモート 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. Gemini 設定ファイルで使用するために、Google Cloud 認証情報とプロジェクト番号を、次のように環境変数に保存します。
    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 リモートツールを許可する

出力には正しい回答と、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 を取得します。古い 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 と入力して MCP プロンプトを呼び出すことができます。ここで、prompt_name は 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 は、価格とパフォーマンスの面で最適なモデルであり、バランスの取れた機能を提供します。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.

ストレッチ ゴールで自分を試す

さらに、同じ手順で、動物園にいる特定の動物種に関する豆知識を返すプロンプトを作成できるかどうか試してみましょう。

さらに、学習した内容をテストするために、頻繁に使用するツールのアイデアを考案し、2 番目のリモート 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 サーバーをデプロイして接続しました。

次のラボに進む

このラボは、3 部構成のシリーズの最初のラボです。2 つ目のラボでは、ADK エージェントを使用して作成した MCP サーバーを使用します。

ADK エージェントで Cloud Run の MCP サーバーを使用する

(省略可)クリーンアップ

次のラボに進まず、作成したものをクリーンアップする場合は、Cloud プロジェクトを削除して、追加の課金が発生しないようにします。

サービスが使用されていない場合、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