{"id":"52fbc3c7-342c-42a0-b079-a94247743ef7","slug":"toolrush-mcp","kind":"mcp","name":"toolrush-mcp","summary":"Kill the tool-call tax in any MCP agent harness: fast read/search, warm persistent shell, batched calls. Go port of OnlyTerp/toolrush.","owner":"dhava-gautama","repoUrl":"https://github.com/dhava-gautama/toolrush-mcp","license":"MIT","licenseTier":"permissive","trust":"community","stars":1,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-09-06T17:03:27.000Z","addedAt":"2026-10-21T05:06:03.256Z","logoUrl":"https://avatars.githubusercontent.com/u/62224294?u=848ffae1b77af235f13c80e196da2bd0db60e833&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["search","developer-tools","cloud-infra"],"tags":["agent","claude-code","codex","developer-tools","go","shell"],"runtime":"go","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-21T05:35:12.845Z","sample":false,"url":"https://conduits.dev/tools/toolrush-mcp","language":"Python","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# ToolRush-MCP\n\n[![ci](https://github.com/dhava-gautama/toolrush-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/dhava-gautama/toolrush-mcp/actions/workflows/ci.yml)\n[![Release](https://img.shields.io/github/v/release/dhava-gautama/toolrush-mcp)](https://github.com/dhava-gautama/toolrush-mcp/releases/latest)\n[![Go Report Card](https://goreportcard.com/badge/github.com/dhava-gautama/toolrush-mcp)](https://goreportcard.com/report/github.com/dhava-gautama/toolrush-mcp)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\n**Kill the tool-call tax — in any agent harness.** A fast local tool server\nfor [Kimi Code CLI](https://www.kimi.com/code), [Codex CLI](https://github.com/openai/codex),\n[Claude Code](https://docs.anthropic.com/en/docs/claude-code), and anything\nelse that speaks the Model Context Protocol.\n\nA universal port of [ToolRush](https://github.com/OnlyTerp/toolrush) (a\nHermes Agent plugin, Windows/MSYS-only) — same lanes, same fail-closed\nphilosophy, shipped as one static Go binary instead of harness-specific\nmonkeypatching.\n\n## What you get\n\n| Tool | What it does |\n|---|---|\n| `fast_read` | In-process file read: line-number gutter, offset/limit paging, negative offset = tail, binary sniff, BOM strip, >64MB files stream the window. Line-level mtime cache — page turns are cache hits |\n| `batch_read` | 1–16 reads through **one** tool call, input order, whole-batch validated before anything runs (serial by design — measured faster than pooling on page-cache-fast storage) |\n| `fast_search` | Direct `rg` transport — real `.gitignore`, real regex grammar. Pure-Go walk fallback when rg is absent. `context=N` (0–5) adds N lines of gutter around each hit: `L-line` before, `L+line` after. Output stops at 8MB of rg output — `capped:true` means `total_hits` is a lower bound |\n| `batch_search` | 1–16 searches through **one** call, fanned out across goroutines — each op spawns its own rg process, so the batch wall time approaches the slowest op, not the sum. Input order, whole-batch validated, per-op failures isolated |\n| `fast_tree` | Budgeted directory listing: deterministic dirs-first alphabetical order, depth (1–10) and entry (1–5000) budgets, basename pattern filter (invalid patterns error rather than matching nothing). Skips `.git`, `node_modules`, `__pycache__`, `.venv`, `target`, `dist`, `build`, `*_cache`. Entries carry `is_symlink` (lstat semantics, dangling links included). No `.gitignore` parsing — use `pattern=` to narrow |\n| `warm_exec` | **One persistent bash**: `cd`, `export`, and shell state survive across calls (harness terminals spawn fresh shells per call). Per-call framing, rc + cwd read back from the shell, process-group kill on timeout, never retries a submitted command |\n| `batch_exec` | 1–16 shell commands through **one** call on the warm shell, sequentially, state flowing between them |\n| `doctor` | Lane status, versions, kill-switch state, counters |\n\nWhy it matters: every MCP tool call pays a fixed transport + dispatch cost.\nThe structural wins are **persistent shell state** (impossible with per-call\nspawns) and **batching** (one round trip instead of sixteen) — plus the\nserver itself is fast enough to never be the bottleneck.\n\n## Measured performance\n\nFrom `bench/bench_go.py` (Linux, i7-8750H, medians; your numbers will vary):\n\n| Metric | Python impl | Go impl | C ping ref |\n|---|---:|---:|---:|\n| startup → first reply | 60.3 ms | **2.5 ms** | 0.9 ms |\n| ping round trip | 0.034 ms | 0.035 ms | 0.019 ms |\n| cold `batch_read`, 16×1000-line files | 31.3 ms | 22.9 ms | — |\n| `fast_read` **during** a 2s `warm_exec` | 2002.4 ms | **0.37 ms** | — |\n| 6 searches: `batch_search` (1 call) vs 6× `fast_search` | 2899.9 ms | **2574.6 ms** vs 2714.3 ms | — |\n\nThe last row is 6 full-tree `rg` scans over `/usr/share/doc` (424 MB, median\nof 10, this i7-8750H + HDD box). The Go server fans the ops out across\ngoroutines but wins only ~1.05x here: the scans are disk-bound, and six\nconcurrent rg processes saturate the same spindle (raw concurrent rg outside\nthe server measures the same 1.05x). On page-cache-hot trees or\nCPU-bound regexes the parallelism shows up for real; on cold HDD scans,\nhonestly, it mostly saves the five extra RPC round trips. The Python\nreference runs its ops sequentially (GIL + subprocess dispatch overhead)\nand, as expected, ties its own 6-call loop.\n\nThe `fast_read`-during-`warm_exec` row is the architectural one: per-request goroutines mean a long\nshell command never head-of-line blocks the other tools. Per-call latency is\nkernel/transport-bound and deliberately ties — there is nothing left to win\nthere in any language.\n\n## Install\n\n**Go (recommended):**\n\n```\ngo install github.com/dhava-gautama/toolrush-mcp@latest\n# binary lands in $(go env GOPATH)/bin/toolrush-mcp\n```\n\n**From source:**\n\n```\ngit clone https://github.com/dhava-gautama/toolrush-mcp.git\ncd toolrush-mcp\nCGO_ENABLED=0 go build -trimpath -ldflags=\"-s -w\" -o toolrush-go .\n```\n\nRequirements: `bash`; `rg` on PATH is optional (the search lane falls back\nto a built-in walker without it). POSIX only (Linux/macOS).\n\n## Register with your harness\n\nUse the binary path from the install step above (`$HOME/go/bin/toolrush-mcp`\nfor `go install`, `./toolrush-go` for source builds).\n\n**Kimi Code CLI** — `~/.kimi-code/mcp.json` (new sessions pick it up; `/mcp` to verify):\n\n```json\n{\n  \"mcpServers\": {\n    \"toolrush\": {\n      \"command\": \"/home/YOU/go/bin/toolrush-mcp\",\n      \"args\": [],\n      \"toolTimeoutMs\": 120000\n    }\n  }\n}\n```\n\n**Codex CLI:**\n\n```\ncodex mcp add toolrush -- /home/YOU/go/bin/toolrush-mcp\n```\n\n**Claude Code:**\n\n```\nclaude mcp add toolrush -s user -- /home/YOU/go/bin/toolrush-mcp\n```\n\n**Any other MCP harness:** stdio server, command = the binary, no args.\nNewline-delimited JSON-RPC: `initialize` / `tools/list` / `tools/call` /\n`ping`.\n\n## Kill-switches (fail-closed)\n\nSet any of these to `0` in the server's environment to disable a lane — a\ndisabled lane errors clearly so the agent falls back to its native tools\n(`TOOLRUSH_PERSIST=0` runs spawn-per-call instead, as a negative control):\n\n```\nTOOLRUSH_FASTLANE=0  TOOLRUSH_SEARCH=0  TOOLRUSH_PERSIST=0  TOOLRUSH_PARALLEL=0\n```\n\n## Safety model\n\nRead/search lanes are read-only. There is deliberately **no write tool** —\nwrites belong behind your harness's own permission UI. `warm_exec` carries\nthe same privileges as the harness's terminal tool; gate it with your\nharness's MCP approval rules. No network access, no persistence, stdout\ncarries protocol frames only (diagnostics on stderr).\n\n## Verify / develop\n\n```\npython3 python/smoke.py                                   # 53 checks vs Python impl\nTOOLRUSH_SERVER=./toolrush-go python3 python/smoke.py     # same 53 vs Go binary\npython3 bench/bench_go.py                                 # Python vs Go vs C shootout\ngcc -O2 -o bench/ping_ref bench/ping_ref.c                # C floor reference\npython3 bench/bench_lang.py                               # transport floor\n```\n\n## Layout\n\n| Path | What |\n|---|---|\n| `main.go` | the Go server (the shipped implementation) |\n| `python/` | Python reference implementation (`toolrush_mcp.py`), the smoke suite, lane bench |\n| `bench/` | cross-language benchmarks + pure-C transport-floor reference |\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md).\n\n## Known limitations\n\nHonest footguns, so you learn them here instead of in a lost hour:\n\n- `warm_exec`: a command with an unclosed quote hangs until the call\n  timeout, then the shell is destroyed and respawned (state lost). Quote\n  carefully.\n- `warm_exec`: background jobs that outlive their command (e.g.\n  `sleep 99 &`) keep writing into whichever call is in flight — output\n  attribution is best-effort. Processes that call `setsid` escape the\n  timeout kill (same as any terminal).\n- Concurrent `warm_exec` calls from a pipelining client have no\n  execution-order guarantee — use `batch_exec` for ordered sequences.\n- A background child holding the shell's output pipe delays death\n  detection until the timeout.\n- Output caps: `fast_search`/`batch_search` stop at 8MB of rg output (see\n  `capped`); `warm_exec` caps at 8MB (`truncated`).\n- `fast_tree` doesn't parse `.gitignore` (the skip list covers the common\n  cases).\n- POSIX only; Windows untested.\n\n## Origin and license\n\nPort of [ToolRush](https://github.com/OnlyTerp/toolrush) by OnlyTerp —\nthe Hermes-side design, kill-switch discipline, and \"measured evidence or it\ndidn't happen\" methodology are theirs; the MCP universalization and Go\nimplementation are here. Dropped in the port: Hermes byte-parity quirks and\nthe update-survival machinery (no upstream harness to survive here).\nMIT — see [LICENSE](LICENSE).\n"}