Cloud Run にリモート MCP サーバーを構築してデプロイする

このチュートリアルでは、ストリーミング可能な HTTP トランスポートを使用して、Cloud Run にリモート Model Context Protocol(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 管理者roles/run.admin)とサービス アカウント ユーザーroles/iam.serviceAccountUser)のロールが付与されていることを確認します。
  8. アカウントに Cloud Run 起動元(roles/run.invokerロールを付与します。このロールにより、リモート MCP サーバーは Cloud Run サービスにアクセスできます。
  9. ロールの付与方法を確認する

    コンソール

    1. Google Cloud コンソールで、[IAM] ページに移動します。

      IAM に移動
    2. プロジェクトを選択します。
    3. [ アクセスを許可] をクリックします。
    4. [新しいプリンシパル] フィールドに、ユーザー ID を入力します。これは通常、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. Python パッケージとプロジェクト マネージャーである Uv をインストールします。
  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. 次の新しいファイルを追加で作成します。

      • MCP サーバーのソースコードの server.py
      • 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 サーバーを作成する

    MCP で LLM の使用を改善するための重要なコンテキストを提供するには、FastMCP を使用して数学 MCP サーバーを設定します。FastMCP は、Python で MCP サーバーとクライアントを迅速に構築するためのツールです。

    加算や減算などの数学演算用の MCP サーバーを作成する手順は次のとおりです。

    1. 次のコマンドを実行して、pyproject.toml ファイルに FastMCP を依存関係として追加します。

      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. uv ツールを使用して server.py ファイルを実行するには、Dockerfile に次のコードを追加します。

      # 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 に push します。

      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 起動元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 の URL にアクセスし、リモート 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
      

    次のステップ