API keys (legacy)
No longer supported
The MCP server only accepts sign-in now: see MCP setup. API keys get a 401 from the MCP server. They keep working for the REST API, the GitHub Action and the Docker image. To move a client over, follow Moving from an API key.
This page is kept for reference.
The tools that needed a key (shared accounts, secret files and variable requests) were removed with key support.
Creating an MCP key#
The dashboard no longer offers the MCP server surface, so new MCP keys cannot be created. This section explains what an existing key's settings mean. A key was created in Organization → Settings → API Keys → New API Key like this:
- Give the key a recognizable name, such as
codex-development. - Select the MCP server surface. Deselect REST API and GitHub Action unless this same credential genuinely needs them.
- Select only the projects the client needs. All projects also includes projects created in the future and is owner-only.
- Select only the environments the client needs. A development-only agent should not receive production access.
- Select the resources required by its tools:
| Resource | MCP tools enabled |
|---|---|
projects | envpilot_list_projects; project-name and project-slug matches from envpilot_search |
variables | envpilot_get_variables, envpilot_get_variable; variable-key matches from envpilot_search (which also needs projects to enumerate) |
accounts | envpilot_list_accounts |
files | envpilot_list_files, envpilot_get_file |
requests | envpilot_request_variable, envpilot_get_request_status |
docs | envpilot_search_docs, envpilot_get_doc, envpilot_create_doc, envpilot_update_doc_draft. Cannot be combined with files — see below |
For the common project-discovery and variable-read workflow, select projects and variables. Most assistants begin with envpilot_list_projects; without projects, that opening call is denied. An accounts-only or requests-only key is still valid, but only for the corresponding tools.
Think twice before granting `files`
files lets an agent fetch a signing keystore or a private key in full. A
leaked string can be rotated in minutes; a leaked signing key is a different
kind of day. Grant it only to a key whose agent genuinely runs builds, and
never alongside All projects.
- Choose an expiry, create the key, and copy the
envpk_...value immediately.
docs and files are mutually exclusive: a key may carry one or the other,
never both. Documentation is prose an agent reads into its context and files
returns decrypted key material, so a single credential holding both is an
exfiltration chain. An agent that needs each gets two keys.
Project, environment, resource, and surface scopes are immutable. You cannot widen or edit them after creation; create a replacement key when the required access changes. The plaintext is also displayed once: Envpilot stores only its SHA-256 hash and cannot recover a lost key.
Endpoint#
https://www.envpilot.dev/api/mcpTransport is Streamable HTTP (the current MCP spec transport for remote servers). Auth is a plain bearer token — the same envpk_... API key you'd use for the REST API:
Authorization: Bearer envpk_your_key_hereSet ENVPILOT_API_KEY#
Keep the plaintext out of MCP config files and repositories. Put it in the environment of the process that starts the client, then make the client reference the variable by name.
macOS#
For the current Terminal session (zsh), enter the key at the hidden prompt so it does not appear in shell history:
read -rs "ENVPILOT_API_KEY?Envpilot API key: "; echo
export ENVPILOT_API_KEYThis value disappears when the shell exits. For future terminal sessions, have a password manager inject it or edit a user-only shell startup file (do not build the line with a shell command that would record the key in history):
# ~/.zshrc
export ENVPILOT_API_KEY='envpk_your_key_here'A literal export in a startup file is persistent but is plaintext on disk; never put it in a repository, and restrict the file to your user:
chmod 600 ~/.zshrcApps opened from Finder, the Dock, or Spotlight do not inherit variables from ~/.zshrc. To make the current login session pass the already-exported value to newly launched GUI apps:
launchctl setenv ENVPILOT_API_KEY "$ENVPILOT_API_KEY"Fully quit and reopen Codex, Cursor, or the IDE afterward. launchctl setenv lasts only for the current login session; after logout or restart, set it again (preferably from a login automation that reads a keychain or password manager—do not embed the raw key in a LaunchAgent plist). Do not run launchctl getenv ENVPILOT_API_KEY without redirecting it, because that prints the secret.
Linux#
For the current bash session:
read -rsp "Envpilot API key: " ENVPILOT_API_KEY; echo
export ENVPILOT_API_KEYFor future terminal sessions, have a secret manager inject it or edit the appropriate user-only login file (do not build the line with a shell command that would record the key in history):
# ~/.profile
export ENVPILOT_API_KEY='envpk_your_key_here'A literal export is stored as plaintext, so keep the file private:
chmod 600 ~/.profileA desktop launcher inherits the graphical login session, not an interactive shell's .bashrc. The simplest safe option is to launch the app from a terminal that already has the variable. On systemd-based desktops, you can also import the current value into the user and D-Bus activation environments:
systemctl --user import-environment ENVPILOT_API_KEY
dbus-update-activation-environment --systemd ENVPILOT_API_KEYThen fully quit and reopen the app. For persistence, configure the variable through your desktop login environment or secret manager and sign out and back in; do not put the raw key in a .desktop launcher.
Windows PowerShell#
Set the key for the current PowerShell process without echoing the input:
$secret = Read-Host "Envpilot API key" -AsSecureString
$pointer = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret)
try {
$env:ENVPILOT_API_KEY = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($pointer)
} finally {
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($pointer)
}
Remove-Variable secret, pointerChild processes launched from that PowerShell window inherit it. To persist the current value for your Windows user:
[Environment]::SetEnvironmentVariable(
"ENVPILOT_API_KEY",
$env:ENVPILOT_API_KEY,
"User"
)The User-scope value is stored in your Windows profile and is available only to new processes. Fully quit and reopen terminals, Codex, Cursor, and IDE windows; already-running processes keep their old environment.
WSL#
Windows and WSL have separate process environments. A Windows User-scope variable does not automatically configure clients running inside WSL, and a variable exported in WSL does not configure Windows GUI apps. Set ENVPILOT_API_KEY separately inside the WSL distribution using the Linux instructions, then start the WSL-hosted client from a new WSL shell.
Check presence without printing the key#
Use a boolean check—never echo, printenv, Get-ChildItem Env:, or an unredirected launchctl getenv for a secret:
if [ -n "${ENVPILOT_API_KEY:-}" ]; then
echo "ENVPILOT_API_KEY is set"
else
echo "ENVPILOT_API_KEY is not set"
fiif ([string]::IsNullOrEmpty($env:ENVPILOT_API_KEY)) {
"ENVPILOT_API_KEY is not set"
} else {
"ENVPILOT_API_KEY is set"
}A repository .env or .env.local file does not automatically configure an MCP client. Those files are conventions loaded only by frameworks or commands that explicitly read them. Codex, Claude Code, Cursor, and desktop launchers inspect their own process environment; they do not source arbitrary repository dotenv files. Keeping the MCP credential outside the repository also prevents an agent from reading the very key that controls its access.
Rotating or updating a key#
A key's projects, environments, resources, and surfaces are fixed at creation. To recover a lost key, rotate a credential, or grant different access (for example, adding the projects resource or MCP surface), create a new key with the complete intended scope.
- Store the new value in the same environment-variable source. If you set both a persistent value and a current-session value, update both—an already-running shell or GUI process keeps the old value.
- For macOS GUI clients, update
launchctl; for Linux desktop clients, update the login/user environment; for Windows, update the User-scope value. WSL remains separate. - Fully quit and restart the client. The saved Claude Code, Codex, and Cursor configurations still reference the same variable name and need no secret edit.
- Confirm
/mcpor the client's MCP panel lists the Envpilot tools, then make a permitted tool call. - Revoke the old key in Organization → Settings → API Keys.
Revocation is instant—anything still using the old key stops on its next call. If you previously pasted a key directly into Claude Code, remove and re-add the server (claude mcp remove envpilot) or edit the saved entry; claude mcp add does not overwrite an existing server name.
Connecting a client with a key#
Set ENVPILOT_API_KEY in the client's environment first, using the instructions above.
Claude Code#
Reference the environment variable in an expanded Authorization header:
claude mcp add --transport http --scope user \
envpilot https://www.envpilot.dev/api/mcp \
--header 'Authorization: Bearer ${ENVPILOT_API_KEY}'The single quotes matter in POSIX shells: they keep ${ENVPILOT_API_KEY} literal in the saved configuration, and Claude Code expands it from its environment at connection time. The secret never lands in the file.
Choose the Claude Code configuration scope deliberately:
--scope local(the default) keeps the server private to you in the current project.--scope projectwrites.mcp.jsonfor the team. The environment-variable reference is safe to commit, but each user must set their own key and approve/trust the project server before tools load.--scope userkeeps the server private to your user and makes it available across projects.
claude mcp list confirms the server is registered — a revoked or wrong key still shows as listed. To verify the connection is actually live and its tools loaded, run /mcp inside a session. Manage it later with claude mcp get envpilot / claude mcp remove envpilot.
Codex CLI, desktop, and IDE extension#
Codex's local CLI, desktop app, and IDE extension share the same MCP configuration layers. Register the server from the CLI:
codex mcp add envpilot --url https://www.envpilot.dev/api/mcp \
--bearer-token-env-var ENVPILOT_API_KEYOr add it to the user-level ~/.codex/config.toml:
[mcp_servers.envpilot]
url = "https://www.envpilot.dev/api/mcp"
bearer_token_env_var = "ENVPILOT_API_KEY"The url selects Streamable HTTP, while bearer_token_env_var makes Codex build the bearer header from the named variable. Do not replace it with the plaintext key.
You may put the same block in .codex/config.toml to scope it to a repository, but Codex loads project configuration only after you trust that project. After changing the variable or configuration, start a new CLI session, select Restart for the server in Codex desktop, or restart the IDE extension. Run /mcp to confirm the server is connected and the Envpilot tools—not merely the saved server entry—are present.
Cursor#
Add a remote server to the global ~/.cursor/mcp.json, or to .cursor/mcp.json for a trusted project:
{
"mcpServers": {
"envpilot": {
"url": "https://www.envpilot.dev/api/mcp",
"headers": {
"Authorization": "Bearer ${env:ENVPILOT_API_KEY}"
}
}
}
}Cursor resolves ${env:ENVPILOT_API_KEY} from the environment it inherited at startup. Fully quit and reopen Cursor after setting or rotating the variable, then confirm the tools under MCP settings. Do not commit a raw envpk_... value.
Other Streamable HTTP clients#
Configure the endpoint as Streamable HTTP and send this header on every request:
Authorization: Bearer <the ENVPILOT_API_KEY value>Prefer a client-native secret store or environment-variable reference. Placeholder syntax is client-specific: do not assume a generic client expands ${ENVPILOT_API_KEY} or ${env:ENVPILOT_API_KEY}.
Troubleshooting a key connection#
New MCP keys cannot be created. Where a fix below says to create a replacement key, switch the client to sign-in instead.
A failed MCP tool call returns an error message in its result — no separate error code, since tool clients only see the text. The table lists each message (tool-specific variants may append detail, e.g. the request tools' — filing requests needs the "requests" resource). One exception: a missing or malformed Authorization header is rejected at the transport level with HTTP 401 before any tool runs.
First separate client setup failures from Envpilot tool errors:
| Symptom | Meaning / fix |
|---|---|
| Server is registered but has no tools | Registration only proves the config was saved. Open /mcp or the client's MCP panel and inspect initialization. The most common cause is that the client process did not inherit ENVPILOT_API_KEY; set it in the parent environment and fully restart the client. |
| Works in a terminal, not a GUI app | The terminal has a current-session variable, but the desktop launcher started from a different environment. Use launchctl on macOS, the graphical login/user environment on Linux, or Windows User scope, then launch a new process. |
| Works on Windows but not in WSL | Windows and WSL environments are separate. Set the key inside the WSL distribution and restart the WSL-hosted client. |
Header contains ${...} literally | The client did not expand the placeholder. Claude Code uses ${ENVPILOT_API_KEY}; Cursor uses ${env:ENVPILOT_API_KEY}; Codex uses bearer_token_env_var = "ENVPILOT_API_KEY". Confirm the client supports that syntax and inherited the variable, then restart it. |
| HTTP 401 before tools load | Ensure the header is exactly Authorization: Bearer envpk_...: one Bearer prefix, one space, no surrounding quotes in the value, no duplicated prefix, and no literal placeholder. Use a safe presence check instead of printing the key. |
Once tools load, these are the server's error semantics:
| Message | Meaning / fix |
|---|---|
Invalid or revoked API key | The key is wrong, revoked, or expired—create a replacement key. |
That resource is not in this API key's scope | The key is missing the resource a tool needs. Scopes are immutable: use the Tools table to create a replacement with the required resource. Request tools append — filing requests needs the "requests" resource. |
That environment is not in this API key's scope | The key is limited to other environments. Use one already in scope, or create a replacement key that includes the required environment. |
Project not found | The slug is wrong, or the project is outside the key's immutable scope—the two are indistinguishable by design; see Understand scope. |
This API key is not enabled for this surface | The key was created without the MCP server surface. Surfaces are immutable: create a replacement with MCP server selected. |
The public API is available on the Pro plan — this organization's plan no longer includes it | The organization's plan no longer includes MCP access. |
Rate limit exceeded — retry after Nms | Hit a rate-limit bucket: 120/min metadata or 30/min value pulls (both shared with REST), or 5/hour (burst 2) for envpilot_request_variable—back off for the given delay. |
Missing or invalid API key. (HTTP 401) | Transport-level rejection before any tool runs—the Authorization header is missing or malformed. It must resolve to Bearer envpk_..., not a literal placeholder. |
Older server builds returned an opaque [Request ID] Server Error for all of the above instead of the real message — if you see that instead of one of these strings, the connected server predates this fix.
Limits#
- Scope cannot be widened. Adding a project, environment or resource means a new key and a client restart.
- The key is shown once. Store it in an environment variable, never in a config file you commit.
- Pro plan (
mcp_server), re-checked on every tool call. - Placeholder syntax is client-specific:
${VAR},${env:VAR}andbearer_token_env_varare not interchangeable. - A client only inherits the environment it was launched with; changing the key means fully restarting it.