Build and deploy a remote MCP server on Cloud Run

This tutorial shows you how to build and deploy a remote Model Context Protocol (MCP)server on Cloud Run using thestreamable HTTP transport.With streamable HTTP transport, the MCP server operates as an independent process that canhandle multiple client connections.

Objectives

In this tutorial, you will:

  1. Prepare your Python project with theuv package manager.
  2. Create an MCP server for math operations.
  3. Deploy to Cloud Run.
  4. Authenticate MCP client.
  5. Test the remote MCP server.

Costs

In this document, you use the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use thepricing calculator.

New Google Cloud users might be eligible for afree trial.

Before you begin

  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.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.create permission.Learn how to grant roles.
    Note: If you don't plan to keep the resources that you create in this procedure, create a project instead of selecting an existing project. After you finish these steps, you can delete the project, removing all resources associated with the 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.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.create permission.Learn how to grant roles.
    Note: If you don't plan to keep the resources that you create in this procedure, create a project instead of selecting an existing project. After you finish these steps, you can delete the project, removing all resources associated with the 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.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enable permission.Learn how to grant roles.

    Enable the APIs

  7. Set up your Cloud Run development environmentin your Google Cloud project.
  8. Make sure you have the appropriatepermissions to deploy services, and theCloud Run Admin (roles/run.admin) andService Account User (roles/iam.serviceAccountUser) roles granted to your account.
  9. Grant theCloud RunInvoker (roles/run.invoker) role to your account. This role allows the remote MCP server to access the Cloud Run service.
  10. Learn how to grant the roles

    Console

    1. In the Google Cloud console, go to theIAM page.

      Go to IAM
    2. Select the project.
    3. ClickGrant access.
    4. In theNew principals field, enter your user identifier. This is typically the email address used to deploy the Cloud Run service.

    5. In theSelect a role list, select a role.
    6. To grant additional roles, clickAdd another role and add each additional role.
    7. ClickSave.

    gcloud

    To grant the required IAM roles to your account on your project:

    gcloudprojectsadd-iam-policy-bindingPROJECT_ID\--member=PRINCIPAL\--role=ROLE

    Replace:

    • PROJECT_NUMBER: your Google Cloud project number.
    • PROJECT_ID: your Google Cloud project ID.
    • PRINCIPAL: the email address of the account to which you are granting the role.
    • ROLE: the role you are adding to the deployer account.
  11. If you are under a domain restriction organization policyrestricting unauthenticated invocations for your project, you will need to access your deployed service as described underTesting private services.

  12. InstallUv, a Python package and project manager.

Prepare your Python project

The following steps describe how toset up your Python project with theuv package manager.

  1. Create a folder namedmcp-on-cloudrun to store the source code fordeployment:

      mkdir mcp-on-cloudrun  cd mcp-on-cloudrun
  2. Create a Python project with theuv tool to generate apyproject.toml file:

      uv init --name "mcp-on-cloudrun" --description "Example of deploying an MCP server on Cloud Run" --bare --python 3.10

    Theuv init command creates the followingpyproject.toml file:

    [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. Create the following additional new files:

    • server.py for the MCP server source code
    • test_server.py to test the remote server
    • A Dockerfile for deploying to Cloud Run
    touch server.py test_server.py Dockerfile

    Your project directory should contain the following structure:

    ├── mcp-on-cloudrun│   ├── pyproject.toml│   ├── server.py│   ├── test_server.py│   └── Dockerfile

Create an MCP server for math operations

To provide valuable context for improving the use of LLMs with MCP, set up amath MCP server withFastMCP.FastMCP provides a quick way to build MCP servers and clients with Python.

Follow these steps to create an MCP server for math operations such asaddition and subtraction.

  1. Run the following command to add FastMCP as a dependency in thepyproject.toml file:

    uv add fastmcp==2.13.1 --no-sync
  2. Add the following math MCP server source code in theserver.py file:

    importasyncioimportloggingimportosfromfastmcpimportFastMCPlogger=logging.getLogger(__name__)logging.basicConfig(format="[%(levelname)s]:%(message)s",level=logging.INFO)mcp=FastMCP("MCP Server on Cloud Run")@mcp.tool()defadd(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}'")returna+b@mcp.tool()defsubtract(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}'")returna-bif__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. Include the following code in the Dockerfile to use theuv tool for running theserver.pyfile:

    # Use the official Python imageFROMpython:3.13-slim# Install uvCOPY--from=ghcr.io/astral-sh/uv:latest/uv/uvx/bin/# Install the project into /appCOPY./appWORKDIR/app# Allow statements and log messages to immediately appear in the logsENVPYTHONUNBUFFERED=1# Install dependenciesRUNuvsyncEXPOSE$PORT# Run the FastMCP serverCMD["uv","run","server.py"]

Deploy to Cloud Run

You can deploy the MCP server as acontainer image or assource code:

Container image

To deploy an MCP server packaged as a container image, follow these instructions.

  1. Create an Artifact Registry repository to store the container image:

    gcloud artifacts repositories create remote-mcp-servers \--repository-format=docker \--location=us-central1 \--description="Repository for remote MCP servers" \--project=PROJECT_ID
  2. Build the container image and push it to Artifact Registry with Cloud Build:

    gcloud builds submit --region=us-central1 --tag us-central1-docker.pkg.dev/PROJECT_ID/remote-mcp-servers/mcp-server:latest
  3. Deploy the MCP server container image to 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

Source

You can deploy remote MCP servers to Cloud Run from their sources.

Deploy from source by running the following command:

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

Authenticate MCP client

If you deployed your service with the--no-allow-unauthenticated flag, any MCP clientthat connects to your remote MCP server must authenticate.

  1. Grant theCloud Run Invoker (roles/run.invoker) role to the service account. ThisIdentity and Access Management policy binding makes sure that a strong security mechanism is used to authenticate your local MCP client.

  2. Run theCloud Run proxyto create an authenticated tunnel to the remote MCP server on your localmachine:

    gcloud run services proxy mcp-server --region=us-central1

    If the Cloud Run proxy is not yet installed, this command promptsyou to download the proxy. Follow the prompts to download and install the proxy.

Cloud Run authenticates all traffic tohttp://127.0.0.1:8080 and forwardsrequests to the remote MCP server.

Test the remote MCP server

You test and connect to the remote MCP server by using the FastMCP client and accessingthe URLhttp://127.0.0.1:8080/mcp.

To test and invoke the add and subtract mechanism, follow these steps:

  1. Before running the test server,run the Cloud Run proxy.

  2. Create a test file calledtest_server.py and add the following code:

    importasynciofromfastmcpimportClientasyncdeftest_server():# Test the MCP server using streamable-http transport.# Use "/sse" endpoint if using sse transport.asyncwithClient("http://localhost:8080/mcp")asclient:# List available toolstools=awaitclient.list_tools()fortoolintools:print(f">>> 🛠️  Tool found:{tool.name}")# Call add toolprint(">>> 🪛  Calling add tool for 1 + 2")result=awaitclient.call_tool("add",{"a":1,"b":2})print(f"<<< ✅ Result:{result[0].text}")# Call subtract toolprint(">>> 🪛  Calling subtract tool for 10 - 3")result=awaitclient.call_tool("subtract",{"a":10,"b":3})print(f"<<< ✅ Result:{result[0].text}")if__name__=="__main__":asyncio.run(test_server())
  3. In a new terminal, run the test server:

    uv run test_server.py

    You should see the following output:

     🛠️ Tool found: add 🛠️ Tool found: subtract 🪛 Calling add tool for 1 + 2 ✅ Result: 3 🪛 Calling subtract tool for 10 - 3 ✅ Result: 7
Success: You successfully deployed a remote MCP server to Cloud Run andtested it using the FastMCP client.

Clean up

To avoid additional charges to your Google Cloud account, delete all the resourcesyou deployed with this tutorial.

Delete the project

If you created a new project for this tutorial, delete the project.If you used an existing project and need to keep it without the changes you addedin this tutorial,delete resources that you created for the tutorial.

The easiest way to eliminate billing is to delete the project that you created for the tutorial.

To delete the project:

    Caution: Deleting a project has the following effects:
    • Everything in the project is deleted. If you used an existing project for the tasks in this document, when you delete it, you also delete any other work you've done in the project.
    • Custom project IDs are lost. When you created this project, you might have created a custom project ID that you want to use in the future. To preserve the URLs that use the project ID, such as anappspot.com URL, delete selected resources inside the project instead of deleting the whole project.

    If you plan to explore multiple architectures, tutorials, or quickstarts, reusing projects can help you avoid exceeding project quota limits.

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

    Go to Manage resources

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

Delete tutorial resources

  1. Delete the Cloud Run service you deployed in this tutorial.Cloud Run services don't incur costs until they receive requests.

    To delete your Cloud Run service, run the following command:

    gcloudrunservicesdeleteSERVICE-NAME

    ReplaceSERVICE-NAME with the name of your service.

    You can also delete Cloud Run services from theGoogle Cloud console.

  2. Remove thegcloud default region configuration you added during tutorialsetup:

    gcloudconfigunsetrun/region
  3. Remove the project configuration:

     gcloud config unset project

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-17 UTC.