capy-fleet
# capy-fleet
An MCP server for [Capy](https://capy.ai). Lets Claude Code, Cursor, Codex, or any other MCP client delegate work to Capy's cloud agents and wait for the results without you leaving the editor.
Your local agent is smart, but there's only one of it. This gives it a workforce.
```
you: here are 8 bugs, farm them out
-> capy_delegate x8
-> capy_wait (all 8)
-> capy_diff on each
8 diffs come back, you review them in one place
```
Not affiliated with Capy. I built it because I wanted it.
## Install
Not on npm yet. For now, clone and build:
```bash
git clone https://github.com/Takumixbt/capy-fleet.git
cd capy-fleet
npm install
npm run build
```
You'll need an API token from [capy.ai/settings/tokens](https://capy.ai/settings/tokens). It starts with `capy_`.
### Claude Code
```bash
claude mcp add capy-fleet --env CAPY_API_KEY=capy_xxx -- node /absolute/path/to/capy-fleet/dist/index.js
```
### Cursor
`~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"capy-fleet": {
"command": "node",
"args": ["/absolute/path/to/capy-fleet/dist/index.js"],
"env": {
"CAPY_API_KEY": "capy_xxx",
"CAPY_PROJECT_ID": "proj_xxx"
}
}
}
}
```
Windsurf uses the same shape in `~/.codeium/windsurf/mcp_config.json`.
### Codex
`~/.codex/config.toml`:
```toml
[mcp_servers.capy-fleet]
command = "node"
args = ["/absolute/path/to/capy-fleet/dist/index.js"]
env = { CAPY_API_KEY = "capy_xxx", CAPY_PROJECT_ID = "proj_xxx" }
```
Setting `CAPY_PROJECT_ID` is optional but saves you passing a project id on every call. Run `capy_projects` once to find yours.
## Tools
| Tool | What it does |
| --- | --- |
| `capy_delegate` | Start an agent on a piece of work. Call it N times for N parallel agents. |
| `capy_wait` | Block until threads finish. Takes a list, so you can wait on the whole batch. |
| `capy_status` | One-shot check on a thread. |
| `capy_list` | See the whole fleet. Filter by status, tag, PR state, or free text. |
| `capy_diff` | Read the code an agent wrote. |
| `capy_messages` | Read the conversation, including the agent's own summary of what it did. |
| `capy_message` | Steer a running agent, or answer a question it asked. |
| `capy_open_pr` | Ask an agent to commit and open a PR. |
| `capy_stop` | Kill a thread that's going the wrong way. |
| `capy_projects` | List projects and their repos. |
| `capy_models` | List available models and which can act as Captain. |
| `capy_usage` | What your agents cost, split by LLM and VM, broken down by user and thread. |
## Things that will confuse you if nobody tells you
**Threads spawn tasks, and diffs belong to tasks.** You delegate to a thread and get back a thread id, but `capy_diff` wants a *task* id. Task ids show up in the thread's task list, which `capy_status` and `capy_wait` both print. This mirrors how Capy's API actually works rather than papering over it.
**There is no PR endpoint.** Capy's API can't open a pull request directly. `capy_open_pr` sends the agent a message asking it to do it, which means the PR shows up a bit after the call returns, not during it. Run `capy_wait` after and read the URL off the result.
**No streaming, no webhooks.** The API is poll-only, so `capy_wait` polls with backoff (3s, growing to 15s). It returns early if a thread gets blocked on an auth or permission gate, because sitting there waiting on something that needs a human is useless. If it times out, nothing is lost. The agents keep running on Capy's side and you just call `capy_wait` again with the same ids.
**Tasks are read-only over the API.** Older unofficial Capy wrappers used `POST /tasks` endpoints that no longer work. Everything here goes through threads, which is the supported path.
## Not burning your credits by accident
Delegating spends real money, and an LLM in a loop can delegate a lot.
- `CAPY_FLEET_MAX_DELEGATIONS` caps how many threads one server process will start. Defaults to 25. Set it to 0 if you really want it uncapped.
- `CAPY_FLEET_READONLY=1` registers only the read tools. Handy if you want an agent that can watch the fleet but not spend anything.
- `capy_diff` truncates to a byte budget instead of dumping a 40k-line patch into your context. Use `stats_only` first, then pull specific paths.
## Config reference
| Variable | Required | Default | |
| --- | --- | --- | --- |
| `CAPY_API_KEY` | yes | | Token from capy.ai/settings/tokens |
| `CAPY_PROJECT_ID` | no | | Default project, so you can skip `project_id` |
| `CAPY_BASE_URL` | no | `https://capy.ai/api` | Override the API host |
| `CAPY_FLEET_MAX_DELEGATIONS` | no | `25` | Per-process delegation cap, 0 for unlimited |
| `CAPY_FLEET_READONLY` | no | `0` | Set to 1 to hide the write tools |
## Development
```bash
npm run build # compile
npm run watch # compile on change
npm run smoke # start the server over stdio, check every tool registers
```
The smoke test uses a deliberately invalid token, so the only network call it makes is one that's supposed to come back 401. It's checking that the tools register and that errors come back readable, not that your account works.
Types in `src/types.ts` are transcribed from Capy's published OpenAPI document. If Capy ships changes, that's the file to update first.
## License
MIT
TDQS
Scored across 12 tools
Each tool has a distinct purpose with clear boundaries. For example, capy_status checks state one-shot while capy_wait blocks until completion, and capy_messages reads history while capy_message sends a message. No overlapping functionalities.
All tools follow the consistent pattern 'capy_<noun_or_verb>', all lowercase with underscores. The naming is predictable and well-structured.
12 tools cover the full range of operations for managing Capy fleet agents: delegation, monitoring, messaging, PR handling, cost tracking, and listing. The count feels well-scoped without being excessive or too thin.
The tool set covers the complete lifecycle: delegate (create), status/list/diff/messages (read), message (update), stop (delete), plus blocking wait and PR creation. No obvious gaps for the domain.