# In Your Editor

Give the agent you code with your API as tools: npx @noverax/courier-mcp serves your project's courier.config.ts over stdio to Claude Code, Cursor, VS Code or Codex.

## The command

`courier-mcp` serves the endpoints your project offers to agents — those marked `.agent()`, and those its [`agents` policy](/docs/agents/overview#what-agents-may-call) offers — over stdio, the transport an editor's agent starts a local MCP server with. It loads `courier.config.ts` the way your app's runtime and Studio load it — TypeScript, extensionless imports and tsconfig path aliases included — and offers every source it declares:

```bash
npm install -D @noverax/courier-mcp
npx @noverax/courier-mcp --dotenv .env.local
```

Started by hand it waits for a client on stdin; an editor starts it for you.

> **In one command**
>
> `npx @noverax/create-courier --mcp` sets Courier up with this done: `agents: { offer: "reads" }` in the config, the example API's reads described with `.agent()`, the package installed, and `.mcp.json` written for Claude Code. See [Create Courier](/docs/create-courier).

> **Write the package's full name**
>
> npx runs the project's own copy of a command. Where it finds none — an editor that starts servers outside the project, or before `npm install` — it fetches the package the command names from npm, and with no terminal to ask in, it does not ask. Under the bare name `courier-mcp`, npm keeps a package that is not Courier's; `@noverax/courier-mcp` runs your project's copy, or Courier's own.

## Add it to your editor

**Claude Code** — from the project's root; `--scope project` writes `.mcp.json` for everyone who works on it:

```bash
claude mcp add courier --scope project -- npx @noverax/courier-mcp --dotenv .env.local
```

**Cursor** — in `.cursor/mcp.json`:

```json title=".cursor/mcp.json"
{
  "mcpServers": {
    "courier": { "command": "npx", "args": ["@noverax/courier-mcp", "--dotenv", ".env.local"] }
  }
}
```

**VS Code** — in `.vscode/mcp.json`:

```json title=".vscode/mcp.json"
{
  "servers": {
    "courier": {
      "type": "stdio",
      "command": "npx",
      "args": ["@noverax/courier-mcp", "--cwd", "${workspaceFolder}", "--dotenv", ".env.local"]
    }
  }
}
```

> **With the Courier extension**
>
> The [Courier extension](/docs/studio/editor#your-api-for-vs-codes-agent) offers VS Code's agent each project's servers on its own — the API's, handed the project's `.env` files, and Studio's — with nothing to write here.

**Codex** — in `~/.codex/config.toml`:

```toml title="~/.codex/config.toml"
[mcp_servers.courier]
command = "npx"
args = ["@noverax/courier-mcp", "--cwd", "/path/to/project", "--dotenv", ".env.local"]
```

An editor that starts servers somewhere other than the project names it with `--cwd`.

## Options

| Option | What it does |
| --- | --- |
| `--cwd <dir>` | The project's root, where `courier.config.*` is (default: the working directory) |
| `--source <names>` | The sources to offer, comma-separated (default: every source). With one, tool names carry no source prefix |
| `--dotenv <files>` | `.env` files to load before the config, comma-separated, relative to the root |
| `--read-only` | Offer reads alone, whatever the config's `agents` allows |
| `--deny <patterns>` | Endpoints to keep from agents as well as the config's own `deny`, comma-separated: `billing.**,shop.users.*` |
| `--list` | Print what is offered to agents and why, and exit without serving |
| `--no-watch` | Keep the tools the server started with: no reload on a save |
| `--allow-destructive` | For a client that cannot ask a person, leave a call a person confirms to the client's own approval; a client that can ask is asked all the same |
| `--timeout <ms>` | How long a call may take when its endpoint names no timeout (default: 60 000) |
| `--name <name>` | The name the server gives its client (default: `courier`) |

Node's own `--env-file` is not one of them: Node takes that flag for itself wherever it appears.

Behind a corporate proxy, or with a certificate authority of your own, give the server `NODE_USE_ENV_PROXY=1`, `HTTPS_PROXY` and `NODE_EXTRA_CA_CERTS` in its `env` in the editor's configuration — Node reads them as it starts, before `--dotenv` loads anything. See [Proxies & Certificates](/docs/advanced/proxies-and-certificates#the-mcp-server).

`--read-only` and `--deny` only ever narrow what the config offers: what an agent may call is widened in code and config, which go through review, never on a command line.

## What is offered

`--list` reads the project as the server would and prints what it decided, without serving or reaching Studio:

```text
$ npx @noverax/courier-mcp --list
3 of 6 endpoints offered to agents
agents: offer "reads", access "destructive", confirm "destructive", deny billing.**

  orders_get     read                            shop.orders.get     marked .agent()
  orders_list    read                            shop.orders.list    offer: "reads"
  orders_cancel  destructive, a person confirms  shop.orders.cancel  marked .agent()

Kept from agents
  shop.orders.create  POST orders        a write not marked .agent()
  shop.orders.export  GET orders/export  .agent(false)
  billing.charge      POST charge        denied by billing.**
```

It takes `--source`, `--read-only` and `--deny` as the server does, so it shows what a start with them would offer — a step a CI job can run, too. Warnings follow the list: a pattern that names no endpoint, a tool left out for its name, more than 40 tools.

## While you edit

The server follows the project: a save to `courier.config.ts`, or to any module of the project it reaches — an API's definition, the `agents` policy — loads the config again, and the client is told when the tools it sees change. Nothing needs restarting:

- **Only what changed is transformed.** A module whose bytes are the same is not compiled again; a burst of saves — a branch checked out — is one reload. From the save to the client being told takes about a tenth of a second on a project of 40 tools, 75 ms of it the wait that gathers a burst.
- **Told only of a real change.** A save no agent can see — a comment, a formatting pass, a file touched — tells the client nothing.
- **Both eras.** A client on the 2025 handshake gets `notifications/tools/list_changed`; a 2026-07-28 client gets it on the stream it opened with `subscriptions/listen`. A client that asks for neither sees the new tools the next time it lists them.
- **A broken save keeps the server serving.** The config or the tools a save breaks are logged, the last good ones stay, and the save that mends them loads them.
- **Nearly free at rest.** Each directory is watched — saves an editor makes by renaming a file included — and the few files the config reaches are looked at again every two seconds, for a filesystem that announces no saves: about 0.03 % of a core.

`--no-watch` keeps the tools the server started with, for a server that should not change while it runs.

## What the agent gets

The tools are your endpoints, called with the credentials your config gives them — the API keys your middleware reads from the environment, for one. The agent can do what those credentials allow, through the endpoints the project offers and no others; a `destructive` one asks you first, in the editor, with the exact call — and so does every write where the policy says `confirm: "write"`.

On start, the server lists the tools it offers in its log — which an editor shows as the server's output — with the policy's warnings, and stops with one line when the config cannot be loaded, its `agents` policy cannot be decided by, or it names no source it was asked for. A project that offers nothing gets a server with no tools, and a line saying so.

## Watch it in Studio

With Studio running, the server joins it as the application's runtime does, and every call an agent makes shows in the timeline marked **agent** — its tool, the client, the variables, the answer, the middleware it ran through. Choose **Agent** in the Mode filter to see them alone. A call that did not run — declined by you, or refused for its arguments — is there too.

```bash
npx @noverax/courier-studio
```

Studio serves the other direction too: the agent you code with can read what Studio recorded — the failed requests, the Audit's findings, the mocks — and send a request again after a fix, through `courier-studio mcp`. See [Studio for Your Agent](/docs/agents/studio).

## stdout is the protocol's

Over stdio, every byte on stdout is read as an MCP message. The server keeps it for the protocol: whatever else writes there — a `console.log` in your config, a library's banner — goes to stderr, which the editor shows as the server's log.
