Chapter 2

Set Up Your Agent

There are four pieces, and they do different jobs. The skill teaches your agent how Courier works. The MCP server lets it act on your workspace. The CLI gives it a terminal. The machine-readable docs are there when it needs to look something up.

how to build product notifications with AI

Last updated: September 2026

There are four pieces, and they do different jobs. The skill teaches your agent how Courier works. The MCP server lets it act on your workspace. The CLI gives it a terminal. The machine-readable docs are there when it needs to look something up.

You don't need all four to start. You need an API key and about ten minutes.

What you need before you start

A Courier account, and an API key from Settings → API Keys.

Every workspace has two environments, Production and Test, and each has its own key. They're fully isolated: templates, brands, integrations, log data, all of it belongs to one environment only. Use the Test key for everything here. Sending to your own email from Test is fine. Sending to real users from Test is not.

One thing that saves time later: generate a separate key for each agent you connect. The key is what you revoke when something goes wrong, and you want to revoke one agent, not all of them.

How do I connect Courier's MCP server to my AI tool?

The MCP server is a remote HTTP endpoint at https://mcp.courier.com. It exposes 144 tools covering the Courier API, so your agent can create templates, send messages, build journeys, and read delivery logs by calling typed tools instead of writing HTTP requests.

Authentication is a header named api_key. Not Authorization, not a bearer token. Every client passes it a little differently, but the value is the same API key you'd use against the REST API.

Claude Code:

claude mcp add --transport http courier https://mcp.courier.com --header api_key:YOUR_COURIER_API_KEY

That registers the server for the current project. Add --scope user to make it available everywhere.

Cursor, in your MCP settings:

{
"mcpServers": {
"courier": {
"url": "https://mcp.courier.com",
"headers": { "api_key": "YOUR_COURIER_API_KEY" }
}
}
}

VS Code, in .vscode/mcp.json:

{
"inputs": [
{
"type": "promptString",
"id": "courier-api-key",
"description": "API key for Courier service",
"password": true
}
],
"servers": {
"courier": {
"url": "https://mcp.courier.com",
"type": "http",
"headers": { "api_key": "${input:courier-api-key}" }
}
}
}

Windsurf, in ~/.codeium/windsurf/mcp_config.json. Note it wants serverUrl, not url:

{
"mcpServers": {
"courier": {
"serverUrl": "https://mcp.courier.com",
"headers": { "api_key": "YOUR_COURIER_API_KEY" }
}
}
}

Codex, in ~/.codex/config.toml. The codex mcp add command can't set custom headers, so edit the file directly:

[mcp_servers.courier]
url = "https://mcp.courier.com"
http_headers = { "api_key" = "YOUR_COURIER_API_KEY" }

Claude Desktop doesn't speak remote HTTP MCP natively, so it goes through a shim:

{
"mcpServers": {
"courier": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.courier.com", "--header", "api_key: YOUR_COURIER_API_KEY"]
}
}
}

Antigravity, Gemini CLI, Grok Build, OpenCode, Zed, and Warp are also supported. The MCP docs page has the exact block for each.

How do I install the Courier CLI?

npm install -g @trycourier/cli

The CLI reads COURIER_API_KEY from your environment. Export it in your shell profile and every command picks it up:

export COURIER_API_KEY="your_test_key"

--api-key overrides it for a single command, which is what you want when you're bouncing between Test and Production.

A few flags worth knowing. --format takes json, yaml, jsonl, pretty, or raw, and defaults to human-readable in a terminal and JSON in a pipe. --transform filters output with GJSON syntax. --debug shows the HTTP request and response, which is the fastest way to find out why something failed.

Commands follow one pattern:

courier [resource] <command> [flags]

The groups you'll use in this guide are send, messages, notifications, journeys, journeys:templates, journeys:runs, profiles, brands, and translations. Run --help on any of them.

How do I install the Courier skill?

The skill is a set of instructions your agent reads when you ask it something Courier-related. It's one skill, named courier, and the fastest install works with most assistants:

npx skills add trycourier/courier-skills

Claude Code can install it as a plugin instead, which self-updates and ships the Courier docs MCP server alongside it, so your agent can look things up with no extra setup:

/plugin marketplace add trycourier/courier-skills
/plugin install courier@courier-skills

Or clone it by hand into whatever skills directory your tool reads:

git clone https://github.com/trycourier/courier-skills.git /tmp/courier-skills
cp -R /tmp/courier-skills/skills/courier ~/.claude/skills/ # or ~/.cursor/skills/

What it actually does is route. The agent reads SKILL.md first, and a table inside maps your task to the one or two reference files that answer it. Ask about an OTP flow and it loads the transactional and SMS guides, and nothing else. That matters more than it sounds: the alternative is an agent that either guesses or reads everything.

Give your agent standing context

This part is our recommendation rather than something Courier documents, but it's the difference between an agent that asks you the same question every session and one that doesn't.

Put an AGENTS.md or CLAUDE.md in your project with the things that are true about your setup:

# Notifications
- Courier, Test environment. Key is in `COURIER_API_KEY`.
- Always send to `user_id`, never to a raw email address.
- Live channels: email (SendGrid), in-app inbox. No SMS yet.
- Create templates as drafts. A human publishes.
- Before saying a send worked, check the delivery log and confirm it reached SENT.

Five lines like that stop most of the guessing.

Connect your first channel provider

Provider setup happens in the Courier dashboard under Channels, not through the API. Your agent can send through a provider once it's connected, but it doesn't wire up the OAuth or hold the credentials.

Gmail is the easiest first one because the dashboard walks you through the browser OAuth and there's no key to manage. For SendGrid, Twilio, or a Slack bot token, paste the credential into the provider's page and save. Your application code never handles it after that.

Worth knowing before you hand a key to an agent: provider credentials are readable through the API. courier providers list returns each provider's settings, and those settings include secrets in plaintext, such as a Resend api_key, a Twilio auth_token, or a Slack signing_secret. So an agent with a workspace key can read your provider credentials, not only send through them. Scope keys per agent and per environment accordingly, and treat a Courier key as roughly as sensitive as the provider keys behind it.

If you're only testing, skip this. Courier's built-in email provider and the in-app inbox work with no setup in the Test environment.

Verify the install with a real send

Ask your agent:

Send a test email to me@example.com that says "Courier is connected."

Or do it from the terminal:

courier send message \
--message '{"to":{"email":"me@example.com"},"content":{"title":"Courier is connected","body":"Hello from the CLI."}}'

You'll get a requestId back. That means Courier accepted the job, not that anything was delivered. Hold onto that distinction. It comes up constantly.

A worked example of why, from running this exact command: the send returned a clean 200 and a requestId, and delivered nothing. The message log said:

status: UNROUTABLE
reason: PROVIDER_ERROR
error: No provider(s) resend in the list of message channel provider(s): postmark.

The workspace's default email routing named a provider that wasn't connected. Nothing about the command was wrong, and nothing in the response hinted at it. Adding explicit routing fixed it:

courier send message \
--message '{"to":{"email":"you@example.com"},"content":{"title":"Courier is connected","body":"Hello from the CLI."},"routing":{"method":"single","channels":["resend"]}}'

Then the history read ENQUEUED → ROUTED → RENDERED → SENT.

To find out what actually happened:

courier messages list --recipient me@example.com
courier messages history --message-id <MESSAGE_ID>

The history endpoint is the honest one. A trailing SENT event means it really went.

Your first ten minutes with MCP

The CLI is better for anything you want to repeat. MCP is better for the part where you don't yet know what you want. Ten minutes in a conversation makes that concrete faster than any explanation.

Try this in order:

"What channel providers do I have connected?" Your agent reads your actual workspace. Nothing to configure, and you find out immediately whether the connection works.

"Send me a test email that says my setup works." First send, no template, no code.

"Did it arrive? Show me the log for that request." Now it's reading the result back rather than telling you what it thinks happened.

"Turn that into a reusable template and send it again with my first name merged in." This is where it stops being a toy. You get a real template in your workspace.

"Show me exactly what got rendered." The agent fetches the rendered output, so you see the resolved variables and the real subject line rather than a description of them.

"Now make the same thing work for SMS."

Ten minutes in, you have a template you can send, and you've watched your agent read your workspace, act on it, and check its own work. When you know what you want, move it to the CLI or the SDK so it runs the same way every time. Chapter 3 is about making that choice deliberately.

Frequently asked questions

Do I need both the MCP server and the CLI?

No, and plenty of people run one. MCP is for exploring and prototyping, where a conversation beats remembering syntax. The CLI is for anything you want to happen the same way twice: CI, scheduled jobs, scripts. They read the same API, so a template your agent creates over MCP shows up in courier notifications list immediately.

What's the difference between the MCP server and the skill?

The MCP server is what your agent can do. The skill is how it knows to do it well. The server exposes typed tools; the skill tells the agent which ones to reach for and what the rules are. You can use either alone. Together, the agent stops guessing.

Which AI coding tools work with Courier?

Any tool that speaks MCP. The docs currently ship install configs for Claude Code, Cursor, Codex, Antigravity, VS Code, Windsurf, Gemini CLI, Grok Build, OpenCode, Zed, Warp, and Claude Desktop. As new MCP clients ship, they work without anything changing on Courier's side.

Can a teammate share my setup?

They use the same server URL and their own API key. The key determines which workspace and environment the calls land in, so if you share a workspace, generate a key each rather than passing one around. Revoking one key then doesn't lock out the whole team.

Should I use my Test or Production key?

Test, until you're deliberately shipping. The environments are fully isolated, so nothing you do in Test touches production templates, logs, or users. The one thing to watch: if you connect real provider credentials to your Test environment, Test sends go through those real providers. Use a sandbox provider key for Test if that matters to you.