mcp-fleet-worker
by alexgenovese
README.md
# @alexgenovese/mcp-fleet-worker
> **Spawn headless OpenCode workers on cheap models** — delegate expensive tool-using tasks to a fleet of parallel workers with isolated git worktrees. Optional **Brick routing** selects the optimal model per task automatically.
[](LICENSE)
[](package.json)
[](#)
[](#)
[](https://github.com/regolo-ai/brick-SR1)
---
## MCP Activation Keywords
Le seguenti keyword attivano questo MCP in Claude Code / OpenCode:
| Keyword | Azione |
|---|---|
| `fleet-worker` | Attivazione generica |
| `delegate to GLM` | Usa `regolo/glm5.2-beta` come worker |
| `spawn a GLM worker` | Idem |
| `cheap parallel agent` | Spawn worker su modello economico |
| `grunt worker` | Worker per task ripetitivi |
| `offload to glm` | Delega task a GLM |
| `z.ai worker` | Worker su endpoint z.ai |
| `GLM-5.2 worker` | Worker su glm5.2 |
| `sonnet worker` | Worker Sonnet |
| `haiku worker` | Worker Haiku |
| `cheap coding agent` | Worker economico generico |
| `fan out workers` | Spawn multipli in parallelo |
| `non-Anthropic model in OpenCode` | Worker su modello non-Anthropic |
| `ANTHROPIC_BASE_URL worker` | Worker su endpoint custom |
| `fleet-worker list models` | `fleet_worker_list_models` |
| `fleet-worker spawn` | `fleet_worker_spawn` |
| `fleet-worker collect` | `fleet_worker_collect` |
| `fleet-worker status` | `fleet_worker_status` |
| `fleet-worker cancel` | `fleet_worker_cancel` |
Aggiungi al tuo `.claude/hooks/PreToolUse` o usa direttamente i tool MCP via Claude Code.
---
## What Is This?
`mcp-fleet-worker` is an [MCP server](https://modelcontextprotocol.io) that lets you **spawn headless OpenCode workers** on any model configured in your `opencode.json` — from local Ollama models to cheap remote providers like GLM via z.ai.
Each worker runs in an **isolated git worktree** with its own `CLAUDE_CONFIG_DIR`, so multiple workers run side-by-side without conflicting. Workers are treated as disposable "grunt agents": a powerful orchestrator (Opus) fans out tasks, collects results, and lands the completed branches.
### Why?
- **Cost optimization**: run cheap models (GLM-5.2, Haiku, Sonnet) for routine coding tasks, reserve Opus for orchestration
- **Parallel execution**: spawn N workers simultaneously, each in its own worktree
- **Isolation**: each worker gets a fresh git branch + scratch directory
- **Fleet-ops ready**: designed to pair with [fleet-ops](https://opencode.ai) for test-gated landing
---
## Technology Stack
| Technology | Version | Purpose |
|---|---|---|
| **Node.js** | >= 18 | Runtime |
| **TypeScript** | 5.3 | Language |
| **@modelcontextprotocol/sdk** | ^1.0.0 | MCP server framework |
| **zod** | ^3.23.0 | Runtime schema validation |
| **git worktree** | system | Worker isolation |
| **OpenCode** | any | Spawned agent process |
| **Brick** (optional) | SR1 | Smart model routing via Regolo API |
---
## Architecture
```
┌─────────────────────────────────┐
│ Claude Code (Opus) │
│ (orchestrator / caller) │
└──────────┬──────────────────────┘
│ MCP (stdio)
┌──────────▼──────────────────────┐
│ mcp-fleet-worker server │
│ │
│ ┌─ fleet_worker_spawn │
│ ├─ fleet_worker_collect │
│ ├─ fleet_worker_status │
│ ├─ fleet_worker_list_models │
│ └─ fleet_worker_cancel │
└──────────┬──────────────────────┘
│
┌──────────▼──────────────────────┐
│ Git Worktree (.fleet-work/) │
│ │
│ worker-1/ ← branch `fleet/id1` │
│ worker-2/ ← branch `fleet/id2` │
│ ... │
└──────────┬──────────────────────┘
│
┌──────────▼──────────────────────┐
│ ~/.fleet-worker/scratch/<id>/ │
│ (CLAUDE_CONFIG_DIR per worker) │
└─────────────────────────────────┘
```
### Flow
1. **Caller** sends a prompt + optional model to `fleet_worker_spawn`
2. **Server** creates an isolated git worktree (`.fleet-work/<id>/`) with a dedicated branch (`fleet/<id>`)
3. **Server** spawns `opencode run -m <model> --agent coder --auto --dir <worktree> --format json "<prompt>"`
4. **Caller** polls `fleet_worker_collect` or waits for completion
5. **Worker** finishes → output is captured → `fleet_worker_cancel` cleans up worktree + scratch dir
---
## Getting Started
### Prerequisites
- Node.js >= 18
- npm or pnpm
- [OpenCode](https://opencode.ai) installed (the `opencode` CLI in PATH)
- A git repository to use as the worker base directory
### Installation
```bash
# Clone
git clone https://github.com/alexgenovese/mcp-fleet-worker.git
cd mcp-fleet-worker
# Install deps
npm install
# Build
npm run build
# Test
node dist/index.js
```
### Configuration
Add to your `opencode.json` (or to your MCP hub config):
```json
{
"mcpServers": {
"mcp-fleet-worker": {
"command": "node",
"args": ["/path/to/mcp-fleet-worker/dist/index.js"],
"env": {
"FLEET_WORKER_BASE_DIR": "/path/to/your/git/repo",
"FLEET_WORKER_DEFAULT_MODEL": "regolo/glm5.2-beta",
"FLEET_WORKER_BRICK_URL": "https://api.regolo.ai",
"FLEET_WORKER_BRICK_API_KEY": "your-regolo-api-key",
"OPENCODE_PATH": "opencode"
}
}
}
}
```
**Environment Variables:**
| Variable | Default | Description |
|---|---|---|
| `FLEET_WORKER_BASE_DIR` | `process.cwd()` | Git repo for worktree isolation |
| `FLEET_WORKER_DEFAULT_MODEL` | `regolo/gemma4-31b` | Fallback model when routing is off/unavailable |
| `FLEET_WORKER_BRICK_URL` | *(empty)* | Brick API URL (Regolo). When set, enables smart routing |
| `FLEET_WORKER_BRICK_API_KEY` | *(empty)* | API key for Brick (Regolo API key) |
| `OPENCODE_PATH` | `opencode` | Path to opencode binary |
| `XDG_CONFIG_HOME` | *unset for worker* | Stripped so worker uses fresh config |
---
## Brick Smart Routing (Optional)
When `FLEET_WORKER_BRICK_URL` and `FLEET_WORKER_BRICK_API_KEY` are set, `fleet_worker_spawn` **without an explicit `model` parameter** will call Brick's `/v1/routing/test` endpoint to select the optimal model based on:
- **Capability** — 6 dimensions (coding, math_reasoning, creative_synthesis, instruction_following, planning_agentic, world_knowledge)
- **Complexity** — easy / medium / hard
- **Cost** — penalizes expensive models for simple tasks
### How It Works
```
fleet_worker_spawn(prompt="fix typo in README.md")
↓
Brick analyzes prompt → complexity: easy, capability: {instruction_following: 0.9}
↓
Brick selects: ollama/qwen3:4b (cheapest capable model)
↓
Worker spawns on ollama/qwen3:4b
↓
fleet_worker_status shows: routed=true, costSavings=95%
```
### When Routing Kicks In
| Call | Behavior |
|---|---|
| `fleet_worker_spawn(prompt="...", model="regolo/glm5.2-beta")` | Explicit model → **no routing**, use specified model |
| `fleet_worker_spawn(prompt="...")` + Brick configured | **Brick routes** automatically |
| `fleet_worker_spawn(prompt="...")` + Brick not configured | Falls back to `FLEET_WORKER_DEFAULT_MODEL` |
### Cost Savings Tracking
Every routed worker records its `costSavings` percentage (estimated vs. using the fallback model). This appears in:
- `fleet_worker_spawn` response (`routing.costSavings`)
- `fleet_worker_status` output (per-worker `costSavings`)
- `fleet_worker_collect` result (`routing.costSavings`)
See [USE_CASES.md](USE_CASES.md) for detailed cost-saving scenarios for developers and CTOs.
---
## Project Structure
```
mcp-fleet-worker/
├── src/
│ ├── index.ts # MCP server entry point
│ ├── types.ts # WorkerSpec, WorkerProcess, WorkerStatus
│ ├── lib/
│ │ ├── models.ts # opencode.json parser (JSONC-aware)
│ │ ├── router.ts # Brick routing client (Regolo API)
│ │ ├── worktree.ts # Git worktree create/remove/cleanup
│ │ ├── config.ts # Scratch directory (~/.fleet-worker/)
│ │ ├── id.ts # Short UUID generator (8 chars)
│ │ └── worker-manager.ts # Spawn/track/kill opencode children
│ └── tools/
│ └── register.ts # 5 MCP tool handlers
├── dist/ # Compiled JavaScript
├── package.json
├── tsconfig.json
└── README.md
```
---
## Key Features
### 1. Multi-Model Support
Reads all providers and models from `opencode.json` — Ollama, GLM, custom OpenAI-compatible endpoints. Use `fleet_worker_list_models` to see what's available.
### 2. Git Worktree Isolation
Each worker runs in a dedicated git worktree (`git worktree add -b fleet/<id>`), so multiple workers can modify the same repo simultaneously without merge conflicts at runtime.
### 3. Background Execution
Workers spawn as child processes with captured stdout/stderr. Collect results async via `fleet_worker_collect`.
### 4. Cleanup
`fleet_worker_cancel` with `cleanup: true` removes:
- The worktree directory (`.fleet-work/<id>/`)
- The local git branch (`fleet/<id>`)
- The scratch config dir (`~/.fleet-worker/scratch/<id>/`)
### 5. JSONC Parsing
Reads `opencode.json` even with comments (`//` and `/* */`) — no need to strip them manually.
---
## MCP Tools
### `fleet_worker_list_models`
List all available models grouped by provider, with context window and cost info.
### `fleet_worker_spawn`
Spawn a headless worker on any model.
| Parameter | Type | Default | Description |
|---|---|---|---|
| `prompt` | string | *required* | Task prompt for the worker |
| `model` | string | env/FALLBACK | `provider/model-id` format |
| `agent` | string | `coder` | OpenCode agent type |
| `worktree` | string | `FLEET_WORKER_BASE_DIR` | Git repo path |
| `branch` | string | `fleet/<id>` | Git branch name |
| `maxTurns` | number | 50 | Max interaction turns |
| `timeout` | number | 300 | Timeout in seconds |
### `fleet_worker_collect`
Get a worker's result.
| Parameter | Type | Default | Description |
|---|---|---|---|
| `workerId` | string | *required* | Worker ID from spawn |
| `wait` | boolean | false | Block until completion |
| `timeout` | number | 30 | Max wait in seconds |
### `fleet_worker_status`
List all workers with status, model, branch, elapsed time.
### `fleet_worker_cancel`
Stop and clean up a worker.
| Parameter | Type | Default | Description |
|---|---|---|---|
| `workerId` | string | *required* | Worker ID to cancel |
| `cleanup` | boolean | true | Remove worktree + scratch |
---
## Development Workflow
1. **Install** → `npm install`
2. **Build** → `npm run build`
3. **Watch** → `npm run dev` (tsc --watch)
4. **Test locally** → `node dist/index.js` (then connect with MCP inspector or [Claude Desktop](https://claude.ai/download))
To test with the MCP inspector:
```bash
npx @modelcontextprotocol/inspector node dist/index.js
```
---
## Testing
```bash
# Type check
npx tsc --noEmit
# Build
npm run build
# Quick smoke test (list models)
node -e "
import('./dist/index.js').then(() => console.log('Server loads OK'))
"
```
---
## License
MIT © [Alex Geno](https://github.com/alexgenovese)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing