This is Part 2 of the AlloyDB Agentic RAG application tutorial, please start with Part 1.
7. Deploy the MCP Toolbox to Cloud Run
Now we can deploy the MCP Toolbox to Cloud Run. There are different ways how the MCP toolbox can be deployed. The simplest way is to run it from the command line but if we want to have it as a scalable and reliable service then Cloud Run is a better solution.
Prepare Client ID
To use booking functionality of the application we need to prepare OAuth 2.0 Client ID using Cloud Console. Without it we cannot sign into the application with our Google credentials to make a booking and record the booking to the database.
In the Cloud Console go to the APIs and Services and click on “OAuth consent screen”. Here is a link to the page. It will open the Oauth Overview page where we click Get Started.
On the next page we provide the application name, user support email and click Next.
On the next screen we choose Internal for our application and click Next again.
Then again we provide contact email and click Next
Then we agree with Google API services policies and push the Create button.
It will lead us to the page where we can create an OAuth client.
On the screen we choose “Web Application” from the dropdown menu, put “Cymbal Air” as application and push the Add URI button.
The URIs represent trusted sources for the application and they depend on where you are trying to reach the application from. We put “http://localhost:8081” as authorized URI and “http://localhost:8081/login/google” as redirect URI. Those values would work if you put in your browser “http://localhost:8081” as a URI for connection. For example, when you connect through an SSH tunnel from your computer for example. I will show you how to do it later.
After pushing the “Create” button you get a popup window with your clients credentials. And the credentials will be recorded in the system. You always can copy the client ID to be used when you start your application.
Later you will see where you provide that client ID.
Create Service Account
We need a dedicated service account for our Cloud Run service with all required privileges. For our service we need access to AlloyDB and Cloud Secret Manager. As for the name for the service account we are going to use toolbox-identity.
Open another Cloud Shell tab using the sign “+” at the top.
In the new cloud shell tab execute:
export PROJECT_ID=$(gcloud config get-value project)
gcloud iam service-accounts create toolbox-identity
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/alloydb.client"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/serviceusage.serviceUsageConsumer"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"
Please pay attention if you have any errors. The command is supposed to create a service account for cloud run service and grant privileges to work with secret manager, database and Vertex AI.
Close the tab by either pressing ctrl+d or executing command “exit” in the tab:
exit
Prepare MCP Toolbox Configuration
Prepare configuration file for the MCP Toolbox. You can read about all configuration options in the documentation but here we are going to use the sample tools.yaml file and replace some values such as cluster and instance name, AlloyDB password and the project id by our actual values.
Export AlloyDB Password:
export PGPASSWORD=
Export client ID we prepared in the previous step:
export CLIENT_ID=
Prepare configuration file.
PROJECT_ID=$(gcloud config get-value project)
ADBCLUSTER=alloydb-aip-01
sed -e "s/project: retrieval-app-testing/project: $(gcloud config get-value project)/g" \
-e "s/cluster: my-alloydb-cluster/cluster: $ADBCLUSTER/g" \
-e "s/instance: my-alloydb-instance/instance: $ADBCLUSTER-pr/g" \
-e "s/password: postgres/password: $PGPASSWORD\\n ipType: private/g" \
-e "s/^ *clientId: .*/ clientId: $CLIENT_ID/g" \
cymbal-air-toolbox-demo/tools.yaml >~/tools.yaml
If you look into the file section defining the target data source you will see that we also added a line to use private IP for connection.
sources:
my-pg-instance:
kind: alloydb-postgres
project: gleb-test-short-003-471020
region: us-central1
cluster: alloydb-aip-01
instance: alloydb-aip-01-pr
database: assistantdemo
user: postgres
password: L23F...
ipType: private
authServices:
my_google_service:
kind: google
clientId: 96828*******-***********.apps.googleusercontent.com
Create a secret using the tools.yaml configuration as a source.
In the VM ssh console execute:
gcloud secrets create tools --data-file=tools.yaml
Expected console output:
student@instance-1:~$ gcloud secrets create tools --data-file=tools.yaml
Created version [1] of the secret [tools].
Deploy the MCP Toolbox as a Cloud Run Service
Now everything is ready to deploy the MCP Toolbox as a service to Cloud Run. For local testing you can run “./toolbox –tools-file=./tools.yaml” but if we want our application to run in the cloud the deployment in Cloud Run makes much more sense.
In the VM SSH session execute:
export IMAGE=us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest
gcloud run deploy toolbox \
--image $IMAGE \
--service-account toolbox-identity \
--region us-central1 \
--set-secrets "/app/tools.yaml=tools:latest" \
--args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
--network default \
--subnet default \
--no-allow-unauthenticated
Expected console output:
student@instance-1:~$ export IMAGE=us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:latest
gcloud run deploy toolbox \
--image $IMAGE \
--service-account toolbox-identity \
--region us-central1 \
--set-secrets "/app/tools.yaml=tools:latest" \
--args="--tools-file=/app/tools.yaml","--address=0.0.0.0","--port=8080" \
--network default \
--subnet default \
--no-allow-unauthenticated
Deploying container to Cloud Run service [toolbox] in project [gleb-test-short-002-470613] region [us-central1]
✓ Deploying new service... Done.
✓ Creating Revision...
✓ Routing traffic...
Done.
Service [toolbox] revision [toolbox-00001-l9c] has been deployed and is serving 100 percent of traffic.
Service URL: https://toolbox-868691532292.us-central1.run.app
student@instance-1:~$
Verify The Service
Now we can check if the service is up and we can access the endpoint. We use gcloud utility to get the retrieval service endpoint and the authentication token. Alternatively you can check the service URI in the cloud console.
You can copy the value and replace in the curl command the “$(gcloud run services list –filter=”(toolbox)” –format=”value(URL)” part .
Here is how to get the URL dynamically from the command line:
curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" $(gcloud run services list --filter="(toolbox)" --format="value(URL)")
Expected console output:
student@instance-1:~$ curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" $(gcloud run services list --filter="(toolbox)" --format="value(URL)")
🧰 Hello, World! 🧰student@instance-1:~$
If we see the “Hello World” message it means our service is up and serving the requests.
8. Deploy Sample Application
Now when we have the retrieval service up and running we can deploy a sample application. The application represents an online airport assistant which can give you information about flights, airports and even book a flight based on the flights and airport data from our database.
The application can be deployed locally, on a VM in the cloud or any other service like Cloud Run or Kubernetes. Here we are going to show how to deploy it on the VM first.
Prepare the environment
We continue to work on our VM using the same SSH session. To run our application we need some Python modules and we have already added them when we initiated our database earlier. Let’s switch to our Python virtual environment and change our location to the app directory.
In the VM SSH session execute:
source ~/.venv/bin/activate
cd cymbal-air-toolbox-demo
Expected output (redacted):
student@instance-1:~$ source ~/.venv/bin/activate
cd cymbal-air-toolbox-demo
(.venv) student@instance-1:~/cymbal-air-toolbox-demo$
Run Assistant Application
Before starting the application we need to set up some environment variables. The basic functionality of the application such as query flights and airport amenities requires only TOOLBOX_URL which points application to the retrieval service. We can get it using the gcloud command .
In the VM SSH session execute:
export TOOLBOX_URL=$(gcloud run services list --filter="(toolbox)" --format="value(URL)")
Expected output (redacted):
student@instance-1:~/cymbal-air-toolbox-demo$ export BASE_URL=$(gcloud run services list --filter="(toolbox)" --format="value(URL)")
To use more advanced capabilities of the application like booking and changing flights we need to sign-in to the application using our Google account and for that purpose we need to provide CLIENT_ID environment variable using the OAuth client ID from the Prepare Client ID chapter:
export CLIENT_ID=215....apps.googleusercontent.com
Expected output (redacted):
student@instance-1:~/cymbal-air-toolbox-demo$ export CLIENT_ID=215....apps.googleusercontent.com
And now we can run our application:
python run_app.py
Expected output:
student@instance-1:~/cymbal-air-toolbox-demo/llm_demo$ python run_app.py
INFO: Started server process [2900]
INFO: Waiting for application startup.
Loading application...
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8081 (Press CTRL+C to quit)
Connect to the Application
You have several ways to connect to the application running on the VM. For example you can open port 8081 on the VM using firewall rules in the VPC or create a load balancer with public IP. Here we are going to use a SSH tunnel to the VM translating the local port 8080 to the VM port 8081.
Connecting From Local Machine
When we want to connect from a local machine we need to run a SSH tunnel. It can be done using gcloud compute ssh:
gcloud compute ssh instance-1 --zone=us-central1-a -- -L 8081:localhost:8081
Expected output:
student-macbookpro:~ student$ gcloud compute ssh instance-1 --zone=us-central1-a -- -L 8080:localhost:8081
Warning: Permanently added 'compute.7064281075337367021' (ED25519) to the list of known hosts.
Linux instance-1.us-central1-c.c.gleb-test-001.internal 6.1.0-21-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.90-1 (2024-05-03) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
student@instance-1:~$
Now we can open the browser and use http://localhost:8081 to connect to our application. We should see the application screen.
Connecting From Cloud Shell
Alternatively we can use Google Cloud Shell to connect. Open another Cloud Shell tab using the sign “+” at the top.
In the new tab get the origin and redirect URI for your web client executing the gcloud command:
echo "origin:"; echo "https://8080-$WEB_HOST"; echo "redirect:"; echo "https://8080-$WEB_HOST/login/google"
Here is the expected output:
student@cloudshell:~ echo "origin:"; echo "https://8080-$WEB_HOST"; echo "redirect:"; echo "https://8080-$WEB_HOST/login/google"
origin:
https://8080-cs-35704030349-default.cs-us-east1-rtep.cloudshell.dev
redirect:
https://8080-cs-35704030349-default.cs-us-east1-rtep.cloudshell.dev/login/google
And use the origin and the redirect of URIs as the “Authorized JavaScript origins” and “Authorized redirect URIs” for our credentials created in the “Prepare Client ID” chapter replacing or adding to the originally provided http://localhost:8080 values.
Click on “Cymbal Air” on the OAuth 2.0 client IDs page.
Put the origin and redirect URIs for the Cloud Shell and push the Save button.
In the new cloud shell tab start the tunnel to your VM by executing the gcloud command:
gcloud compute ssh instance-1 --zone=us-central1-a -- -L 8080:localhost:8081
If it will show an error “Cannot assign requested address” – please ignore it.
Here is the expected output:
student@cloudshell:~ gcloud compute ssh instance-1 --zone=us-central1-a -- -L 8080:localhost:8081
bind [::1]:8081: Cannot assign requested address
inux instance-1.us-central1-a.c.gleb-codelive-01.internal 6.1.0-21-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.90-1 (2024-05-03) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat May 25 19:15:46 2024 from 35.243.235.73
student@instance-1:~$
It opens port 8080 on your cloud shell which can be used for the “Web preview”.
Click on the “Web preview” button on the right top of your Cloud Shell and from the drop down menu choose “Preview on port 8080”
It opens a new tab in your web browser with the application interface. You should be able to see the “Cymbal Air Customer Service Assistant” page.
Sign into the Application
When everything is set up and your application is open we can use the “Sign in” button at the top right of our application screen to provide our credentials. That is optional and required only if you want to try booking functionality of the application.
It will open a pop-up window where we can choose our credentials.
After signing in the application is ready and you can start to post your requests into the field at the bottom of the window.
This demo showcases the Cymbal Air customer service assistant. Cymbal Air is a fictional passenger airline. The assistant is an AI chatbot that helps travelers to manage flights and look up information about Cymbal Air’s hub at San Francisco International Airport (SFO).
Without signing in (without CLIENT_ID) it can help answer users questions like:
When is the next flight to Denver?
Are there any luxury shops around gate C28?
Where can I get coffee near gate A6?
Where can I buy a gift?
Please find a flight from SFO to Denver departing today
When you are signed in to the application you can try other capabilities like booking flights or check if the seat assigned to you is a window or aisle seat.
The application uses the latest Google foundation models to generate responses and augment it by information about flights and amenities from the operational AlloyDB database. You can read more about this demo application on the Github page of the project.
9. Clean up environment
Now when all tasks are completed we can clean up our environment
Delete Cloud Run Service
In Cloud Shell execute:
gcloud run services delete toolbox --region us-central1
Expected console output:
student@cloudshell:~ (gleb-test-short-004)$ gcloud run services delete retrieval-service --region us-central1
Service [retrieval-service] will be deleted.
Do you want to continue (Y/n)? Y
Deleting [retrieval-service]...done.
Deleted service [retrieval-service].
Delete the Service Account for cloud run service
In Cloud Shell execute:
PROJECT_ID=$(gcloud config get-value project)
gcloud iam service-accounts delete toolbox-identity@$PROJECT_ID.iam.gserviceaccount.com --quiet
Expected console output:
student@cloudshell:~ (gleb-test-short-004)$ PROJECT_ID=$(gcloud config get-value project)
Your active configuration is: [cloudshell-222]
student@cloudshell:~ (gleb-test-short-004)$ gcloud iam service-accounts delete retrieval-identity@$PROJECT_ID.iam.gserviceaccount.com --quiet
deleted service account [retrieval-identity@gleb-test-short-004.iam.gserviceaccount.com]
student@cloudshell:~ (gleb-test-short-004)$
Destroy the AlloyDB instances and cluster when you are done with the lab.
Delete AlloyDB cluster and all instances
If you’ve used the trial version of AlloyDB. Do not delete the trial cluster if you have plans to test other labs and resources using the trial cluster. You will not be able to create another trial cluster in the same project.
The cluster is destroyed with option force which also deletes all the instances belonging to the cluster.
In the cloud shell define the project and environment variables if you’ve been disconnected and all the previous settings are lost:
gcloud config set project
export REGION=us-central1
export ADBCLUSTER=alloydb-aip-01
export PROJECT_ID=$(gcloud config get-value project)
Delete the cluster:
gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force
📝 Note: The command takes 3-5 minutes to execute
Expected console output:
student@cloudshell:~ (test-project-001-402417)$ gcloud alloydb clusters delete $ADBCLUSTER --region=$REGION --force
All of the cluster data will be lost when the cluster is deleted.
Do you want to continue (Y/n)? Y
Operation ID: operation-1697820178429-6082890a0b570-4a72f7e4-4c5df36f
Deleting cluster...done.
Delete AlloyDB Backups
Delete all AlloyDB backups for the cluster:
📝 Note: The command will destroy all data backups for the cluster with name specified in environment variable
for i in $(gcloud alloydb backups list --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" --format="value(name)" --sort-by=~createTime) ; do gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done
Expected console output:
student@cloudshell:~ (test-project-001-402417)$ for i in $(gcloud alloydb backups list --filter="CLUSTER_NAME: projects/$PROJECT_ID/locations/$REGION/clusters/$ADBCLUSTER" --format="value(name)" --sort-by=~createTime) ; do gcloud alloydb backups delete $(basename $i) --region $REGION --quiet; done
Operation ID: operation-1697826266108-60829fb7b5258-7f99dc0b-99f3c35f
Deleting backup...done.
Now we can destroy our VM
Delete GCE VM
In Cloud Shell execute:
export GCEVM=instance-1
export ZONE=us-central1-a
gcloud compute instances delete $GCEVM \
--zone=$ZONE \
--quiet
Expected console output:
student@cloudshell:~ (test-project-001-402417)$ export GCEVM=instance-1
export ZONE=us-central1-a
gcloud compute instances delete $GCEVM \
--zone=$ZONE \
--quiet
Deleted
Delete the Service Account for GCE VM and The Retrieval service
In Cloud Shell execute:
PROJECT_ID=$(gcloud config get-value project)
gcloud iam service-accounts delete compute-aip@$PROJECT_ID.iam.gserviceaccount.com --quiet
Expected console output:
student@cloudshell:~ (gleb-test-short-004)$ PROJECT_ID=$(gcloud config get-value project)
gcloud iam service-accounts delete compute-aip@$PROJECT_ID.iam.gserviceaccount.com --quiet
Your active configuration is: [cloudshell-222]
deleted service account [compute-aip@gleb-test-short-004.iam.gserviceaccount.com]
student@cloudshell:~ (gleb-test-short-004)$
10. Congratulations
Congratulations for completing the codelab.
What we’ve covered
✅ How to deploy AlloyDB Cluster
✅ How to connect to the AlloyDB
✅ How to configure and deploy MCP Toolbox Service
✅ How to deploy a sample application using the deployed service


















