# adequate-rust-mcp Industrial-grade, self-healing MCP server for `rust-analyzer`. ## Dependency Note This workspace currently consumes `libmcp` from the public swarm Git surface: - `https://git.swarm.moe/libmcp.git` Cargo will fetch that dependency automatically on first build. ## Crates - `ra-mcp-domain`: strict domain types and lifecycle algebra - `ra-mcp-engine`: resilient rust-analyzer transport + supervisor - `adequate-rust-mcp`: MCP stdio server exposing analysis tools ## Guarantees - automatic recovery from broken pipes and dead workers - bounded request/startup deadlines - typed boundaries for lifecycle, faults, and source positions - fault-injection integration tests for restart behavior ## Runtime Modes - default (`adequate-rust-mcp`): stable host process (Codex-facing stdio endpoint) - worker (`adequate-rust-mcp --worker`): actual MCP tool server process The host supervises worker generations, drains pending requests with explicit JSON-RPC errors on worker loss, and automatically respawns. ## Quick Start From the workspace root: ```bash cargo run -p adequate-rust-mcp ``` To launch the disposable worker directly: ```bash cargo run -p adequate-rust-mcp -- --worker ``` ## Live Reload Host mode watches the worker binary path for updates. On Unix it self-reexecs into the new binary and restores live session state before spawning the next worker generation; on other platforms it falls back to worker-only restart. It replays `initialize` and reconstructs `notifications/initialized` if needed so replacement workers come up fully live. In-flight requests are replayed across host/worker restarts with bounded at-least-once semantics, so transient rollout and recovery churn is hidden from clients by default. Environment knobs: - `ADEQUATE_MCP_WORKER_BINARY`: worker binary path to execute/watch (default: current executable) - `ADEQUATE_MCP_HOST_RELOAD_DEBOUNCE_MS`: file-change debounce before reload (default: `250`) - `ADEQUATE_MCP_HOST_RESPAWN_FLOOR_MS`: initial respawn backoff floor (default: `100`) - `ADEQUATE_MCP_HOST_RESPAWN_CEILING_MS`: respawn backoff ceiling (default: `3000`) - `ADEQUATE_MCP_HOST_QUEUE_CAPACITY`: max queued inbound frames while recovering (default: `512`) - `ADEQUATE_MCP_HOST_MAX_REPLAY_ATTEMPTS`: replay budget per in-flight request before surfacing an error (default: `8`) ## Tool Surface In addition to typed core tools (`hover`, `definition`, `references`, `rename_symbol`, `diagnostics`, `clippy_diagnostics`, `fix_everything`, `health_snapshot`, `telemetry_snapshot`), the server exposes `advanced_lsp_request` for editing-heavy and advanced rust-analyzer capabilities: - completions - completion/resolve - code actions + resolve - code lens + resolve - prepare rename - rename - execute command - formatting (document/range/on-type) - symbols + workspace symbol resolve - document links + resolve - colors + color presentation - linked editing range, inline value, moniker - document/workspace diagnostics - selection/folding/inlay hints + inlay resolve - semantic tokens (full/range/full-delta), call hierarchy, type hierarchy `hover`, `definition`, `references`, `health_snapshot`, and `telemetry_snapshot` also default to line-oriented porcelain text with `render=json` opt-in. `diagnostics` and `clippy_diagnostics` split detail from presentation: - `mode`: `compact` (default), `full`, or `summary` - `render`: `porcelain` (default line-oriented text) or `json` - default responses are model-friendly porcelain text in `content` - `render=json` exposes the structured payload and schema for programmatic consumers - empty `definition`/`references`/`hover` results may include an indexing note during early rust-analyzer warm-up when the empty result could be a false negative - transient early-startup `unlinked-file` / `not part of any crate` diagnostics are retried during the same warm-up window before surfacing to clients ## One-Stop Autofix `fix_everything` is the do-the-obvious thing button for agent loops. It runs, in order: - workspace formatter command (default: `cargo fmt --all`) - workspace clippy fix command (default: `cargo clippy --fix --workspace --all-targets --all-features --allow-dirty --allow-staged`) The output is structured and model-friendly: - `success`: whether all steps exited with status `0` - `workspace_root`: resolved workspace root path - `steps`: per-step command argv, exit code, and bounded stdout/stderr excerpts ## Input Normalization User-facing tool inputs are intentionally permissive and normalized at the boundary: - `file_path` accepts absolute paths, `file://` URIs, and relative paths (resolved against workspace root) - position indices accept numeric strings and integer-like floats - `0` indices are normalized to `1` for one-indexed fields - alias spellings are accepted for common fields (`filePath`, `lineNumber`, `character`, `newName`, etc.) - `advanced_lsp_request.method` accepts snake_case, camelCase, kebab-case, and full LSP method paths - `diagnostics.mode` accepts `compact` (default), `full` (aliases: `raw`, `verbose`), or `summary` - `diagnostics.render` accepts `porcelain` (default; aliases: `text`, `plain`, `plain_text`) or `json` (alias: `structured`) - `diagnostics.max_items` and `diagnostics.max_message_chars` accept numeric strings and integer-like floats - `diagnostics` and `clippy_diagnostics` accept either a single file (`file_path`) or many files (`file_paths`/`files`/`paths`) - `clippy_diagnostics` accepts the same render controls as `diagnostics` - multi-file diagnostics preserve requested file order and return one fused diagnostics list - `render=json` compact diagnostics use descriptive field names (`severity`, `file_path`, `start_line`, etc.) and descriptive counters (`error_count`, `total_count`, ...) ## Clippy Gate Integration `clippy_diagnostics` runs `cargo clippy` and filters results to the requested file. Strictness lives in workspace lint configuration: - `[workspace.lints.clippy]` in `Cargo.toml` is the canonical policy (`all` + `pedantic` with explicit carve-outs) - `./check.py` runs `cargo clippy` without inline lint flags, so commit-gate behavior is sourced from `Cargo.toml` The MCP worker executes: - `cargo clippy --workspace --all-targets --all-features --message-format=json` To override command shape (for example, alternate target selection), configure: ```toml [workspace.metadata.adequate-rust-mcp] format_command = ["cargo", "fmt", "--all"] clippy_command = [ "cargo", "clippy", "--workspace", "--all-targets", "--all-features", "--message-format=json", ] fix_command = [ "cargo", "clippy", "--fix", "--workspace", "--all-targets", "--all-features", "--allow-dirty", "--allow-staged", ] ``` ## Telemetry Use `telemetry_snapshot` as first-line triage when the system slows down or starts flapping. It reports: - lifecycle state + generation - uptime - consecutive failures and restart count - total request counters (success, response error, transport fault, retries) - per-method counters and latency aggregates (`last`, `avg`, `max`) - last observed method-level error text - latest restart-triggering fault Useful choke signatures: - rising `transport_fault_count` + `restart_count`: rust-analyzer process instability or I/O link failure - rising `response_error_count` with low restart count: semantic/query misuse or LSP-level request issues - high `avg_latency_ms`/`max_latency_ms` in one method: method-specific hot spot in large workspaces - non-zero `consecutive_failures` while state is `recovering`: active degradation loop ## Host JSONL Telemetry (XDG State) The host process also emits append-only JSONL telemetry for path-level heat/error analysis. - default path: `$XDG_STATE_HOME/adequate-rust-mcp/telemetry.jsonl` - fallback path: `$HOME/.local/state/adequate-rust-mcp/telemetry.jsonl` - snapshot cadence: `ADEQUATE_MCP_TELEMETRY_SNAPSHOT_EVERY` (default: `100`) Each tool call writes a `tool_call` event with: - `repo_root` - `request_id` - `tool_name` and optional `lsp_method` - `path_hint` (best-effort normalized path extraction) - `latency_ms`, `replay_attempts` - `outcome` (`ok`/`error`) - optional `error_code`, `error_kind`, `error_message` Every N calls, and once on shutdown, the host writes `hot_paths_snapshot` with: - `hottest_paths` (highest request volume) - `slowest_paths` (highest average latency) - `error_count` per path ## QA Checklist For a lean live MCP smoke pass against this repo, run: ```bash python3 qa_checklist.py ``` The literal step list lives in `docs/qa-checklist.md`.