Skip to content

Latest commit

 

History

History
153 lines (123 loc) · 7.05 KB

File metadata and controls

153 lines (123 loc) · 7.05 KB

CLAUDE.md

Guidance for Claude Code when working in this repository.

What this repo is

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.

Variant map

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.

Toolchains

  • Rust — edition 2024. Most variants pin rmcp 0.14; stdio/ is on rmcp 3.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.

rmcp 3.x gotchas (apply to stdio/, and to any variant you upgrade)

  • ServerInfo (InitializeResult) is #[non_exhaustive]. Build it with ServerInfo::new(capabilities) plus with_* helpers — a struct literal will not compile.
  • Bare #[tool_handler] defaults to router = Self::tool_router(), rebuilding the router on every tool call. Use #[tool_handler(router = self.tool_router)] to reuse the router cached in new().

See docs/upgrade-rmcp-3-and-claude-code.md for the full migration write-up.

Commands

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.

Conventions

  • Stdio variants must never write to stdout except JSON-RPC frames. All logging goes to stderr via tracing (JSON format). Adding a println! to a stdio variant breaks the protocol.
  • Tool names are variant-specific and load-bearing for clients: local_system_info and disk_usage in the stdio variants, iap_system_info in iap/, sysutils_manual_rust / sysutils_bearer_rust / sysutils_proxy_rust plus disk_usage and list_processes in their respective HTTP variants. Renaming a tool is a breaking change to any .mcp.json that registers it.
  • Tests live inline in #[cfg(test)] mod tests at the bottom of src/main.rs (Rust), main_test.go (Go), and tests/ (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.

Google Cloud

  • source ./set_env.sh exports PROJECT_ID, PROJECT_NUMBER, REGION, ID_TOKEN, SHORT_SHA, RUST_LOG. It reads the project ID from ~/project_id.txt and requires an authenticated gcloud. It must be sourced, not executed.
  • ./init.sh is first-time setup: writes ~/project_id.txt, enables APIs, sets up ADC.
  • set_key.sh / set_adc.sh handle 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 the gcloud services api-keys CLI. MCP_API_KEY overrides the lookup.
  • Deploys go through cloudbuild.yaml in each variant → Cloud Run. Service names differ per variant (e.g. sysutils-manual-rust, bearer-rust, proxy-python); check the variant's Makefile.

Secrets

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.

Registering a server with Claude Code

The stdio variants are usable directly as MCP servers. From the variant directory:

cd stdio
make release
claude          # approve the project-scoped server once

Verify with /mcp inside Claude Code, or claude mcp list / claude mcp get sysutils-stdio-rust from the shell.

Docs

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.