---
title: 'CLI and MCP server'
description: 'Deploy and manage agents from a terminal, CI, or a coding agent over MCP'
---
[View as Markdown](https://camelai.com/docs/camelrun/cli.md) · [Docs index for coding agents](https://run.camelai.com/llms.txt)

`camelrun` deploys and manages agents from a terminal, a script or CI. Coding
agents such as Claude Code, Cursor and Codex get the same operations over MCP,
so they can write an agent's manifest, deploy it, talk to the agent and read what
it did. Use the hosted MCP server at `https://run.camelai.com/mcp` with
nothing to install, or run `camelrun mcp` on your machine.

## Connect your coding agent

The hosted MCP server needs no API key. Add it by URL and sign in when your
client asks: the sign-in page (GitHub, Google, or an API token) asks you to
allow the client, which then acts for your account until you revoke it. Signing
in for the first time creates your account. The server speaks Streamable HTTP.

### Claude Code

```bash
claude mcp add --transport http camelrun https://run.camelai.com/mcp
# Then run /mcp in Claude Code to sign in. Or skip signing in with a key from your environment:
claude mcp add --scope project --transport http camelrun https://run.camelai.com/mcp \
  --header 'Authorization: Bearer ${CAMELAI_API_KEY}'
```

The single quotes keep `${CAMELAI_API_KEY}` as written: `--scope project`
saves it in the project's `.mcp.json`, and Claude Code reads the variable
from its environment each time it starts. The file is safe to commit; a key
is not.

### Codex

```bash
codex mcp add camelrun --url https://run.camelai.com/mcp
codex mcp login camelrun
```

### Cursor

[Add camelRun to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=camelrun\&config=eyJ1cmwiOiJodHRwczovL3J1bi5jYW1lbGFpLmNvbS9tY3AifQ==),
or add it to `.cursor/mcp.json`:

```json
{ "mcpServers": { "camelrun": { "url": "https://run.camelai.com/mcp" } } }
```

### VS Code

[Add camelRun to VS Code](https://vscode.dev/redirect/mcp/install?name=camelrun\&config=%7B%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Frun.camelai.com%2Fmcp%22%7D),
then start the server and sign in when VS Code asks.

### Claude

In claude.ai or the desktop app, go to **Settings**, then **Connectors**,
then **Add custom connector**, and enter
`https://run.camelai.com/mcp`.

The hosted server's `deploy` takes a manifest's YAML as text. It reads no files
or environment variables, so `systemPromptFile`, `specFile` and `${NAME}` are
refused: write the values in, or deploy from your machine with the CLI.

Connected apps appear in the console under **API tokens**, where you revoke
them. To connect a client to one agent instead, see
[Agents as MCP servers](/docs/camelrun/mcp-server). Their access tokens last an hour and can't create API tokens.

## Install the CLI

```bash
npm install -g @camelai/camelrun   # Node 22+; or npx @camelai/camelrun <command>
camelrun login                     # paste an API key from the console's API tokens page
```

`login` checks the key and saves it to `~/.config/camelrun/credentials.json`.
`CAMELAI_API_KEY` and `CAMELAI_BASE_URL` (for a self-hosted runtime, as the SDKs
read it; `CAMELAI_URL` works too), or `--api-key`
and `--url`, take precedence over it.

## Deploy from a manifest

An agent's configuration lives in your repository as `agent.yaml`, and
`camelrun deploy` makes it so in camelRun. `camelrun init [key]` writes one to
start from.

```yaml agent.yaml
key: support                     # the same key is the same definition
name: Support
systemPromptFile: prompts/support.md
builtins: [web_search, ask_user]
mcpServers:
  - name: app
    url: https://app.example.com/mcp
    auth: { type: bearer, token: "${APP_MCP_TOKEN}" }
agents:                          # keyed agents made from it on deploy
  - key: support-main
  - key: support-eu
    systemPromptAppend: Answer customers in the EU region.
```

* Every field except `key`, `agents`, `systemPromptFile` and an OpenAPI
  source's `specFile` is sent as the [definition](/docs/camelrun/definitions).
* `${NAME}` and `${NAME:-default}` read the environment, so credentials stay out
  of the file. An unset variable is an error.
* Each entry of `agents` is a keyed agent made from the definition, with the
  fields of `POST /v1/agents`.
* A file can hold several manifests separated by `---`.

```bash
camelrun deploy                  # ./agent.yaml (or agent.yml, agent.json)
camelrun deploy agents/*.yaml    # several files
camelrun deploy --dry-run        # what would change, credentials hidden
camelrun deploy --apply          # also move live agents to the new revision
```

Deploying upserts each definition by its key: created the first time, a new
revision when the manifest changed it, and `unchanged` otherwise, so you can
deploy on every push. Agents keep the revision they were made with until you
deploy with `--apply`, which reconfigures each live agent between its turns and
keeps its history.

## Commands

An agent is named by its key or its id (`client_...`), and a definition by its
key or id (`def_...`).

| Command                                                                                          |                                                                                                                   |
| ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `whoami`                                                                                         | The account the key belongs to, and its default model                                                             |
| `models [--available]`                                                                           | The model catalog, or the models your account can use                                                             |
| `init [key] [--model m]`                                                                         | Write `agent.yaml`                                                                                                |
| `deploy [file...] [--apply] [--dry-run]`                                                         | Deploy manifests                                                                                                  |
| `agents list`, `agents get <agent>`                                                              | List agents, or show one's configuration and tool sources                                                         |
| `agents create <key> [--definition d] [--model m] [--prompt text]`                               | Create an agent outside a manifest                                                                                |
| `agents configure <agent> [--model m] [--prompt text] [--prompt-append text] [--thinking level]` | Change one agent between runs                                                                                     |
| `agents fork <agent> [--key k] [--name n] [--at message]`                                        | A new agent with its configuration, history and files; `--at` ends the history at a message index or a request id |
| `agents delete <agent> --yes`                                                                    | Stop an agent and delete its history and files                                                                    |
| `run <agent> <message...>`                                                                       | Send a message and print the reply                                                                                |
| `runs get <agent> <requestId> [--wait s]`                                                        | A run's result                                                                                                    |
| `history <agent> [--limit n]`                                                                    | Its latest messages, tool calls included                                                                          |
| `abort <agent>`                                                                                  | Stop its running turn                                                                                             |
| `inputs [agent]`, `answer <agent> <inputId> <value>`                                             | Questions and approvals waiting on someone, and answering them                                                    |
| `schedules list\|add\|delete <agent>`                                                            | Wake-ups: `add --text t --in 3600 [--every 86400]`                                                                |
| `definitions list\|get\|agents\|delete`                                                          | Definitions, and the revision each agent has                                                                      |
| `telemetry get\|set\|test\|clear`                                                                | [Trace export](/docs/camelrun/observability): where traces go, header names, the last export                      |

`run` waits for the run to end. `--wait 30` waits at most 30 seconds, and
`--no-wait` prints the request id to follow with `runs get`. `--from user-1`
says who is sending, and `--steer` gives the message to a running turn.

`telemetry set` changes only what it is given: an endpoint, `--header`,
`--protocol http/protobuf|http/json`, `--sample-rate 0..1`, `--content` or `--no-content`. Take header values from the environment or stdin,
so your collector's key stays out of shell history and the process list:

```bash
camelrun telemetry set https://api.smith.langchain.com/otel/v1/traces --header x-api-key=@env:LANGSMITH_API_KEY
camelrun telemetry test      # one span, sent now; exits 1 if the endpoint refused it
```

No command prints a header's value. `run --traceparent 00-<trace-id>-<span-id>-01`
continues your trace.

`answer` takes `true` or `false` for an approval, the chosen label or your own
words for a question, the fields as JSON for a form, or `decline`.

Output is text on a terminal and JSON otherwise (or with `--json`). Exit codes
are `0` for done, `1` for an error or a failed run, and `2` when the run waits
on a person.

## Local MCP server

`camelrun mcp` serves the same tools over stdio, with the CLI's credentials. Its
`deploy` also takes `file`, a path to a manifest, and reads the files and
environment variables it names.

### Claude Code

```bash
claude mcp add camelrun -- npx -y @camelai/camelrun mcp
```

It uses `CAMELAI_API_KEY` from the environment Claude Code starts it in, or
else your `camelrun login`. To name the key in the project's `.mcp.json`, as
a variable rather than its value:

```json .mcp.json
{
  "mcpServers": {
    "camelrun": { "command": "npx", "args": ["-y", "@camelai/camelrun", "mcp"], "env": { "CAMELAI_API_KEY": "${CAMELAI_API_KEY}" } }
  }
}
```

### Cursor

Cursor reads the environment as `${env:NAME}`:

```json .cursor/mcp.json
{
  "mcpServers": {
    "camelrun": { "command": "npx", "args": ["-y", "@camelai/camelrun", "mcp"], "env": { "CAMELAI_API_KEY": "${env:CAMELAI_API_KEY}" } }
  }
}
```

### Codex

Codex passes the variables `env_vars` names through:

```toml ~/.codex/config.toml
[mcp_servers.camelrun]
command = "npx"
args = ["-y", "@camelai/camelrun", "mcp"]
env_vars = ["CAMELAI_API_KEY"]
```

### Keys stay out of MCP configs

MCP configs such as `.mcp.json` and `.cursor/mcp.json` are often committed.
Never write a key's value into one: name the variable, as above, and keep the
key in your shell's environment or an ignored file such as `.env.local`.

## MCP tools

Both servers offer `deploy`, `list_agents`, `get_agent`, `create_agent`,
`configure_agent`, `fork_agent`, `delete_agent`, `run_agent`, `get_run`, `agent_history`,
`abort_agent`, `list_inputs`, `answer_input`, the schedule and definition tools,
`list_models`, `whoami`, and `read_docs`, which reads the camelRun docs.

`run_agent` and `get_run` wait at most `wait` seconds (default 50) so a call
stays inside clients' tool timeouts. A run still going comes back as `running`
with its `requestId`. A run that asks a person something comes back as
`input_required`, and the coding agent should ask you and answer with what you
decided.

The tools that overwrite, delete, stop or irreversibly answer something
(`deploy`, `configure_agent`, `create_agent`, the deletes, `abort_agent`,
`answer_input`) are marked destructive, so clients that confirm such calls ask
you first. `create_agent` is because, for a key that already has an agent, it
brings that agent to the configuration given (keeping its history).
`fork_agent` only adds an agent, so it isn't. `run_agent`, `answer_input` and `add_schedule` are open-world: the runs they
start can search and fetch the web and call the agent's tool servers.

`list_agents` gives each agent's key, id, name and model, with `loaded`
(whether it is in a runtime's memory now, idle or not; not whether a run is
going, which `run_agent` and `get_run` say) and `toolsConnected` (whether an
application serving its attached tools is connected).

> **Warning:**
>
> A key or a connected app can create and delete every agent in your account.
> Give a coding agent a key of its own, or connect it with OAuth, so you can
> revoke it alone.
