MCP Development with Lisp, Firestore, Cloud Run, and Gemini CLI
Source: Dev.to
Source: Dev.to
Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications with the Lisp language deployed to Google Cloud Run.
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 approaches with other coding languages.
The goal of this article is to provide a minimal viable basic working MCP HTTP transport server in Lisp that can be run locally without any unneeded extra code or extensions.
The bottom line is different strokes for different folks and the tools can meet you where you are. The Internet has gotten over the Emacs vs Vi flame wars.
Resources
-
Lisp MCP library (demo) – https://github.com/40ants/mcp
40ANTS-MCP is a framework for building Model Context Protocol servers in Common Lisp. -
Common Lisp – https://common-lisp.net/ (good starting point)
-
Steel Bank Common Lisp (SBCL) – https://www.sbcl.org/
Standard in most Linux distributions. -
Quicklisp – https://www.quicklisp.org/beta/ (automated package management)
-
Gemini CLI –
npm install -g @google/gemini-cli -
Node Version Manager (nvm) – https://github.com/nvm-sh/nvm
-
Official MCP Lisp docs – https://github.com/40ants/mcp/tree/master/docs
Installing SBCL (Debian 12 example)
sudo apt-get update
sudo apt-get install sbcl
Verify the installation:
xbill@penguin:~$ sbcl --version
SBCL 2.2.9.debian
Setting Up the Development Environment
-
Install Gemini CLI (requires a recent Node.js version).
npm install -g @google/gemini-cli -
Authenticate Gemini CLI (key or Google account).
gemini -
Use nvm to ensure a consistent Node version.
# Follow the instructions in the nvm repo -
Clone the sample repository (includes helper scripts).
cd ~ git clone https://github.com/xbill9/gemini-cli-codeassist -
Initialize the environment.
cd gemini-cli-codeassist source init.sh-
If the session times out or you need to re‑authenticate, run:
source set_env.sh -
PROJECT_IDand other variables are set byset_env.sh.
-
MCP Transport Overview
The standard MCP libraries abstract transport methods, so the high‑level tool implementation is identical regardless of the underlying channel.
| Transport | Description |
|---|---|
| stdio | Connects a locally running process (client & server in same environment). |
| HTTP | Allows client and server to be on the same machine or distributed over the Internet. |
Example: HTTP Transport for Cloud Run
(in-package :40ants-mcp/http-transport)
(setf *sse-handler* (clack-sse:serve-sse 'sse-stream-writer))
(defmethod 40ants-mcp/transport/base:start-loop ((transport http-transport) message-handler)
"Start the HTTP server and begin processing requests.
Monkey‑patched to listen on 0.0.0.0 for Cloud Run."
(log:info "Starting HTTP transport on port" (transport-port transport))
(setf (transport-message-handler transport) message-handler)
;; Start the server
(setf (transport-server transport)
(clack:clackup (transport-lack-app transport)
:server :hunchentoot
:address "0.0.0.0"
:port (transport-port transport)
:use-thread nil)))
The code depends on several standard libraries for MCP and logging:
(defpackage :mcp-server
(:use :cl)
(:import-from :40ants-mcp/tools
:define-tool)
(:import-from :40ants-mcp/server/definition
:start-server
:mcp-server)
(:export :main
:get-greeting))
Running the Minimal MCP Server
-
Load your Lisp environment (e.g.,
sbcl). -
Load the server package and start it:
(in-package :mcp-server) (start-server) ; or whatever entry point you defined -
Validate with Gemini CLI (both client and server run locally).
gemini <your‑command‑or‑prompt>
If everything is set up correctly, Gemini CLI will communicate with the MCP server over HTTP (or stdio) and you’ll see responses from your Lisp implementation.
Next Steps
- Extend the basic server with additional tools using
define-tool. - Deploy the server to Google Cloud Run (the HTTP transport already listens on
0.0.0.0). - Explore more advanced MCP features and integrate with other LLMs via Gemini CLI.
Install dependencies
xbill@penguin:~/gemini-cli-codeassist/firestore-https-lisp$ make deps
2 dists to check.
You already have the latest version of "quicklisp": 2026-01-01.
You already have the latest version of "ultralisp": 20260125155000.
To load "jsonrpc":
Load 1 ASDF system:
jsonrpc
; Loading "jsonrpc"
.
To load "40ants-mcp":
Load 1 ASDF system:
40ants-mcp
; Loading "40ants-mcp"
..................................................
......
To load "serapeum":
Load 1 ASDF system:
serapeum
; Loading "serapeum"
To load "yason":
Load 1 ASDF system:
yason
; Loading "yason"
To load "local-time":
Load 1 ASDF system:
local-time
; Loading "local-time"
Dependencies installed successfully.
Build the binary
xbill@penguin:~/gemini-cli-codeassist/firestore-https-lisp$ make
Building mcp-server...
To load "mcp-https-lisp":
Load 1 ASDF system:
mcp-https-lisp
; Loading "mcp-https-lisp"
..................................................
........
A binary is generated at the end of the process.
Lint the code
xbill@penguin:~/gemini-cli-codeassist/firestore-https-lisp$ make lint
To load "sblint":
Load 1 ASDF system:
sblint
; Loading "sblint"
Run the test suite
xbill@penguin:~/gemini-cli-codeassist/firestore-https-lisp$ make test
To load "mcp-https-lisp/tests":
Load 1 ASDF system:
mcp-https-lisp/tests
; Loading "mcp-https-lisp/tests"
..................................................
..................................................
[package mcp-server-tests].
Testing System mcp-https-lisp/tests
;; testing 'mcp-server-tests'
test-greeting
should return a valid greeting
✓ Expect (STRING= (GET-GREETING "World") "Hello, World!") to be true.
✓ Expect (STRING= (GET-GREETING "Lisp") "Hello, Lisp!") to be true.
✓ 1 test completed
Summary:
All 1 test passed.
Run the local MCP server
xbill@penguin:~/gemini-cli-codeassist/firestore-https-lisp$ make run
To load "mcp-https-lisp":
Load 1 ASDF system:
mcp-https-lisp
; Loading "mcp-https-lisp"
..................................................
........
{"timestamp":"2026-1-25T12:27:54.375041EST","level":"INFO","message":"Metadata service not available or failed, checking GOOGLE_APPLICATION_CREDENTIALS"}
{"timestamp":"2026-1-25T12:27:54.376395EST","level":"DEBUG","message":"Attempting to get token from gcloud"}
{"timestamp":"2026-1-25T12:27:55.261112EST","level":"DEBUG","message":"Successfully got token from gcloud"}
{"timestamp":"2026-1-25T12:27:55.261215EST","level":"INFO","message":"Starting MCP server on port 8080..."}
[12:27:55] 40ants-mcp/server/definition definition.lisp (start-server) -
Starting MCP server with 40ANTS-MCP/SERVER/DEFINITION::TRANSPORT: :HTTP
transport and tools 40ANTS-MCP/SERVER/DEFINITION::TOOLS-COLLECTIONS: #
{"timestamp":"2026-1-25T12:27:55.268663EST","level":"INFO","message":"Starting HTTP transport on port 8080"}
Hunchentoot server is going to start.
Listening on 0.0.0.0:8080.
NOTICE: Running in debug mode. Debugger will be invoked on errors.
Specify ':debug nil' to turn it off on remote environments.
Sample .gemini/settings.json.https (pre‑built)
{
"mcpServers": {
"firestore-https-lisp": {
"url": "http://127.0.0.1:8080/mcp"
}
}
}
Interact with the server via Gemini CLI
Open another terminal and start the Gemini CLI. The local MCP connection over HTTP to the Lisp code is validated and the full Gemini CLI session will start:
> /mcp list
Configured MCP servers:
🟢 firestore-https-lisp - Ready (8 tools)
Tools:
- add
- check_db
- get_product_by_id
- get_products
- get_root
- greet
- reset
- seed
Example conversation
✦ I will execute the get_products tool to retrieve the list of products from the inventory database.
│ ✓ get_products (firestore-https-lisp MCP Server) {} │
✦ I have retrieved the list of products from the inventory database. The results include a variety of items such as Green Tea, Jasmine Rice, Coffee
Beans, and many others, with their current prices and quantities.
This information can be used in the current Gemini CLI context:
> can I make lattes with my inventory
✦ Yes, you have the core ingredients needed to make lattes in your inventory:
* Coffee Beans: 239 units
* Milk: 204 units
You also have Cinnamon (399 units) which could be used as a topping!
Deploy to Google Cloud Run
After the HTTP version of the MCP server has been tested locally, it can be deployed remotely.
# Ensure you are in the project directory
cd ~/gemini-cli-codeassist/firestore-https-lisp
# Deploy using the provided Cloud Build configuration
xbill@penguin:~/gemini-cli-codeassist/firestore-https-lisp$ make deploy
What make deploy does
echo "Submitting build to Google Cloud Build..."
Submitting build to Google Cloud Build...
gcloud builds submit . --config cloudbuild.yaml
Creating temporary archive of 26 file(s) totalling 100.5 KiB before compression.
Some files were not included in the source upload.
Check the gcloud log [/home/xbill/.config/gcloud/logs/2026.01.25/12.38.25.373745.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/1769362705.521381-4d9a6ab6dbb14ef792948c02f4ffff89.tgz]
Created [https://cloudbuild.googleapis.com/v1/projects/comglitn/locations/global/builds/ebfe162d-beed-4817-94b2-5fc8c0ff1bfd].
Logs are available at [https://console.cloud.google.com/cloud-build/builds/ebfe162d-beed-4817-94b2-5fc8c0ff1bfd?project=1056842563084].
Waiting for build to complete. Polling interval: 1 second(s).
---------------------------------------------------------------- REMOTE BUILD OUTPUT ----------------------------------------------------------------
starting build "ebfe162d-beed-4817-9
The Cloud Build will compile the Docker image and deploy the service to Cloud Run. Once the build finishes, you can invoke the MCP server via its public URL.
Build & Deployment Overview
The following steps show how to fetch the source, build the Lisp MCP server, deploy it to Cloud Run, and connect to it with the Gemini CLI.
1. Fetch the source archive
4b2-5fc8c0ff1bfd"
FETCHSOURCE
Fetching storage object:
gs://comglitn_cloudbuild/source/1769362705.521381-4d9a6ab6dbb14ef792948c02f4ffff89.tgz#1769362705948687
The build can take 15–30 minutes while all Lisp libraries are pulled into the build environment and the package is compiled from scratch.
2. Deploy the container to Cloud Run
Starting Step #1
Step #1: Already have image (with digest): gcr.io/cloud-builders/gcloud
Step #1: Deploying container to Cloud Run service [firestore-https-lisp]
in project [comglitn] region [us-central1]
Step #1: Deploying new service...
Step #1: Setting IAM Policy..............done
Step #1: Creating Revision.........................................................................done
Step #1: Routing traffic.....done
Step #1: Done.
Step #1: Service [firestore-https-lisp] revision [firestore-https-lisp-00001-vh7]
has been deployed and is serving 100 % of traffic.
Step #1: Service URL: https://firestore-https-lisp-1056842563084.us-central1.run.app
Finished Step #1 │
Note: The actual service URL will differ per project.
You can view the service details in the Google Cloud Console → Cloud Run.
3. Verify the endpoint
Open the URL in a browser (replace it with the URL you received from Cloud Build):
https://firestore-https-lisp-1056842563084.us-central1.run.app
You will see a “Page Not Found” error – that’s expected because the endpoint expects an MCP request, not a normal HTTP page.
Configure Gemini CLI for Cloud Run
The default settings.json must be replaced with the Cloud‑Run‑specific version.
3.1 Sample settings.json.cloudrun
{
"mcpServers": {
"firestore-cloudrun-lisp": {
"url": "https://firestore-https-lisp-1056842563084.us-central1.run.app/mcp"
}
}
}
3.2 Install the configuration
xbill@penguin:~/gemini-cli-codeassist/firestore-https-lisp$ cd .gemini
xbill@penguin:~/gemini-cli-codeassist/firestore-https-lisp/.gemini$ cp settings.json.cloudrun settings.json
Now the Gemini CLI will point to the Cloud Run MCP server.
Test the connection with Gemini CLI
$ gemini
> /mcp list
Output
Configured MCP servers:
🟢 firestore-cloudrun-lisp - Ready (8 tools)
Tools:
- add
- check_db
- get_product_by_id
- get_products
- get_root
- greet
- reset
- seed
3.1 Run a tool (example: get_products)
? get_products (firestore-cloudrun-lisp MCP Server) {} ←
│
│ MCP Server: firestore-cloudrun-lisp
│ Tool: get_products
│
│ Allow execution of MCP tool "get_products" from server "firestore-cloudrun-lisp"?
│
│ 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)
Select an option (e.g., 3) and you’ll receive a response such as:
✦ I found "Coffee Beans" in the inventory.
Product Details:
- Name: Coffee Beans
- Price: $1
- Quantity: 239
- ID: 37kWbZHTwg5nbrSD13PB
Review the deployed code base
You can also inspect the project structure and key components directly:
> review the project
Project Summary
- Language: Common Lisp
- Purpose: MCP (Model Context Protocol) server that manages an inventory stored in Google Cloud Firestore.
- Core components
- MCP Server (
src/main.lisp) – built on40ants/mcp, includes custom patches for JSON field naming and Cloud Run compatibility; usesclack-ssefor Server‑Sent Events over HTTPS. - Firestore integration (
src/firestore.lisp) – REST calls viadexador; authentication via Google ADC (gcloud locally, metadata service on Cloud Run); manual mapping of Lisp data structures to Firestore JSON. - Build system – defined in
mcp-https-lisp.asd;Makefileprovidesmake deps(Quicklisp/Ultralisp) andmake build(SBCLsave-lisp-and-die). Dockerfile ready for containerization. - Testing – uses
rove; tests located intests/main.lispandtests/packages.lisp.
- MCP Server (
The step‑by‑step process above demonstrates a minimal streaming‑HTTP MCP server built from source, deployed to Cloud Run, and successfully accessed via the Gemini CLI.
Deploying an MCP Client and Server in a Local‑to‑Cloud Workflow
-
Run the MCP client locally in the same environment as your development machine.
-
Containerize the MCP server
- Build a Docker image for the server.
- Push the image to a registry (e.g., Google Artifact Registry).
-
Deploy to Google Cloud Run
- Use Google Cloud Build to build and submit the container.
- Deploy the resulting image to Cloud Run, exposing it via HTTPS.
-
Validate the remote MCP server
- Open the server URL in a standard web browser to confirm it’s reachable.
- Test with the Gemini CLI to ensure the MCP API responds correctly.
-
Perform remote MCP operations
- From your local machine, use the installed Gemini CLI to interact with the Lisp‑based MCP server now running on Cloud Run.
This approach can be extended to more complex deployments and other cloud‑based options.