claude-delegate-local-mcp
README.md
<!-- BUDGET: 182
Raised from 172 on 2026-09-08: a third entry point, `provision`, and the one-paragraph
answer to "do I need it" -- which is no, for every delegation that only reads.
Raised from 165 on 2026-09-08: `--init` replaces the two `cp` lines in the quickstart
and needs three saying what it does and does not decide for you. Cut from four first.
Raised from 160 on 2026-09-07: a new entry point, `--doctor`, and the reason to run
it. The prose was cut to two lines first. -->
# claude-delegate-local-mcp
An MCP server that lets Claude Code hand work to a local model you host yourself.
Bulk, mechanical, read-heavy work — reading a subsystem, writing tests, mechanical
refactors, first-pass review — costs cloud tokens even when the reasoning required is
modest. This moves that class of work onto your own hardware, where it is effectively
free, and keeps Claude for the parts that need it.
See [PLAN.md](PLAN.md) for what is open, and
[archive/PLAN-milestones.md](archive/PLAN-milestones.md) for the roadmap that closed.
## How it works
Two shapes of delegation, and the second is the interesting one:
- **One-shot** — the server reads the files you name and answers from them in a single
prompt, so their contents never reach your context. Good for review, summary and
explanation. `delegate_readonly()` is this shape guaranteed rather than chosen, which is
what lets a caller run it where a write would not be allowed.
- **Agentic** — the local model gets its own tools and iterates: write, run the tests,
read the real failure, try again, at no cloud token cost, then hand back a result for
Claude to review.
That second loop is why a shell exists, why it is confined by
[bubblewrap](https://github.com/containers/bubblewrap), what happens when bubblewrap is
absent, and why the server watches process exit codes rather than the model's account of
them.
How each of those works is [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) and
[docs/DISPATCH.md](docs/DISPATCH.md); this file names them and links, and deliberately
does not restate them.
## What it is not
- Not a cloud router. One backend format ships — OpenAI-compatible. Anthropic-compatible
endpoints are a planned addition behind an existing seam, not a current feature.
- Not a way to run Claude Code against a different model. It delegates *tasks*; Claude
Code stays Claude Code.
- Not a sandbox for untrusted code. It confines a model you chose to run against a
workspace you chose to expose.
## Requirements
- A local OpenAI-compatible endpoint (this was built against vLLM serving DeepSeek V4
Flash on two DGX-Spark-class machines, but nothing depends on that specific stack).
- Python 3.11+.
- **Linux, or WSL2 on Windows** — `bubblewrap` is Linux-only, so the server runs there even
when Claude Code does not ([why](docs/ARCHITECTURE.md)).
## Install
```bash
git clone https://github.com/ComputerSaysNull/claude-delegate-local-mcp
cd claude-delegate-local-mcp
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
python scripts/install_hooks.py # optional, gives the gate at commit time
claude-delegate-local-mcp --init # writes .env and models.toml from answers
claude-delegate-local-mcp --doctor # checks the environment; non-zero on any failure
claude-delegate-local-mcp provision . # optional, so a delegation can run this project's tests
```
`--init` asks what has no safe default, shows the default for everything else it offers,
never overwrites what is already there ([what it does with it](docs/ARCHITECTURE.md)), and
prints the registration block below filled in for this machine. Copying the two `.example`
files by hand still works.
Run the doctor before the first delegation. The server starts whether or not what it needs
is there, so a missing root or an unreachable endpoint otherwise surfaces much later, inside
whichever delegation happens to reach it ([why](docs/ARCHITECTURE.md)).
`provision` is needed only for `run_bash` to run a Python project's tests. It builds a
virtualenv outside the workspace — [why there, and what keeps it in
step](docs/ARCHITECTURE.md). Reading, writing and reviewing files need none of it.
On Windows plus WSL2 the two interpreters cannot share `.venv`: a Linux `python -m venv
.venv` overwrites a Windows one in place, and it reads as a corrupted install rather than a
collision. Put the WSL one elsewhere, on the native filesystem rather than `/mnt/c` where
creating it is ~27x slower (ADR-0020) — `python3 -m venv ~/.venvs/delegate`, then
`~/.venvs/delegate/bin/pip install -e /mnt/c/path/to/the/repo`. That is the runtime
only; [CONTRIBUTING.md](CONTRIBUTING.md) adds `[dev]` to the same venv for tests.
`.env` is read by `config.load()` as a fallback: anything already set in the environment
wins, so an explicit override still works. Point `DELEGATE_ENV_FILE` at another file to use
one elsewhere — if it names a file that does not exist, that is an error rather than a
silent fall back to defaults. ADR-0027 for why the server reads the file itself instead of
taking an `env` key from your MCP client's configuration.
`.env` and `models.toml` are gitignored, deliberately — [MODELS.md](docs/MODELS.md) says
why.
### On Windows, with the server in WSL2
```powershell
wsl --install -d Ubuntu-24.04
```
Then inside Ubuntu — and verify rather than assume, because two of these fail silently:
```bash
sudo apt install -y bubblewrap python3 python3-venv git
bwrap --unshare-all --ro-bind /usr /usr --ro-bind /etc /etc --proc /proc \
--dev /dev --tmpfs /tmp --symlink usr/bin /bin --symlink usr/lib /lib \
--symlink usr/lib64 /lib64 -- /bin/echo ok # must print: ok
getent hosts YOUR-HEAD-NODE # must resolve in WSL, not just Windows
```
The `usr/lib64` symlink is not optional on x86-64: without it nothing dynamically linked
runs, and the error blames the executable rather than the missing loader.
## Register with Claude Code
Native Linux:
```json
{ "mcpServers": { "delegate-local": {
"command": "claude-delegate-local-mcp",
"timeout": 900000
} } }
```
Windows, server in WSL2:
```json
{ "mcpServers": { "delegate-local": {
"command": "wsl.exe",
"args": ["-d", "Ubuntu-24.04",
"--cd", "C:\path\to\claude-delegate-local-mcp",
"-e", "/home/YOU/.venvs/delegate/bin/claude-delegate-local-mcp"],
"timeout": 900000
} } }
```
`--cd` and the script's absolute path are both load-bearing: without them the server starts
in the wrong directory or is not found at all, and neither failure names its own cause —
[TROUBLESHOOTING](docs/TROUBLESHOOTING.md#startup) has both symptoms. Give `--cd` the
Windows form of the path; `/mnt/c/...` is rejected.
`timeout` is milliseconds and the wall-clock default is generous. The per-turn progress
notification holds off the separate stdio *idle* timeout but does not extend the wall clock.
## Documentation
| | |
|---|---|
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | How the pieces fit, and why |
| [docs/DISPATCH.md](docs/DISPATCH.md) | What is sent to a model, and what comes back |
| [docs/CONFIGURATION.md](docs/CONFIGURATION.md) | Every setting *(generated)* |
| [docs/MODELS.md](docs/MODELS.md) | The registry, and adding a model |
| [docs/AGENTS.md](docs/AGENTS.md) | Agent files, and the path policy |
| [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) | Symptom to cause to fix |
| [DECISIONS.md](DECISIONS.md) | Numbered decisions, newest first |
| [JOURNAL.md](JOURNAL.md) | What took real work to figure out |
| [CONTRIBUTING.md](CONTRIBUTING.md) | Setup and conventions |
No configuration default is stated anywhere but `src/claude_delegate_local/config.py`,
which is where they live; `docs/CONFIGURATION.md` is generated from it and is a rendering,
never a source to edit. If you find one repeated elsewhere, that is a
bug — [CLAUDE.md](CLAUDE.md) explains the scheme.
## Provenance and licence
MIT. A derivative work, not an independent implementation: substantial code was ported
from [fegone/claude-code-delegate-local](https://github.com/fegone/claude-code-delegate-local)
and its [mixicz](https://github.com/mixicz/claude-code-delegate-local) fork, both MIT. The
server-side context-prefetch idea comes from
[fjgbue/claude-delegator-deepseek-mcp](https://github.com/fjgbue/claude-delegator-deepseek-mcp).
[NOTICE](NOTICE) records what came from where, feature by feature.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessUnresponsive