Give Claude Code or Cursor access to your env vars, safely (MCP setup)

Short answer: run Dynv's local MCP server with a read-only token kept in a 0600 file, and point your client at it by path. The agent can then list services, see variable names and masked values, and preview changes, but it cannot read a value back or write anything. You enable writes later, per variable, if you need them.

This tutorial was run end to end on 2026-11-01 against a local Dynv server using the current CLI. Commands and outputs below are from that run unless marked. It assumes you have the CLI and a Dynv account (quickstart). The reasoning behind each choice is in AI agent secrets management; a config to check yours is at /tools/mcp-check/.

1. Get a read-only token and keep it in a file

In the dashboard’s Tokens page create a read-only recovery or viewer token for the agent. Do not use the writer recovery kit from sign-up for this setup. Save only the dynv_mt_… line in a file with mode 0600, and never in the client config:

(umask 077 && mkdir -p ~/.config/dynv && \
  grep -o 'dynv_mt_[A-Za-z0-9._-]*' ~/Downloads/dynv-recovery-<account>.txt \
  > ~/.config/dynv/master.token)
chmod 600 ~/.config/dynv/master.token

Why a file: client config files (~/.claude.json, .cursor/mcp.json) are plaintext and often synced or committed. dynv mcp prints a startup warning if its token came from an inline environment variable.

2. Connect your client

All of these use the token file and --read-only. Replace the paths with absolute ones from command -v dynv and your token location; desktop and editor apps usually don’t expand ~.

Claude Code:

claude mcp add --scope user dynv \
  -e DYNV_URL=https://api.dynv.dev \
  -e DYNV_MASTER_TOKEN_FILE="$HOME/.config/dynv/master.token" \
  -- "$(command -v dynv)" mcp --read-only

Cursor (~/.cursor/mcp.json or .cursor/mcp.json):

{
  "mcpServers": {
    "dynv": {
      "command": "/usr/local/bin/dynv",
      "args": ["mcp", "--read-only"],
      "env": {
        "DYNV_URL": "https://api.dynv.dev",
        "DYNV_MASTER_TOKEN_FILE": "/home/you/.config/dynv/master.token"
      }
    }
  }
}

VS Code uses servers and requires "type": "stdio"; Windsurf, Claude Desktop and Codex have their own shapes in the MCP docs. The wrong root key can silently leave you with zero tools, which is why the next step exists. Restart the client after changing its config.

3. Verify with dynv doctor mcp

$ dynv doctor mcp --client cursor --config ./cursor.json
ok   dynv version 0.1.0
ok   cursor config shape (./cursor.json)
ok   master token source, file type and permissions
ok   server reachable at http://127.0.0.1:8099
ok   authenticated account 3oyr7BoHQ41AapQO with a writer keyring
ok   MCP initialize + tools/list: 9 tools (not the silent 0-tools trap)

(Our test server was local, and the test token was a writer token run with --read-only; with a read-only token the keyring line will differ.) The check that matters is the last: a positive tool count. It also catches the mistakes we warn about. With the token pasted inline in the config:

FAIL cursor config: DYNV_MASTER_TOKEN is inline in the client config; move it to a 0600 file and use DYNV_MASTER_TOKEN_FILE
FAIL master token: DYNV_MASTER_TOKEN_FILE is not set

4. What the agent sees

With --read-only the server exposes nine tools, all reads: whoami, list_processes, get_vars, audit_log, list_vulnerabilities, explain_vulnerability, list_shared, get_shared and list_generators. Its whoami scope in our run:

"scope": { "allow_reveal": false, "allow_rotate": false, "allow_process_admin": false,
           "allow_token_create": false, "allowed_keys": [], "read_only": true, "write": false }

get_vars on a service with two variables returns names and masked values:

{ "process": "web", "values_masked": true,
  "vars": { "API_KEY":      { "apply": "restart", "value": "•••• (12 chars)" },
            "DATABASE_URL": { "apply": "restart", "value": "•••• (20 chars)" } },
  "version": 2 }

Masking shows the length. If a length is itself sensitive for a variable, don’t put it where an agent can list it.

Prompts to try in a new session: “Call whoami and list my services.” “Which variables does web have, and which restart versus update hot?” “Do any of my services have critical vulnerabilities?”

5. Try to make it leak

Ask for the value. The get_vars tool has a reveal argument, and the server’s answer to reveal: true when --allow-reveal is off is the same masked result as above: the flag is the operator’s, not the agent’s. Ask a read-only server to change something and it has no write tools to call. Those two refusals are the point: a prompt-injected agent that is told to “print every secret” has nothing to print.

6. Enable writes, narrowly, and always dry-run first

If the agent must change something, don’t widen the token; start the server with an allow-list and a writer token on one dedicated machine (no --read-only):

dynv mcp --allow-keys 'LOG_LEVEL'

Every write tool accepts dry_run: true. Ours returned the exact change without writing:

{ "changes": [ { "name": "LOG_LEVEL", "operation": "add", "before": null, "delivery": "restart" } ],
  "dry_run": true, "ok": true, "target": { "kind": "process", "process": "web" } }

(abridged: the response also reports masked before/after values, affected services and template validation). A key outside the list is refused with a hint rather than a guess:

error: NODE_OPTIONS is not in this MCP server's --allow-keys list
hint: NODE_OPTIONS is outside --allow-keys; ask the owner to add NODE_* or the exact key, or set it in the dashboard

Code-loading variables such as NODE_OPTIONS and PATH are refused over MCP even if an allow-list matches. Only one writer should be active at a time; see the MCP docs before enabling writes.

What this doesn’t protect

  • A value the agent sets passes through its context, because it wrote it.
  • The token file is a file. An agent that can run commands or read files as your OS user may read it; that is why the token should be read-only and the agent sandboxed.
  • Masking covers what the MCP server returns, not commands you let the agent run (dynv run -- env would print the environment).
  • There is no hosted MCP endpoint today: it is a local stdio server, so remote-only connectors can’t use it.

Facts last verified . Spotted an error? Tell us.

New here? Start here for the guides in a sensible order.