DEV Community

xbill for Google Developer Experts

Posted on • Originally published at xbill999.Medium on

Secure MCP Development with Go, Cloud Run, and Gemini CLI

Leveraging the Gemini CLI and the underlying Gemini LLM to add support for building secure Model Context Protocol (MCP) AI applications with the Go Language in a local development environment.

What is this Tutorial Trying to Do?

Traditionally, ML and AI tools have been deployed in interpreted languages like Python, and Java. One of the key goals of this tutorial is to validate that a compiled language like Go can be used for AI software development beyond the traditional interpreted languages.

What Is Go?

Go, also known as Golang, is a programming language created at Google. It’s known for being simple, efficient, and reliable. It’s particularly well-suited for building network services and concurrent applications.

Google Open Source Projects

Installing Go

If Go has not been installed in your environment — there are tools for managing Go installations. The Go Version Manager is available here:

GitHub - moovweb/gvm: Go Version Manager

There are several steps to install gvm :

sudo apt-get install bison
sudo apt-get install curl git mercurial make binutils bison gcc build-essential

bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)
Enter fullscreen mode Exit fullscreen mode

Then use the gvm tool to install the latest version of Go:

xbill@penguin:~$ gvm install go1.26.0 -B
Installing go1.26.0 from binary source

gvm use --default go1.26.0
Enter fullscreen mode Exit fullscreen mode

You can validate the installation of Go with the version command:

xbill@penguin:~$ go version
go version go1.26.0 linux/amd64
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 Go and MCP

There are several competing implementations of the MCP protocol in Go.

This article will focus on the official release:

GitHub - modelcontextprotocol/go-sdk: The official Go SDK for Model Context Protocol servers and clients. Maintained in collaboration with Google.

Go MCP Documentation

The official GitHub Repo provides samples and documentation for getting started:

go-sdk/docs at main · modelcontextprotocol/go-sdk

Where do I start?

The strategy for validating Go 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.

Then, a minimal Hello World Style Go MCP Server is built with HTTP transport. This server is validated with Gemini CLI in the local environment. This setup validates the connection from Gemini CLI to the local compiled Go process via MCP. The MCP client (Gemini CLI) and the Go MCP compiled binary Server both run in the same local environment.

Finally- the entire solution is deployed to Google Cloud Run. The local installation of Gemini CLI is used to validate the remote MCP server in Google Cloud Run.

Setup the Basic Environment

At this point you should have a working Go 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/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.

Hello World with HTTP Transport

One of the key features that the Go SDK provides is abstracting various transport methods.

The high level MCP tool implementation is the same no matter what low level transport channel/method that the MCP Client uses to connect to a MCP Server.

The simplest transport that the SDK supports is the stdio (stdio/stdout) transport — which connects a locally running process. Both the MCP client and MCP Server must be running in the same environment.

The HTTP transport allows both the MCP client and server to run on the same server or be distributed over the Internet.

The connection over HTTP will look similar to this:

streamServer := server.NewStreamableHTTPServer(
s, server.WithEndpointPath("/mcp"))
Enter fullscreen mode Exit fullscreen mode

Building the Go Binary

First- switch the directory with the Go stdio sample code:

cd ~/iap-https-rust/manual-go
Enter fullscreen mode Exit fullscreen mode

Build the release version of the Go binary on the local system:

xbill@penguin:~/iap-https-rust/manual-go$ make release
Running the MCP Streamable HTTP server...
{"time":"2026-02-11T20:03:25.242519709-05:00","level":"INFO","msg":"Using MCP API Key from environment or command line for verification"}
{"time":"2026-02-11T20:03:25.242664169-05:00","level":"INFO","msg":"Starting manual-go MCP server","transport":"http"}
{"time":"2026-02-11T20:03:25.242689358-05:00","level":"INFO","msg":"API Key verification enabled (X-Goog-Api-Key)"}
{"time":"2026-02-11T20:03:25.242730862-05:00","level":"INFO","msg":"Listening","address":"0.0.0.0:8080"}
Enter fullscreen mode Exit fullscreen mode

You can validate the final result of the build by checking the compiled Go binary:

fxbill@penguin:~/iap-https-rust/manual-go$ file manual-go
manual-go: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=372849aa3a4bca3403b643f25d6a0d3ef962904e, with debug_info, not stripped
xbill@penguin:~/iap-https-rust/manual-go$ 
Enter fullscreen mode Exit fullscreen mode

Then run local tests:

xbill@penguin:~/iap-https-rust/manual-go$ make test
Running tests...
ok manual-go 0.029s
xbill@penguin:~/iap-https-rust/manual-go$ 
Enter fullscreen mode Exit fullscreen mode

Running the Tool 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/manual-go$ make info
MCP API Key Status
------------------
Provided Key: [NOT FOUND]

Authentication Failed: Invalid or missing API Key
make: *** [Makefile:29: info] Error 1
Enter fullscreen mode Exit fullscreen mode

This call failed because no API key was provided on the command line or in the current environment.

The tool will also fail if an invalid key is passed:

xbill@penguin:~/iap-https-rust/manual-go$ make info KEY=$MCP_API_KEY
{"time":"2026-02-11T20:06:31.949704898-05:00","level":"INFO","msg":"Fetching MCP API Key","projectID":"comglitn"}
{"time":"2026-02-11T20:06:33.379434171-05:00","level":"INFO","msg":"Successfully fetched API key via gcloud"}
MCP API Key Status
------------------
Provided Key: [FOUND]
Cloud Match: [MISMATCH]

Authentication Failed: Invalid or missing API Key
make: *** [Makefile:29: info] Error 1
Enter fullscreen mode Exit fullscreen mode

Setting an API Key

On project setup the init.sh script configures the Google Cloud environment and creates a sample key to secure the connection. To set this key in the current environment — use the set_key.sh script:

xbill@penguin:~/iap-https-rust/manual-go$ source ../set_key.sh
--- Setting Google Cloud Project ID ---
Using Google Cloud project: comglitn
Checking for existing MCP API Key...
Using existing MCP API Key: projects/1056842563084/locations/global/keys/cbd6422f-e594-4536-9ad9-6f179f43f11b
Retrieving API Key string...
MCP API Key retrieved and exported.

This key can be used with all variants that support API key validation:
  - Rust: manual, local, stdiokey
  - Python: manual-python, local-python, stdiokey-python

Ensure this script was sourced: source ./set_key.sh
--- Environment Checks ---
Not running in Google Cloud VM or Shell. Checking ADC...
Running on ChromeOS.
--- Initial Setup complete ---
Enter fullscreen mode Exit fullscreen mode

The tool can now execute:

xbill@penguin:~/iap-https-rust/manual-go$ make info KEY=$MCP_API_KEY
{"time":"2026-02-11T20:07:56.703127003-05:00","level":"INFO","msg":"Fetching MCP API Key","projectID":"comglitn"}
{"time":"2026-02-11T20:07:58.422723437-05:00","level":"INFO","msg":"Successfully fetched API key via gcloud"}
System Information Report
=========================

MCP API Key Status
------------------
Provided Key: [FOUND]
Cloud Match: [MATCHED]

System Information
------------------
System Name: linux
OS Name: linux
Host Name: penguin

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

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

Network Interfaces
------------------
lo : RX: 626457 bytes, TX: 626457 bytes (MAC: unknown)
br-413ba64fd5af : RX: 0 bytes, TX: 0 bytes (MAC: 36:10:67:8c:35:b8)
docker0 : RX: 0 bytes, TX: 0 bytes (MAC: aa:8b:14:57:7f:9b)
eth0 : RX: 1331970660 bytes, TX: 1058239872 bytes (MAC: 00:16:3e:52:c3:b9)
Enter fullscreen mode Exit fullscreen mode

System Information with MCP HTTP Transport

One of the key features that the MCP protocol provides is abstracting various transport methods.

The high level tool MCP implementation is the same no matter what low level transport channel/method that the MCP Client uses to connect to a MCP Server.

The simplest transport that the SDK supports is the stdio (stdio/stdout) transport — which connects a locally running process. Both the MCP client and MCP Server must be running in the same environment.

The HTTP transport allows the MCP client and server to run in the same environment or be distributed over the Internet.

First- switch the directory with the HTTP sample code:

xbill@penguin:~/iap-https-rust/manual-go$ make run
Running the MCP Streamable HTTP server...
{"time":"2026-02-11T20:08:36.272370879-05:00","level":"INFO","msg":"Fetching MCP API Key","projectID":"comglitn"}
{"time":"2026-02-11T20:08:38.21395639-05:00","level":"INFO","msg":"Successfully fetched API key via gcloud"}
{"time":"2026-02-11T20:08:38.213982451-05:00","level":"INFO","msg":"Successfully fetched MCP API Key from Google Cloud settings"}
{"time":"2026-02-11T20:08:38.214024113-05:00","level":"INFO","msg":"Starting manual-go MCP server","transport":"http"}
{"time":"2026-02-11T20:08:38.214036607-05:00","level":"INFO","msg":"API Key verification enabled (X-Goog-Api-Key)"}
{"time":"2026-02-11T20:08:38.214065654-05:00","level":"INFO","msg":"Listening","address":"0.0.0.0:8080"}
Enter fullscreen mode Exit fullscreen mode

This step validates that the tool can be started locally and uses the MCP_API_KEY in the local environment.

Deploying to Cloud Run

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

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

xbill@penguin:~/iap-https-rust/manual-go$ 
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/manual-go$ make deploy
Submitting build to Google Cloud Build...
Creating temporary archive of 11 file(s) totalling 22.4 MiB before compression.
Some files were not included in the source upload.

Check the gcloud log [/home/xbill/.config/gcloud/logs/2026.02.11/20.09.22.015613.log] to see which files and the contents of the
default gcloudignore file used (see `$ gcloud topic gcloudignore` to learn
more).

Uploading tarball of [.] to [gs://comglitn_cloudbuild/source/1770858562.391952-e8d38596e68e41968386aca3f4496957.tgz]
Created [https://cloudbuild.googleapis.com/v1/projects/comglitn/locations/global/builds/bfd4cf99-253f-4b30-96cb-480eb5124195].
Logs are available at [https://console.cloud.google.com/cloud-build/builds/bfd4cf99-253f-4b30-96cb-480eb5124195?project=1056842563084].
Waiting for build to complete. Polling interval: 1 second(s).
Enter fullscreen mode Exit fullscreen mode

The Cloud Build will start:

Starting Step #0
Step #0: Already have image (with digest): gcr.io/cloud-builders/docker
Step #0: Sending build context to Docker daemon 23.48MB
Step #0: Step 1/11 : FROM golang:1.26.0 AS build
Step #0: 1.26.0: Pulling from library/golang
Step #0: ef235bf1a09a: Already exists
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 Go libraries in the build environment and generate the entire package from scratch:

Step #1: Already have image (with digest): gcr.io/cloud-builders/gcloud
Step #1: Deploying container to Cloud Run service [manual-go] 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 [manual-go] revision [manual-go-00003-28k] has been deployed and is serving 100 percent of traffic.
Step #1: Service URL: https://manual-go-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://manual-go-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 HTTP connection

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

https://manual-go-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:

404 page not found
Enter fullscreen mode Exit fullscreen mode

Pass the API Key in Gemini Settings

The stdio server checks the API key if it is provided. The set_key.sh scripts sets the environment variable from the Google Cloud settings. A sample Gemini setup is provided for this scenario as well:

{
  "mcpServers": {
       "sysutils-cloudrun-go": {
               "httpUrl": "https://manual-go-$PROJECT_NUMBER.us-central1.run.app/mcp",
       "headers": {
         "X-Goog-Api-Key": "$MCP_API_KEY"
       }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The set_key.sh will set the required environment variables:

xbill@penguin:~/iap-https-rust/manual-go$ source ../set_key.sh 
--- Setting Google Cloud Project ID ---
Using Google Cloud project: comglitn
Checking for existing MCP API Key...
Using existing MCP API Key: projects/1056842563084/locations/global/keys/cbd6422f-e594-4536-9ad9-6f179f43f11b
Retrieving API Key string...
MCP API Key retrieved and exported.

This key can be used with all variants that support API key validation:
  - Rust: manual, local, stdiokey
  - Python: manual-python, local-python, stdiokey-python

Ensure this script was sourced: source ./set_key.sh
--- Environment Checks ---
Not running in Google Cloud VM or Shell. Checking ADC...
Running on ChromeOS.
--- Initial Setup complete ---
Enter fullscreen mode Exit fullscreen mode

Next Gemini CLI is used to check the MCP connection settings:

 > /mcp list
Configured MCP servers:

🟢 sysutils-cloudrun-go - Ready (2 tools)
  Tools:
  - disk_usage
  - local_system_info
Enter fullscreen mode Exit fullscreen mode

The MCP Server can now be used directly using Gemini CLI as a MCP client. This is the same Rust binary that was tested locally as a standalone build:

 > run mcp tool local_system_info
✦ I will execute the local_system_info tool to gather detailed information about your system's kernel, CPU cores, and memory usage.

╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Action Required │
│ │
│ ? local_system_info (sysutils-cloudrun-go MCP Server) {} │
│ │
│ MCP Server: sysutils-cloudrun-go │
│ Tool: local_system_info │
│ Allow execution of MCP tool "local_system_info" from server "sysutils-cloudrun-go"? │
│ │
│ 1. Allow once │
│ 2. Allow tool for this session │
│ 3. Allow all server tools for this session │
│ ● 4. Allow tool for all future sessions │
│ 5. No, suggest changes (esc) │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ local_system_info (sysutils-cloudrun-go MCP Server) {} │
│ │
│ System Information Report │
│ ========================= │
│ │
│ Authentication: [VERIFIED] (Running as MCP Server) │
│ │
│ System Information │
│ --- │
│ System Name: linux │
│ OS Name: linux │
│ 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 │
│ --- │
│ lo : RX: 0 bytes, TX: 0 bytes (MAC: unknown) │
│ eth1 : RX: 12911 bytes, TX: 6184 bytes (MAC: unknown) │
│ eth2 : RX: 15525 bytes, TX: 8594 bytes (MAC: 42:00:4e:49:43:00) │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ The local_system_info tool has been executed, and the system information report is displayed above.
Enter fullscreen mode Exit fullscreen mode

Validate with Invalid Key

To verify that that Cloud Run Service checks the key- call the endpoint with an invalid MCP_API_KEY:

xbill@penguin:~/iap-https-rust/manual-go$ export MCP_API_KEY=gophergo!
xbill@penguin:~/iap-https-rust/manual-go$ 

ℹ MCP server 'sysutils-cloudrun-go' requires authentication using: /mcp auth sysutils-cloudrun-go
 > /mcp list
Configured MCP servers:

🔴 sysutils-cloudrun-go - Disconnected (OAuth not authenticated)
Enter fullscreen mode Exit fullscreen mode

Summary

The strategy for using Go for MCP development with Gemini CLI was validated with a incremental step by step approach.

A minimal HTTP transport MCP Server was started from source code and validated with Gemini CLI running as a MCP client in the same local environment.

This basic Go code was enhanced with an API key generated and stored in the main Google Cloud project.

This API key was used to validate access to the local Go tool and the HTTP MCP version directly from Gemini CLI.

Then the entire solution was deployed to Google Cloud Run. This remote deployment was validated with the local Gemini CLI installation.

This approach can be extended to more complex deployments using other MCP transports and Cloud based options.

Top comments (0)