DEV Community

xbill for Google Developer Experts

Posted on • Originally published at xbill999.Medium on

Building a Secure MCP Server with Cloud Run, Rust, and Gemini CLI

Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in the Rust programming language with Cloud Run development environment and the HTTPS MCP transport.

Why not just use Python?

Python has traditionally been the main coding language for ML and AI tools. One of the strengths of the MCP protocol is that the actual implementation details are independent of the development language. The reality is that not every project is coded in Python- and MCP allows you to use the latest AI appt roaches with other coding languages.

What is this Tutorial Trying to Do?

Building on previous tutorials, the goal is to extend a Rust MCP server with Bearer Token support. The ultimate goal is allowing MCP servers to be deployed as authenticated Cloud Run endpoints.

What is Rust?

Rust is a high performance, memory safe, compiled language:

Rust

Rust provides memory safe operations beyond C/C++ and also can provide exceptional performance gains as it is compiled directly to native binaries.

Initial Environment Setup

The environment is meant to be run from a Bash like shell. You can run this from a Linux VM, ChromeOS Linux VM, Firebase Studio environment, or any environment that provides a basic shell. You will also need a working Docker environment.

Rust Setup

Instructions to install Rust are available here:

Getting started

For a Linux like environment the command looks like this:

curl — proto ‘=https’ — tlsv1.2 -sSf https://sh.rustup.rs | sh
Enter fullscreen mode Exit fullscreen mode

Rust also depends on a working C compiler and OpenSSL setup. For a Debian 12 system — install the basic tools for development:

sudo apt install build-essential
sudo apt install libssl-dev
sudo apt install pkg-config
sudo apt-get install libudev-dev
sudo apt install make
sudo apt install git
Enter fullscreen mode Exit fullscreen mode

Gemini CLI

If not pre-installed you can download the Gemini CLI to interact with the source files and provide real-time assistance:

sudo npm install -g @google/gemini-cli
Enter fullscreen mode Exit fullscreen mode

Note- if you are an a non standard environment — you will need to make sure to have at least Node version 20 available in order to run Gemini CLI.

Testing the Gemini CLI Environment

Once you have all the tools and the correct Node.js version in place- you can test the startup of Gemini CLI. You will need to authenticate with a Key or your Google Account:

gemini
Enter fullscreen mode Exit fullscreen mode

Getting Started with Rust and MCP

When MCP was first released, there were several competing Rust frameworks that provided support for the protocol. Eventually, one official supported SDK was consolidated to provide a standard package for building MCP applications with Rust. This SDK is more like a toolbox that provides many options- clients/servers, different transports, and even more advanced integration options.

The official MCP Rust SDK (rmcp) is available here:

GitHub - modelcontextprotocol/rust-sdk: The official Rust SDK for the Model Context Protocol

Where do I start?

The strategy for validating Rust for MCP development is a incremental step by step approach.

First, the basic development environment is setup with the required system variables and a working Gemini CLI configuration.

A command line version of the System Information tool is built with Gemini CLI.

Then, a minimal Rust MCP Server is built with the HTTP transport working directly with Gemini CLI in the local environment. This validates the connection from Gemini CLI to the local compiled Rust process via MCP. The MCP client (Gemini CLI) and the Rust MCP compiled binary Server both run in the same environment.

Setup the Basic Environment

At this point you should have a working Rust compiler and a working Gemini CLI installation. The next step is to clone the GitHub samples repository with support scripts:

cd ~
git clone https://github.com/xbill9/iap-https-rust
Enter fullscreen mode Exit fullscreen mode

Then run init.sh from the cloned directory.

The script will attempt to determine your shell environment and set the correct variables:

cd iap-https-rust
source init.sh
Enter fullscreen mode Exit fullscreen mode

If your session times out or you need to re-authenticate- you can run the set_env.sh script to reset your environment variables:

cd iap-https-rust
source set_env.sh
Enter fullscreen mode Exit fullscreen mode

Variables like PROJECT_ID need to be setup for use in the various build scripts- so the set_env script can be used to reset the environment if you time-out.

Minimal System Information Tool Build

The first step is to build the basic tool directly with Rust. This allows the tool to be debugged and tested locally before adding the MCP layer.

All of the sample code is in the manual directory-which is shorthand for a HTTP transport MCP server with a Bearer Token:

xbill@penguin:~/iap-https-rust/bearer-rust$
Enter fullscreen mode Exit fullscreen mode

First build the tool locally:

xbill@penguin:~/iap-https-rust/bearer-rust$ make 
Building the Rust project...
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
xbill@penguin:~/iap-https-rust/bearer-rust$ 
Enter fullscreen mode Exit fullscreen mode

then lint check the code:

xbill@penguin:~/iap-https-rust/bearer-rust$ make lint
Linting code...
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.37s
xbill@penguin:~/iap-https-rust/bearer-rust$ 
Enter fullscreen mode Exit fullscreen mode

and run local tests:

xbill@penguin:~/iap-https-rust/bearer-rust$ make test
Running tests...
   Compiling bearer-rust v0.3.0 (/home/xbill/iap-https-rust/bearer-rust)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 4.95s
     Running unittests src/main.rs (target/debug/deps/bearer_rust-398bc4508a7a7b5a)

running 7 tests
test tests::test_decode_iap_jwt ... ok
test tests::test_schema_generation ... ok
test tests::test_health_check ... ok
test tests::test_disk_usage ... ok
test tests::test_list_processes ... ok
test tests::test_sysutils_bearer_rust ... ok
test tests::test_collect_system_info_with_context ... ok

test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s

xbill@penguin:~/iap-https-rust/bearer-rust$ 
Enter fullscreen mode Exit fullscreen mode

The last step is to build the production version:

xbill@penguin:~/iap-https-rust/bearer-rust$ make release
Building Release...
    Finished `release` profile [optimized] target(s) in 0.09s
xbill@penguin:~/iap-https-rust/bearer-rust$ 
Enter fullscreen mode Exit fullscreen mode

Testing the Rust Code Locally

Once the release version has been built- the resulting binary can be executed directly in the local environment.

The quick summary of local system info can be run right from the Makefile:

xbill@penguin:~/iap-https-rust/bearer-rust$ make info
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.26s
     Running `target/debug/bearer-rust info`
DEBUG: Starting bearer-rust version 0.3.0-debug
DEBUG: Environment: PORT=8080
DEBUG: Sleeping for 10s before bind to allow environment to settle
DEBUG: Attempting to bind to 0.0.0.0:8080
DEBUG: Successfully bound to 0.0.0.0:8080
System Information Report
=========================

IAP Context & Identity
----------------------
Header Source: x-goog-iap-jwt-assertion
Status: No IAP JWT found (Expected in production Cloud Run environment)

HTTP Request Headers
--------------------
Status: No request headers captured (CLI mode or capture error)

IAP Setup Configuration
-----------------------
Status: No IAP configuration files found in current directory.

System Information
------------------
System Name: Debian GNU/Linux
Kernel Version: 6.6.99-09070-g0245f6566c20
OS Version: 12
Host Name: penguin

CPU Information
---------------
Number of Cores: 12

Memory Information
------------------
Total Memory: 6410 MB
Used Memory: 123 MB
Total Swap: 0 MB
Used Swap: 0 MB

Network Interfaces
------------------
eth0 : RX: 45711806 bytes, TX: 124164836 bytes (MAC: 00:16:3e:52:c3:b9)
lo : RX: 15816 bytes, TX: 15816 bytes (MAC: 00:00:00:00:00:00)
Enter fullscreen mode Exit fullscreen mode

Deploying to Cloud Run

After the HTTP version of the tool has been tested locally — it can be deployed remotely to Google Cloud Run.

First- switch to the directory with the HTTP sample code:

cd ~/sysutils-https-rust/bearer-rust
Enter fullscreen mode Exit fullscreen mode

Deploy the project to Google Cloud Run with the pre-built cloudbuild.yaml and Dockerfile:

xbill@penguin:~/iap-https-rust/bearer-rust$ make deploy

Enter fullscreen mode Exit fullscreen mode

The Cloud Build will start:

xbill@penguin:~/iap-https-rust/bearer-rust$ make deploy
Submitting build to Google Cloud Build...
     Removed 3430 files, 1.6GiB total

Starting Step #0
Step #0: Already have image (with digest): gcr.io/cloud-builders/docker
Step #0: Sending build context to Docker daemon 108.5kB
Step #0: Step 1/11 : FROM rust:1.93-bookworm AS builder
Enter fullscreen mode Exit fullscreen mode

It can take 15–30 minutes to complete the build.

The Cloud Build needs to pull in all the Rust libraries in the build environment and generate the entire package from scratch:

Starting Step #1
Step #1: Already have image (with digest): gcr.io/cloud-builders/gcloud
Step #1: Deploying container to Cloud Run service [sysutils-bearer-rust] in project [comglitn] region [us-central1]
Step #1: Deploying...
Step #1: Setting IAM Policy............done
Step #1: Creating Revision............................................................................................................................................................done
Step #1: Routing traffic.....done
Step #1: Done.
Step #1: Service [sysutils-bearer-rust] revision [sysutils-bearer-rust-00003-9lw] has been deployed and is serving 100 percent of traffic.
Step #1: Service URL: https://sysutils-bearer-rust-1056842563084.us-central1.run.app
Finished Step #1
Enter fullscreen mode Exit fullscreen mode

When the build is complete- an endpoint will be returned. The service endpoint in this example is :

https://sysutils-bearer-rust-1056842563084.us-central1.run.app
Enter fullscreen mode Exit fullscreen mode

The actual endpoint will vary based on your project settings.

Review Service in Cloud Run

Navigate to the Google Cloud console and search for Cloud Run -

and then you can detailed information on the Cloud Run Service:

Cloud Logging

The remote server writes logs to stderr in standard JSON format. These logs are available from the deployed Cloud Run Service:

Validate the connection

Once you have the Endpoint — you can attempt a connection- navigate to in your browser:

https://sysutils-https-rust-1056842563084.us-central1.run.app
Enter fullscreen mode Exit fullscreen mode

You will need to adjust the exact URL to match the URL returned from Cloud Build.

You will get an error- this connection is expecting a message in the MCP format:

{"jsonrpc":"2.0","id":null,"error":{"code":-32700,"message":"Parse error"}}
Enter fullscreen mode Exit fullscreen mode

Gemini CLI settings.json

Replace the default Gemini CLI configuration file —  settings.json with a pre-configured sample- settings.json.cloudrun to use the Cloud Run version of the connection:

{
  "mcpServers": {
    "sysutils-cloudrun-rust": {
    "httpUrl": "https://sysutils-bearer-rust-$PROJECT_NUMBER.us-central1.run.app/mcp",
      "headers": {
        "Authorization": "Bearer $ID_TOKEN"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Validation with Gemini CLI

The final connection test uses Gemini CLI as a MCP client with the deployed Cloud Run Service in Rust providing the MCP server.

Run the environment script to configure the correct variables:

xbill@penguin:~/iap-https-rust/bearer-rust$ source startbearer-rust.sh 
--- Setting Google Cloud Environment Variables ---
Checking gcloud authentication status...
gcloud is authenticated.
Setting gcloud config project to: comglitn
Caution: Project 'comglitn' is designated as 'Development'(tagged 'environment: Development'). Making changes could affect your 'Development' apps. If incorrect, you can update it by managing the tag binding for the 'environment' key using `gcloud resource-manager tags bindings create`. Learn more at https://cloud.google.com/resource-manager/docs/creating-managing-projects#designate_project_environments_with_tags
Updated property [core/project].
Exported PROJECT_ID=comglitn
Exported PROJECT_NUMBER=1056842563084
Exported SERVICE_ACCOUNT_NAME=1056842563084-compute@developer.gserviceaccount.com
Exported GOOGLE_CLOUD_PROJECT=comglitn
Exported GOOGLE_CLOUD_LOCATION=us-central1
Exported REGION=us-central1
Exported GOOGLE_GENAI_USE_VERTEXAI=TRUE

--- Environment setup complete ---
Fetching Cloud Run service URL for sysutils-bearer-rust in us-central1...
Service URL: https://sysutils-bearer-rust-fgasxpwzoq-uc.a.run.app
Fetching identity token from ADC...

--- Authentication Debug Information ---
Authenticated as: xbill@glitnir.com
Active Project: comglitn
Target Service: sysutils-bearer-rust
Target Region: us-central1
----------------------------------------

Done. is now configured for direct Cloud Run access.
Enter fullscreen mode Exit fullscreen mode

Then startup Gemini CLI with the updated settings :

 > /mcp list
Configured MCP servers:

🟢 sysutils-cloudrun-rust - Ready (3 tools)
  Tools:
  - disk_usage
  - list_processes
  - sysutils_bearer_rust
Enter fullscreen mode Exit fullscreen mode

Verify that the MCP tool is in fact running remotely in Cloud Run:

 > sysutils_bearer_rust
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ sysutils_bearer_rust (sysutils-cloudrun-rust MCP Server) {} │
│ │
│ System Information Report │
│ ========================= │
│ │
│ IAP Context & Identity │
│ --- │
│ Header Source: x-goog-iap-jwt-assertion │
│ Status: No IAP JWT found (Expected in production Cloud Run environment) │
│ │
│ HTTP Request Headers │
│ --- │
│ Status: No request headers captured (CLI mode or capture error) │
│ │
│ IAP Setup Configuration │
│ --- │
│ Status: No IAP configuration files found in current directory. │
│ │
│ System Information │
│ --- │
│ System Name: Debian GNU/Linux │
│ Kernel Version: 4.4.0 │
│ OS Version: 12 │
│ Host Name: localhost │
│ │
│ CPU Information │
│ --- │
│ Number of Cores: 2 │
│ │
│ Memory Information │
│ --- │
│ Total Memory: 1024 MB │
│ Used Memory: 5 MB │
│ Total Swap: 0 MB │
│ Used Swap: 0 MB │
│ │
│ Network Interfaces │
│ --- │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I've retrieved the system information report. Is there anything specific you would like me to analyze or do with this information?

Enter fullscreen mode Exit fullscreen mode

Package Information on crates.io

The complete package is available on the Rust crates.io site:

crates.io: Rust Package Registry

Here is the package details page:

Summary

A complete Rust native system information utility was built and testing using Gemini CLI along with Rust libraries. This compiled Rust code was then called directly from the local environment and returned basic system information.

Then, the tool was wrapped in a container and deployed to Google Cloud Run. This cloud deployment was used to verify the environment in the remote Cloud Run server over the streaming HTTP MCP transport with a local copy of Gemini CLI.

Top comments (0)