Guidance for Claude Code when working in this repository.
iap-https-rust is a multi-language, multi-variant Model Context Protocol (MCP)
server workspace. Every variant exposes the same family of system-utility tools
(system info, disk usage, process list) but differs in language, transport,
and security model. The point of the repo is the comparison: the same server
implemented three ways and secured five ways.
There is no shared library. Each variant is a self-contained project with its
own Cargo.toml / go.mod / pyproject.toml, Makefile, README.md, and
GEMINI.md. Code is duplicated across variants on purpose — do not try to
factor it into a workspace crate or shared module unless explicitly asked.
| Directory | Lang | Transport | Auth | Notes |
|---|---|---|---|---|
iap/ |
Rust | Streamable HTTP | IAP JWT | Decodes x-goog-iap-jwt-assertion |
manual/ |
Rust | Streamable HTTP | IAP + x-goog-api-key |
Key fetched via ADC or gcloud |
local/ |
Rust | Streamable HTTP | API key | Local dev; gcloud key fetch |
stdio/ |
Rust | Stdio | none | Newest variant (rmcp 3.x) |
stdiokey/ |
Rust | Stdio | API key | --key or MCP_API_KEY |
bearer-rust/ |
Rust | Streamable HTTP | IAP / bearer ID token | Cloud Run + gcloud auth print-identity-token |
proxy-rust/ |
Rust | Streamable HTTP | IAP header decode | Reached via gcloud run services proxy |
local-python/ |
Python | SSE | API key | pkg name httpkey-python |
manual-python/ |
Python | SSE | API key | pkg name httpkey-python |
stdiokey-python/ |
Python | Stdio | API key | |
bearer-python/ |
Python | SSE | bearer ID token | |
proxy-python/ |
Python | SSE | via Cloud Run proxy | |
stdio-go/ |
Go | Stdio | none | |
stdiokey-go/ |
Go | Stdio | API key | |
manual-go/ |
Go | HTTP | IAP + API key | |
bearer-go/ |
Go | HTTP | bearer ID token | |
proxy-go/ |
Go | HTTP | via Cloud Run proxy |
local-rust, manual-rust, stdio-rust, stdiokey-rust are symlinks to
local, manual, stdio, stdiokey. Edit the real directory; never write
through the symlink path, and never create a second copy of a file under both names.
- Rust — edition 2024. Most variants pin
rmcp0.14;stdio/is onrmcp3.1.0 and is the reference for the newer API.tokio,axum,sysinfo,tracing. - Go — 1.26,
github.com/mark3labs/mcp-go,gopsutil/v3. - Python — 3.11+,
mcp,starlette,uvicorn,psutil.
ServerInfo(InitializeResult) is#[non_exhaustive]. Build it withServerInfo::new(capabilities)pluswith_*helpers — a struct literal will not compile.- Bare
#[tool_handler]defaults torouter = Self::tool_router(), rebuilding the router on every tool call. Use#[tool_handler(router = self.tool_router)]to reuse the router cached innew().
See docs/upgrade-rmcp-3-and-claude-code.md for the full migration write-up.
Every variant directory has the same Makefile vocabulary. Work from inside the variant directory:
cd stdio
make build # cargo build (Python: `make install`)
make test # cargo test
make fmt # cargo fmt --all -- --check (note: CHECK mode, does not rewrite)
make clippy # cargo clippy -- -D warnings (Python/Go: `make lint`)
make release # optimized build
make run # start the server
make info # CLI system report, no server
make disk # CLI disk report, no server
make deploy # gcloud builds submit --config cloudbuild.yaml (HTTP variants only)The root Makefile fans out build/test/fmt/clippy/check, but only
over iap manual local stdio stdiokey and local-python manual-python stdiokey-python. The Go, bearer-*, and proxy-* variants are not covered
by the root Makefile — build and test those from their own directories.
In the Rust variants make fmt runs cargo fmt --check, so it fails on
unformatted code rather than fixing it — run cargo fmt --all to apply
formatting. The Go and Python make fmt targets do rewrite files (go fmt ./...,
ruff format .). Go's make lint skips silently when golangci-lint is absent.
- Stdio variants must never write to stdout except JSON-RPC frames. All
logging goes to stderr via
tracing(JSON format). Adding aprintln!to a stdio variant breaks the protocol. - Tool names are variant-specific and load-bearing for clients:
local_system_infoanddisk_usagein the stdio variants,iap_system_infoiniap/,sysutils_manual_rust/sysutils_bearer_rust/sysutils_proxy_rustplusdisk_usageandlist_processesin their respective HTTP variants. Renaming a tool is a breaking change to any.mcp.jsonthat registers it. - Tests live inline in
#[cfg(test)] mod testsat the bottom ofsrc/main.rs(Rust),main_test.go(Go), andtests/(Python). - When you change one variant's behavior, check whether the sibling variants in the other two languages should match — but only change them if asked.
source ./set_env.shexportsPROJECT_ID,PROJECT_NUMBER,REGION,ID_TOKEN,SHORT_SHA,RUST_LOG. It reads the project ID from~/project_id.txtand requires an authenticatedgcloud. It must be sourced, not executed../init.shis first-time setup: writes~/project_id.txt, enables APIs, sets up ADC.set_key.sh/set_adc.shhandle API key and ADC credential setup.- API-key variants look up a key literally named "MCP API Key" in the project,
via
google-apikeys2(ADC) or thegcloud services api-keysCLI.MCP_API_KEYoverrides the lookup. - Deploys go through
cloudbuild.yamlin each variant → Cloud Run. Service names differ per variant (e.g.sysutils-manual-rust,bearer-rust,proxy-python); check the variant'sMakefile.
The root .gitignore excludes .mcp.json (any depth), .env, and *.key.
.mcp.json files are per-developer local files that may carry injected keys —
never commit one, and never print the contents of a key file into the transcript
or into a doc.
The stdio variants are usable directly as MCP servers. From the variant directory:
cd stdio
make release
claude # approve the project-scoped server onceVerify with /mcp inside Claude Code, or claude mcp list /
claude mcp get sysutils-stdio-rust from the shell.
docs/ holds long-form article drafts about MCP development in this repo
(Rust + Claude Code, Rust + Gemini CLI, the rmcp 3 upgrade). They are drafts with
YAML frontmatter — treat them as prose to edit carefully, not as generated output.
Cover images live in images/.
GEMINI.md files (root and per-variant) are the Gemini CLI equivalents of this
file. When you materially change project structure, update GEMINI.md,
AGENTS.md, and README.md alongside this file so the three agent guides do not
drift apart.