Skip to content

AI AgentsIn Your Editor

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.

6 min readboth modes

The command

courier-mcp serves the endpoints your project offers to agents — those marked .agent(), and those its agents policy 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.

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:

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

VS Code — in .vscode/mcp.json:

.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 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:

~/.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

OptionWhat 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-onlyOffer 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.*
--listPrint what is offered to agents and why, and exit without serving
--no-watchKeep the tools the server started with: no reload on a save
--allow-destructiveFor 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.

--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:

$ 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.

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.