# MCP server
URL: /docs/alineod/mcp

Drive an alineod swarm from Claude Code, Claude Desktop, Cursor, or any MCP client with `npx alineo-mcp`.



`alineo-mcp` is an [MCP](https://modelcontextprotocol.io) server that exposes alineod's swarm-control API as
tools, so an AI client can create a run, fork agents, steer them, and collect their results without you writing
any HTTP calls.

```
MCP client ── stdio ──▶ alineo-mcp ── HTTP + SSE ──▶ alineod ──▶ OpenSandbox + Pi
(Claude Code, Cursor, …)  (npx, local process)         (daemon)
```

It is a small local process, not a hosted service. The client launches it over stdio, and it talks to an
alineod that you (or `init`) have running. It is published on npm as
[`alineo-mcp`](https://www.npmjs.com/package/alineo-mcp).

<Callout type="info" title="You still need alineod and Docker">
  `alineo-mcp` only translates tool calls into alineod requests. The agents run in OpenSandbox
  containers behind alineod, so Docker is required. The `init` tool starts both for you.
</Callout>

## Connect a client [#connect-a-client]

There is nothing to install. The client runs `npx -y alineo-mcp` on demand.

<Tabs items="[&#x22;Claude Code&#x22;, &#x22;Claude Desktop / Cursor&#x22;, &#x22;Bun&#x22;]">
  <Tab value="Claude Code">
    ```bash
    claude mcp add alineo -- npx -y alineo-mcp

    # only for the current project
    claude mcp add alineo --scope project -- npx -y alineo-mcp
    ```
  </Tab>

  <Tab value="Claude Desktop / Cursor">
    Add an entry under `mcpServers` in `claude_desktop_config.json`, `~/.cursor/mcp.json`, or your client's
    equivalent:

    ```json
    {
      "mcpServers": {
        "alineo": {
          "command": "npx",
          "args": ["-y", "alineo-mcp"]
        }
      }
    }
    ```
  </Tab>

  <Tab value="Bun">
    ```json
    {
      "mcpServers": {
        "alineo": {
          "command": "bunx",
          "args": ["alineo-mcp"]
        }
      }
    }
    ```
  </Tab>
</Tabs>

Restart the client and it will list 16 tools, named `{subject}_{verb}` — `run_start`, `agent_spawn`, `spec_add` and so on.

### Pass environment variables through the client [#pass-environment-variables-through-the-client]

Many clients start MCP servers with a limited environment rather than your shell's, so set anything
`alineo-mcp` needs in the config's `env` block:

```json
{
  "mcpServers": {
    "alineo": {
      "command": "npx",
      "args": ["-y", "alineo-mcp"],
      "env": {
        "ALINEOD_URL": "http://127.0.0.1:4600",
        "NVIDIA_API_KEY": "nvapi-..."
      }
    }
  }
}
```

For Claude Code: `claude mcp add alineo --env NVIDIA_API_KEY=nvapi-... -- npx -y alineo-mcp`.

## Start alineod [#start-alineod]

Every `run_*`, `agent_*` and `result_*` tool needs alineod reachable at `ALINEOD_URL` (default `http://127.0.0.1:4600`). Either:

* **Ask the client to call `init`.** It starts OpenSandbox and alineod in Docker, pulling images if
  needed, and writes `alineo.config.json` in the current directory if missing. It forwards any model provider
  key found in `alineo-mcp`'s own environment into the alineod container, which is why the key belongs in the
  `env` block above. This is the same setup as [`alineo init`](/docs/cli/commands/init).
* **Or run alineod yourself**, as described in the [Quickstart](/docs/alineod/quickstart) and
  [Deployment](/docs/alineod/deployment), and point `ALINEOD_URL` at it.

## Run a swarm from chat [#run-a-swarm-from-chat]

With the server connected and alineod up, you can describe the swarm and let the client drive the tools:

> Add the agent spec at `./agents/reviewer.json`, start a run with it, fork two child agents from the root,
> and give me each one's result.

Behind that, the client makes calls in roughly this order:

<Steps>
  <Step>
    ### Get a spec [#get-a-spec]

    `spec_add` fetches an [agent spec](/docs/agent/api-reference/alineo) from a URL or local path,
    validates it, and saves it to the local spec cache. `spec_list` shows what is already saved.
  </Step>

  <Step>
    ### Create the run [#create-the-run]

    `run_start` takes the spec, an optional first `prompt`, and an optional `budget` override. It returns
    a `runId` and `rootAgentId` immediately while the root agent is still `provisioning`; poll
    `run_get` for its real state.
  </Step>

  <Step>
    ### Fan out [#fan-out]

    `agent_spawn` forks a child from a live parent (`parentAgentId`). Pass `waitFor` to hold the spawn
    until other agents finish, and `idempotencyKey` so a retried call cannot create a duplicate. This is the same
    [fan-out/gather](/docs/alineod/concepts/fan-out-gather) model as the HTTP API.
  </Step>

  <Step>
    ### Drive and observe [#drive-and-observe]

    `agent_prompt` starts a turn and `agent_steer` redirects one in flight.
    `agent_pause` and `agent_resume` freeze and thaw a container. To observe, use
    `run_get` for the whole tree or `run_watch` for events.
  </Step>

  <Step>
    ### Collect and tear down [#collect-and-tear-down]

    `result_get` returns a settled agent's output. `agent_stop` stops one agent and
    `run_stop` aborts and closes every live agent in the run. The ledger is kept.
  </Step>
</Steps>

For a complete, runnable version of this flow, see the [MCP Agent Swarm](/docs/cookbooks/mcp-agent-swarm)
cookbook: a lead agent forks two reviewers, one is paused and the other steered, and an editor merges their
findings, all through these tools.

## Tools [#tools]

### Swarm control (need alineod) [#swarm-control-need-alineod]

| Tool           | alineod route                   | What it does                                                      |
| -------------- | ------------------------------- | ----------------------------------------------------------------- |
| `run_start`    | `POST /runs`                    | Load the root agent from a spec, optionally drive a first prompt. |
| `run_get`      | `GET /runs/:runId`              | The spawn tree: every agent with its parent and current state.    |
| `run_stop`     | `DELETE /runs/:runId`           | Abort and close every live agent in the run.                      |
| `run_watch`    | `GET /runs/:runId/events` (SSE) | Collect lifecycle and harness events for a bounded window.        |
| `agent_spawn`  | `POST /runs/:runId/agents`      | Fork a child under a live parent, optionally with `waitFor`.      |
| `agent_get`    | `GET /agents/:agentId`          | An agent's current view plus session stats.                       |
| `agent_prompt` | `POST /agents/:agentId/prompt`  | Drive one turn. Returns immediately.                              |
| `agent_steer`  | `POST /agents/:agentId/steer`   | Inject a message into the in-flight turn.                         |
| `agent_pause`  | `POST /agents/:agentId/pause`   | Freeze the agent's container.                                     |
| `agent_resume` | `POST /agents/:agentId/resume`  | Thaw a paused container.                                          |
| `agent_stop`   | `POST /agents/:agentId/stop`    | Abort and close one agent.                                        |
| `result_get`   | `GET /agents/:agentId/result`   | A settled agent's output. `waitSeconds` (max 240) long-polls.     |

### Setup and specs (work without alineod) [#setup-and-specs-work-without-alineod]

| Tool          | What it does                                                       |
| ------------- | ------------------------------------------------------------------ |
| `init`        | Start OpenSandbox and alineod locally in Docker.                   |
| `spec_add`    | Fetch a spec from a URL or file, validate it, and save it locally. |
| `spec_list`   | List saved specs.                                                  |
| `spec_remove` | Delete a saved spec by name.                                       |

<Callout type="info" title="Events are polled, not streamed">
  An MCP tool call is request/response, so `run_watch` collects events for a bounded window (20
  seconds by default, at most 120) and returns them. Pass the last event's `id` as `sinceEventId` on
  the next call to resume without missing anything.
</Callout>

### Not exposed through MCP yet [#not-exposed-through-mcp-yet]

The tools cover alineod's core routes, not everything the [HTTP API](/docs/alineod/api-reference/http-api) has
gained since. These are available over HTTP only:

* `scope: "subtree"` on pause, resume, and stop (and on steer), which act on an agent and all its
  descendants. The MCP tools act on the one agent you name. To end a whole swarm, use `run_stop`.
* `GET /agents/:agentId/transcript`
* The coordination routes: `await`, `notify-on`, and the inbox.

## Configuration [#configuration]

| Setting              | Where                                                       | Default                 | Affects                                   |
| -------------------- | ----------------------------------------------------------- | ----------------------- | ----------------------------------------- |
| `ALINEOD_URL`        | env var on the `alineo-mcp` process                         | `http://127.0.0.1:4600` | Every `run_*`/`agent_*`/`result_*` tool.  |
| `alineo.config.json` | project file, or `~/.config/alineo/config.json` as fallback | written by `init`       | Where `spec_add` and friends store specs. |
| Model provider key   | env var on the `alineo-mcp` process, e.g. `NVIDIA_API_KEY`  | none                    | Forwarded into alineod by `init`.         |

`alineo-mcp` shares `alineo.config.json` and the spec directory with `alineo-cli`, so a spec added by either
shows up in both.

## Troubleshooting [#troubleshooting]

| Symptom                                               | Cause                                                 | Fix                                                                                                |
| ----------------------------------------------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `alineod error (network): Could not reach alineod...` | alineod is not running, or `ALINEOD_URL` is wrong.    | Call `init` (needs Docker), or check what is listening on the configured URL.                      |
| `alineod error (404): no run ...` or `no agent ...`   | Wrong ID, or it was already deleted or stopped.       | Take the ID from the tool result that created it. `run_get` lists current agents.                  |
| `alineod error (409): agent ... is not live`          | The agent's sandbox has already ended.                | Check `state` and `outcome` in `agent_get` before prompting again.                                 |
| `init` fails at "Checking Docker..."                  | Docker is not installed or its daemon is not running. | Start Docker and retry.                                                                            |
| A spawned agent never produces a result               | No model provider key reached alineod.                | Put the key in the client's `env` block before `init`, or in the alineod container's env.          |
| The client shows no `alineo` tools                    | The server failed to start.                           | Run `npx -y alineo-mcp` in a terminal. It should wait silently for input, and errors go to stderr. |

Every tool returns errors as a tool result with `isError` set instead of crashing the server, so a failed call
is visible to the client and safe to retry.
