DEV Community

xbill for Google Developer Experts

Posted on • Originally published at xbill999.Medium on

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

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

What is this Tutorial Trying to Do?

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

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 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

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

The official MCP Go SDK is available here:

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

Where do I start?

The strategy for validating Go for MCP development is an 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 Go 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 Go process via MCP. The MCP client (Gemini CLI) and the Go MCP compiled binary Server both run in the same environment.

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/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 Go. 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-go$
Enter fullscreen mode Exit fullscreen mode

First build the tool locally:

Cleaning the project...
xbill@penguin:~/iap-https-rust/bearer-go$ make
xbill@penguin:~/iap-https-rust/bearer-go$ file bearer-go
bearer-go: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, Go BuildID=txipku8-J40tLBXOPsf0/OJaXpYXadXZU_KjxBoCL/6bG-H63Cm7NK2gAdO87r/O-Vr938kXDTsbJSkkDqT, BuildID[sha1]=88175f7dd56ffe7c44a0d9bc97eef64542bb4367, with debug_info, not stripped
Enter fullscreen mode Exit fullscreen mode

then lint check the code:

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

and run local tests:

xbill@penguin:~/iap-https-rust/bearer-go$ make test
Running tests...
ok bearer-go (cached)
Enter fullscreen mode Exit fullscreen mode

The last step is to build the production version:

xbill@penguin:~/iap-https-rust/bearer-go$ make release
{"time":"2026-02-18T09:55:51.687890934-05:00","level":"INFO","msg":"APP_STARTING"}
{"time":"2026-02-18T09:55:51.688114952-05:00","level":"INFO","msg":"Entering Server Mode","port":"8080","auth_enabled":false}
{"time":"2026-02-18T09:55:51.688191539-05:00","level":"INFO","msg":"Starting ListenAndServe","address":"0.0.0.0:8080"}
Enter fullscreen mode Exit fullscreen mode

Testing the Go 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-go$ make info
{"time":"2026-02-18T09:56:19.095692922-05:00","level":"INFO","msg":"APP_STARTING"}
System Information Report
=========================

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: 599 MB
Total Swap: 0 MB
Used Swap: 0 MB

Network Interfaces
------------------
lo : RX: 15816 bytes, TX: 15816 bytes (MAC: unknown)
eth0 : RX: 56290772 bytes, TX: 125820171 bytes (MAC: 00:16:3e:52:c3:b9)
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-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/bearer-go$ make deploy
Submitting build to Google Cloud Build...
Enter fullscreen mode Exit fullscreen mode

The Cloud Build will start:

Creating temporary archive of 11 file(s) totalling 21.5 KiB before compression.
Some files were not included in the source upload.

Check the gcloud log [/home/xbill/.config/gcloud/logs/2026.02.18/09.58.38.165850.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/1771426718.321816-39bb1f4bf74e4ab6a1ef224522c270f6.tgz]
Created [https://cloudbuild.googleapis.com/v1/projects/comglitn/locations/global/builds/4928bdc1-0734-4bc8-9a0a-b8e431834e89].
Logs are available at [https://console.cloud.google.com/cloud-build/builds/4928bdc1-0734-4bc8-9a0a-b8e431834e89?project=1056842563084].
Waiting for build to complete. Polling interval: 1 second(s).
------------------------------------------------------------ REMOTE BUILD OUTPUT -------------------------------------------------------------
starting build "4928bdc1-0734-4bc8-9a0a-b8e431834e89"
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: Routing traffic.....done
Step #1: Done.
Step #1: Service [sysutils-bearer-go] revision [sysutils-bearer-go-00004-d4t] has been deployed and is serving 100 percent of traffic.
Step #1: Service URL: https://sysutils-bearer-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://sysutils-bearer-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 the connection

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

https://sysutils-bearer-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:

Error: Forbidden
Your client does not have permission to get URL / from this server.
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-go": {
    "httpUrl": "https://sysutils-bearer-go-$PROJECT_NUMBER.us-central1.run.app/mcp",
      "headers": {
        "Authorization": "Bearer $ID_TOKEN"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Test Connection With Gemini CLI

First- test the connection with Gemini CLI:

ℹ 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

This will fail as the environment variables have not been set.

Validation with Gemini CLI

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

Run the environment script to configure the correct variables:

xbill@penguin:~/iap-https-rust/bearer-go$ source startbearer-go.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](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](mailto: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-go in us-central1...
Service URL: [https://sysutils-bearer-go-fgasxpwzoq-uc.a.run.app](https://sysutils-bearer-go-fgasxpwzoq-uc.a.run.app)
Fetching identity token from ADC...

--- Authentication Debug Information ---
Authenticated as: [xbill@glitnir.com](mailto:xbill@glitnir.com)
Active Project: comglitn
Target Service: sysutils-bearer-go
Target Region: us-central1
----------------------------------------

Done. .gemini/settings.json 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-go - Ready (2 tools)
  Tools:
  - disk_usage
  - local_system_info
Enter fullscreen mode Exit fullscreen mode

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

 > call mcp tool local_system_info
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ local_system_info (sysutils-cloudrun-go MCP Server) {} │
│ │
│ System Information Report │
│ ========================= │
│ │
│ 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: 1 MB │
│ Total Swap: 0 MB │
│ Used Swap: 0 MB │
│ │
│ Network Interfaces │
│ --- │
│ eth2 : RX: 22403 bytes, TX: 11083 bytes (MAC: 42:00:4e:49:43:00) │
│ lo : RX: 0 bytes, TX: 0 bytes (MAC: unknown) │
│ eth1 : RX: 0 bytes, TX: 0 bytes (MAC: unknown) │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ System Information Report
  =========================

  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: 1 MB
  Total Swap: 0 MB
  Used Swap: 0 MB

  Network Interfaces
  ---
  eth2 : RX: 22403 bytes, TX: 11083 bytes (MAC: 42:00:4e:49:43:00)
  lo : RX: 0 bytes, TX: 0 bytes (MAC: unknown)
  eth1 : RX: 0 bytes, TX: 0 bytes (MAC: unknown)

Enter fullscreen mode Exit fullscreen mode

This MCP tool runs inside the Cloud Run environment — and correctly identifies the server differences from the local development environment.

Summary

A complete Go native system information utility was built and tested using Gemini CLI along with Go libraries. This compiled Go 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)