API keys
Connect CI jobs, review bots, and other headless agents to the ctxpipe MCP with an API key.
OAuth is the default for a person at a laptop. Use an API key only when a client cannot finish the browser sign-in: a CI job, a headless agent, a review bot, or a host that accepts only a fixed header.
Choose a key
| Organization key | Personal key | |
|---|---|---|
| Where to create it | Organization settings → API Keys | User account → API Keys |
| Who can create it | An organization owner or admin | Each user, for themselves |
| Acts as | The organization, not the person who created it | You, as a member |
| Reads | Its one organization. The org argument must name it. | Each organization that you are a member of. ctxpipe checks your membership on each call. |
| Works on | /mcp only | /mcp, and the REST API as you |
Use an organization key for shared automation. It continues to work when the person who created it leaves the organization.
A new key expires after 30 days by default, and allows 1,000 requests per hour. You can create a key that never expires, but treat it as a long-lived secret. ctxpipe shows the secret one time only. Give each key a name.
To rotate a key, create a new key, change CTXPIPE_API_KEY to it, then revoke
the old key.
Send the key
Send the key in the x-api-key header to /mcp. If a host can send only a
Bearer token, send Authorization: Bearer <key>. A Bearer API key works only
on /mcp, not on the REST API.
Keep the secret out of files. Put a reference to the CTXPIPE_API_KEY
environment variable in the client configuration. The reference is safe to
commit.
The CLI writes that reference for you:
npx ctxpipe mcp add --client cursor --scope both --auth api-key --non-interactiveThe CLI never creates a key and never reads CTXPIPE_API_KEY.
Start from the client configuration in Configure a client by hand, and add the header entry for your client:
| Client | File | Header entry |
|---|---|---|
| Claude Code | .mcp.json | "headers": { "x-api-key": "${CTXPIPE_API_KEY}" } |
| Cursor | .cursor/mcp.json or ~/.cursor/mcp.json | "headers": { "x-api-key": "${env:CTXPIPE_API_KEY}" } |
| Codex | .codex/config.toml or ~/.codex/config.toml | env_http_headers = { "x-api-key" = "CTXPIPE_API_KEY" } |
| OpenCode | opencode.json or ~/.config/opencode/opencode.json | "headers": { "x-api-key": "{env:CTXPIPE_API_KEY}" }, and "oauth": false |
| VS Code / Copilot | .vscode/mcp.json | "headers": { "x-api-key": "${env:CTXPIPE_API_KEY}" } |
Each client uses its own syntax for the variable. Codex wants the name of the
variable, not $VAR and not the secret. In OpenCode, "oauth": false stops
the client from opening the browser after a 401.
For example, a Claude Code .mcp.json with an API key:
{
"mcpServers": {
"ctxpipe": {
"type": "http",
"url": "https://app.ctxpipe.ai/mcp",
"headers": {
"x-api-key": "${CTXPIPE_API_KEY}"
}
}
}
}Set CTXPIPE_API_KEY
The process of the MCP client must have the variable. An export in the
terminal where you ran the CLI is not enough for an app that you start from
the Dock or the Start menu.
- CLI agents (Claude Code, Codex, OpenCode, Cursor CLI): export the
variable in the terminal, then start the agent from that terminal. To set it
for each session, put it in
~/.zshenvor~/.bash_profile. The Cursor CLI can start a shell that does not read.zshrc. - Desktop apps (Cursor, VS Code): set the variable for your user session,
then quit and open the app again. On macOS, run
launchctl setenv CTXPIPE_API_KEY '<key>'. On Linux, useenvironment.d. On Windows, use the user environment variables. You can also start the app from a terminal that has the variable, for examplecursor .. - CI: store the key as a secret of your CI system, and expose it to the job
as
CTXPIPE_API_KEY.
To test the key, run:
CTXPIPE_API_KEY=<key> npx ctxpipe doctor mcp --url "https://app.ctxpipe.ai/mcp"The status ready-for-api-key means that the key works.
Troubleshooting
- An organization key gets
401on the REST API. This is correct. Organization keys work only on/mcp. Use a personal key or a browser session for the REST API. - A tool gets
org_not_found. An organization key reads only its own organization. Make theorgargument match it. - The client sends no key. A variable in the environment is not enough by
itself. The client configuration must map it to the
x-api-keyheader.