Local MCP Development with Zig and Gemini CLI
Source: Dev.to
Overview
- Python has traditionally dominated ML/AI tooling, but the MCP protocol is language‑agnostic.
- This guide shows how to use Zig—a modern, open‑source systems language—as the development language for MCP.
- You’ll end up with a tiny “Hello World”‑style Zig MCP server that communicates with Gemini CLI over stdio.
Resources
| Resource | Description |
|---|---|
| ZigMCP library | Comprehensive MCP library for Zig |
| Zig home page | |
| Debian Zig install guide | |
| Gemini CLI (npm) | npm install -g @google/gemini-cli |
| Node Version Manager (nvm) | |
| MCP Zig docs & samples |
Prerequisites
-
Zig (latest stable) – install via your OS package manager or the Debian guide above.
-
Node.js – a recent, up‑to‑date version. Use nvm to manage it:
# Install nvm (if not already present) curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # Load nvm and install Node LTS source ~/.bashrc # or ~/.zshrc nvm install --lts -
Gemini CLI – install globally with npm:
npm install -g @google/gemini-cli -
Authentication – run
geminionce to log in with a Google account or API key.
Setting Up the Development Environment
# Clone the helper repository (contains init scripts and sample code)
cd ~
git clone https://github.com/xbill9/gemini-cli-codeassist
cd gemini-cli-codeassist
# Initialise environment variables for your shell
source init.sh
If your session expires or you need to re‑authenticate later:
source set_env.sh # resets PROJECT_ID, credentials, etc.
Building the Minimal MCP stdio Server
1. Create the Zig project
The sample project lives under gemini-cli-codeassist/mcp-stdio-zig.
Navigate there and run the default Make target:
cd mcp-stdio-zig
make # runs `zig build`
You should see something like:
Linked zig-out/bin/mcp-stdio-zig to server
2. Source code highlights
// src/main.zig
const std = @import("std");
const mcp = @import("mcp");
// Run the server using stdio transport
try server.run(.{ .stdio = {} });
The server imports the standard Zig library (std) and the MCP library (mcp), then starts a stdio‑based MCP server.
3. Lint / format
make lint
# → zig fmt --check .
# → zig build -Doptimize=ReleaseFast
4. Test the server
make test
# Output (truncated):
# Testing 'greet' tool...
# ✓ initialize successful
# ✓ notifications/initialized sent
# ✓ tools/list successful
# ✓ tools/call (greet) successful
# All tests passed!
The test harness (python3 test_server.py) validates the greet tool.
Registering the Server with Gemini CLI
Add an entry to ~/.config/gemini-cli/settings.json (or the default location):
{
"mcpServers": {
"mcp-stdio-zig": {
"command": "$HOME/gemini-cli-codeassist/mcp-stdio-zig/server"
}
}
}
Restart Gemini CLI to pick up the new configuration.
Using the MCP Server
# Start a Gemini CLI session
gemini
> /mcp schema
Configured MCP servers:
🟢 mcp-stdio-zig - Ready (1 tool)
Tools:
- greet
Get a greeting from a local stdio server.
Parameters:
{
"type": "object"
}
Now invoke the tool:
> greet Carmen!
✦ I will read the src/main.zig file to understand how the greet tool is implemented and what parameters it expects.
╭─────────────────────────────────────────────────────────────────────╮
│ ✓ ReadFile src/main.zig │
╰─────────────────────────────────────────────────────────────────────╯
The server responds with the greeting, confirming that the MCP stdio transport works end‑to‑end.
Recap & Next Steps
- Environment – Zig, Node (via nvm), Gemini CLI installed and authenticated.
- Server – Minimal Zig MCP stdio server compiled and tested.
- Integration – Registered with Gemini CLI, verified via
/mcp schemaand a tool call.
From here you can:
- Add more MCP tools (e.g.,
summarize,translate). - Switch to other transports (TCP, WebSocket) using the same high‑level MCP API.
- Embed the Gemini LLM directly into Zig code for tighter integration.
Happy coding! 🚀
MCP Tools Extension – Summary
1️⃣ Greeting Test
Command
✦ I will call the greet tool with the parameter param set to "Carmen!".
Tool Invocation
✓ greet (mcp-stdio-zig MCP Server) {"param":"Carmen!"}
Result
Carmen!
Note: The tool returned “Carmen!”, confirming that the basic MCP functionality works.
2️⃣ Adding New MCP Tools
The Zig project was extended with three new tools:
| Tool | Purpose |
|---|---|
zig-info | Returns Zig version, OS, and architecture |
server-info | Returns server name and version |
current-time | Returns the current system timestamp |
Code Diff (added to src/main.zig)
+ fn serverInfoHandler(allocator: std.mem.Allocator, _: ?std.json.Value) mcp.tools.ToolError!mcp.tools.ToolResult {
+ logInfo("Executed server-info tool");
+
+ const info = "Server: mcp-stdio-zig, Version: 0.1.0";
+ var items = allocator.alloc(mcp.types.ContentItem, 1) catch return mcp.tools.ToolError.OutOfMemory;
+ items[0] = .{ .text = .{ .text = try allocator.dupe(u8, info) } };
+
+ return mcp.tools.ToolResult{
+ .content = items,
+ .is_error = false,
+ };
+ }
The changes were committed, and the new tools were verified.
3️⃣ Build & List Tools
xbill@penguin:~/gemini-cli-codeassist/mcp-stdio-zig$ make
zig build
Linked zig-out/bin/mcp-stdio-zig to server
List Available MCP Tools
/mcp list
Configured MCP servers:
🟢 mcp-stdio-zig - Ready (4 tools)
Tools:
- current-time
- greet
- server-info
- zig-info
4️⃣ Running the New Tools
current-time
✓ current-time (mcp-stdio-zig MCP Server) {}
Timestamp: 1769875173
zig-info
✓ zig-info (mcp-stdio-zig MCP Server) {}
Zig Version: 0.15.2, OS: linux, Arch: x86_64
Result: Confirmed you are running Zig 0.15.2 on Linux x86_64.
server-info
✓ server-info (mcp-stdio-zig MCP Server) {}
Server: mcp-stdio-zig, Version: 0.1.0
Result: Confirmed the server name and version.
5️⃣ Summarizing the Zig Environment
Using the MCP tools and the codebase:
✓ ReadFile src/main.zig
✓ ReadFile build.zig
✓ ReadFile build.zig.zon
Summary
- Zig Version: 0.15.2
- Operating System: Linux (x86_64)
- MCP Server:
mcp-stdio-zig(v0.1.0) - Primary Dependency:
mcp.zig(v0.0.1) – a Model Context Protocol implementation for Zig. - Communication: Standard Input/Output (stdio) with structured JSON logging to
stderr. - Exposed Tools:
greet– Returns a greeting (parameterized).zig-info– Reports Zig version, OS, and architecture.server-info– Returns server name and version.current-time– Provides the current system timestamp.
6️⃣ The Ultimate Showdown: Ferris vs. Carmen
Google Search (for context)
✓ GoogleSearch Searching the web for: "who is carmen programming language mascot"
Search results for "who is carmen programming language mascot" returned.
Result
In a hypothetical smack‑down between Ferris the Rust Crab and Carmen the Zig Allocgator, we get a battle of Safety vs. Control.
Tale of the Tape
| Contestant | Signature Move | Defense | Weakness |
|---|---|---|---|
| 🦀 Ferris (Rust) | “Borrow Checker” (Hold) – you can’t move data until it’s proven safe. | Very high – the type system makes memory corruption nearly impossible. | Long compile times; slower to get ready for the fight. |
| 🐊 Carmen (Zig) | “Defer Deinit” (Death Roll) – resources are cleaned up when you explicitly tell her. | High – manual control gives power but requires discipline. | Requires explicit management; mistakes can lead to leaks or crashes. |
Bottom line: Ferris brings ironclad safety, while Carmen offers fine‑grained control. The winner depends on whether you value guaranteed safety (Rust) or deterministic, low‑overhead control (Zig).
Using Zig with MCP Development (Gemini CLI)
The strategy for using Zig with MCP development via the Gemini CLI was validated with an incremental, step‑by‑step approach:
- A minimal
stdiotransport MCP server was started from Zig source code and validated with the Gemini CLI running as an MCP client in the same local environment. - The Gemini CLI was then used to extend the sample Zig code with several MCP tools and to use these tools inside the context for the underlying LLM.