Cloud Run에 원격 MCP 서버 빌드 및 배포


이 튜토리얼에서는 스트리밍 가능한 HTTP 전송을 사용하여 Cloud Run에서 원격 모델 컨텍스트 프로토콜 (MCP) 서버를 빌드하고 배포하는 방법을 보여줍니다. 스트리밍 가능한 HTTP 전송을 사용하면 MCP 서버가 여러 클라이언트 연결을 처리할 수 있는 독립 프로세스로 작동합니다.

목표

이 튜토리얼에서는 다음 단계를 진행합니다.

  1. uv 패키지 관리자로 Python 프로젝트를 준비합니다.
  2. 수학 연산을 위한 MCP 서버를 만듭니다.
  3. Cloud Run에 배포
  4. MCP 클라이언트 인증
  5. 원격 MCP 서버 테스트

비용

이 문서에서는 비용이 청구될 수 있는 Google Cloud구성요소( )를 사용합니다.

프로젝트 사용량을 기준으로 예상 비용을 산출하려면 가격 계산기를 사용하세요.

Google Cloud 신규 사용자는 무료 체험판을 사용할 수 있습니다.

시작하기 전에

  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. Verify 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. Verify that billing is enabled for your Google Cloud project.

  6. Enable the Artifact Registry, Cloud Run Admin API, and Cloud Build APIs.

    Enable the APIs

  7. Google Cloud 프로젝트에서 Cloud Run 개발 환경을 설정합니다.
  8. 서비스를 배포할 적절한 권한이 있고 Cloud Run 관리자 (roles/run.admin) 및 서비스 계정 사용자 (roles/iam.serviceAccountUser) 역할이 계정에 부여되어 있는지 확인합니다.
  9. 계정에 Cloud Run 호출자 (roles/run.invoker) 역할을 부여합니다. 이 역할을 통해 원격 MCP 서버가 Cloud Run 서비스에 액세스할 수 있습니다.
  10. 역할 부여 방법 알아보기

    콘솔

    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: 배포자 계정에 추가할 역할입니다.
  11. 프로젝트에서 인증되지 않은 호출을 제한하는 도메인 제한 조직 정책이 적용되는 경우 비공개 서비스 테스트의 설명대로 배포된 서비스에 액세스해야 합니다.

  12. Python 패키지 및 프로젝트 관리자인 Uv를 설치합니다.

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. 다음 수학 MCP 서버 소스 코드를 server.py 파일에 추가합니다.

    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. server.py 파일을 실행하는 데 uv 도구를 사용하려면 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에 푸시합니다.

    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
    

소스

소스에서 Cloud Run으로 원격 MCP 서버를 배포할 수 있습니다.

다음 명령어를 실행하여 소스에서 배포합니다.

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

MCP 클라이언트 인증

--no-allow-unauthenticated 플래그를 사용하여 서비스를 배포한 경우 원격 MCP 서버에 연결하는 모든 MCP 클라이언트는 인증을 받아야 합니다.

  1. 서비스 계정에 Cloud Run 호출자 (roles/run.invoker) 역할을 부여합니다. 이 ID 및 액세스 관리 정책 바인딩은 강력한 보안 메커니즘이 로컬 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 클라이언트를 사용하고 URL 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
    

삭제

Google Cloud 계정에 추가 비용이 청구되지 않도록 하려면 이 튜토리얼에서 배포한 모든 리소스를 삭제합니다.

프로젝트 삭제

이 튜토리얼용으로 새 프로젝트를 만든 경우 이 프로젝트를 삭제합니다. 기존 프로젝트를 사용한 경우 이 튜토리얼에 추가된 변경사항은 제외하고 보존하려면 튜토리얼용으로 만든 리소스를 삭제합니다.

비용이 청구되지 않도록 하는 가장 쉬운 방법은 튜토리얼에서 만든 프로젝트를 삭제하는 것입니다.

프로젝트를 삭제하는 방법은 다음과 같습니다.

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

튜토리얼 리소스 삭제

  1. 이 튜토리얼에서 배포한 Cloud Run 서비스를 삭제합니다. Cloud Run 서비스는 요청을 수신할 때까지 비용이 발생하지 않습니다.

    Cloud Run 서비스를 삭제하려면 다음 명령어를 실행합니다.

    gcloud run services delete SERVICE-NAME

    SERVICE-NAME를 서비스 이름으로 바꿉니다.

    Google Cloud 콘솔에서 Cloud Run 서비스를 삭제할 수도 있습니다.

  2. 튜토리얼 설정 중에 추가한 gcloud 기본 리전 구성을 삭제합니다.

     gcloud config unset run/region
    
  3. 프로젝트 구성을 삭제합니다.

     gcloud config unset project