AI Claude Code 1Password Secrets Security MCP CLI 2026

Claude Code Secrets Management with 1Password CLI: op run, Shell Integration, and MCP — Complete 2026 Guide

The Prompt Shelf ·

Claude Code ingests your entire project directory by default. If your .env file lives in the repo, it lives in the model’s context window — and so do every API key, OAuth token, and database URL inside it. .gitignore does not protect you here. The model sees the file before any commit boundary applies.

This is a different threat model than the one most developers learned. .env files were “safe” when only humans (and CI runners with scoped tokens) read them. AI agents change that contract: every spawned subagent, every MCP server call, every read_file action potentially exposes the secret further than you intended.

This guide covers three production-grade patterns for replacing plaintext .env with 1Password CLI as the source of truth, plus a clean comparison against Doppler, Infisical, HashiCorp Vault, and SOPS.

Why .env Plaintext Is a Liability in the AI Agent Era

Three concrete failure modes from Claude Code’s default behavior:

  1. Context window exposure. Claude Code’s project context loader reads files matching common patterns (*.md, source files, configuration). .env is excluded by the default ignore list, but custom scripts, .env.local.sample, secrets.json, or any misnamed file is fair game. Once a secret is in the context window, you cannot reliably redact it from subsequent tool calls.

  2. Subagent parallelism. With Claude Code subagents (Task tool) running in parallel, each agent receives a copy of the project context. A four-agent fanout means four copies of any secret that leaked into context. Audit trails become harder to reconstruct.

  3. MCP server transit. MCP servers that accept arbitrary input (database queries, HTTP requests) can be tricked into exfiltrating secrets through prompt injection. A secret only ever loaded at runtime — never written to disk in plaintext — significantly narrows this attack surface.

The fix is not “be more careful.” It is structural: make plaintext secrets impossible to read, because they do not exist on disk.

1Password CLI Quick Setup

1Password CLI (op) is the official command-line client. Install on macOS, Linux, or Windows:

# macOS (Homebrew)
brew install 1password-cli

# Linux (Debian/Ubuntu)
curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
  sudo gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] \
  https://downloads.1password.com/linux/debian/amd64 stable main" | \
  sudo tee /etc/apt/sources.list.d/1password.list
sudo apt update && sudo apt install 1password-cli

# Windows (Winget)
winget install AgileBits.1Password.CLI

# Verify
op --version  # should print 2.30+ as of June 2026

Sign in once per session:

eval "$(op signin)"

Pair the CLI with the 1Password 8 desktop app for biometric unlock — op signin then resolves through Touch ID / Windows Hello / polkit without prompting for the master password each session.

If you do not have a 1Password account yet, start a free 14-day trial before continuing. Pattern A and B below require an active vault.

Pattern A: op run for Runtime Injection

op run resolves op:// references at process start and injects the values as environment variables to the child process — without ever writing them to disk.

Step 1. Store a secret in 1Password (one-time setup):

op item create --category=apicredential \
  --title="Anthropic API" \
  --vault=Development \
  credential=sk-ant-api03-xxxxx

Step 2. Reference it from .env (this file is safe to commit):

# .env
ANTHROPIC_API_KEY=op://Development/Anthropic API/credential
OPENAI_API_KEY=op://Development/OpenAI/credential
DATABASE_URL=op://Development/Prod DB/connection_string

Step 3. Run any command with secrets injected:

op run --env-file=.env -- claude
op run --env-file=.env -- npm run dev
op run --env-file=.env -- python agent.py

The child process sees ANTHROPIC_API_KEY=sk-ant-api03-xxxxx in its environment. The file on disk only contains the op:// reference. There is no plaintext secret anywhere in your filesystem.

Production tip. Use op run --no-masking only when debugging — by default op run masks secret values in stdout/stderr to prevent accidental terminal logging.

Pattern B: Shell Integration (zsh / fish / bash)

If you do not want to prefix every command with op run, use shell-level injection. Each shell has slightly different syntax.

zsh (~/.zshrc):

# Resolve op:// references on shell startup
if command -v op &>/dev/null; then
  export ANTHROPIC_API_KEY="$(op read 'op://Development/Anthropic API/credential' 2>/dev/null)"
  export OPENAI_API_KEY="$(op read 'op://Development/OpenAI/credential' 2>/dev/null)"
fi

fish (~/.config/fish/config.fish):

if command -v op >/dev/null
    set -gx ANTHROPIC_API_KEY (op read 'op://Development/Anthropic API/credential' 2>/dev/null)
    set -gx OPENAI_API_KEY (op read 'op://Development/OpenAI/credential' 2>/dev/null)
end

bash (~/.bashrc):

if command -v op &>/dev/null; then
  export ANTHROPIC_API_KEY="$(op read 'op://Development/Anthropic API/credential' 2>/dev/null)"
fi

Trade-off: shell integration loads secrets into every shell session, increasing exposure surface compared to op run. Use it for keys you genuinely need everywhere (your primary Anthropic key); use op run for project-scoped secrets.

Pattern C: 1Password MCP Server Integration

The Model Context Protocol server for 1Password lets Claude Code (and any MCP-compatible AI tool) request secret resolution mid-conversation, with explicit user approval per access.

Setup. Add to your Claude Code MCP configuration (~/.claude/mcp.json or .mcp.json in your project):

{
  "mcpServers": {
    "1password": {
      "command": "npx",
      "args": ["-y", "@1password/mcp-server"],
      "env": {
        "OP_SERVICE_ACCOUNT_TOKEN": "${OP_SERVICE_ACCOUNT_TOKEN}"
      }
    }
  }
}

The OP_SERVICE_ACCOUNT_TOKEN is a 1Password service account credential (created at https://my.1password.com/developer-tools/infrastructure-secrets/serviceaccount). Service accounts are scoped to specific vaults — never give them access to your personal vault.

Usage in Claude Code. Once configured, the agent can request 1password__op_read for any op:// reference. The MCP server returns the resolved value to the model’s context window for the current turn. Claude Code displays a permission prompt on first access per session.

Use Pattern C when:

  • The set of needed secrets is unknown ahead of time (agent decides which API to call).
  • You want per-request audit logs in 1Password’s activity log.
  • Long-running agents need rotation without restart.

Do not use Pattern C when:

  • You can determine the needed secrets at process start (Pattern A is simpler).
  • You are running in CI/CD without an interactive user to approve prompts (service account tokens bypass this, but at the cost of audit granularity).

Decision Matrix: Which Pattern When

ScenarioRecommended Pattern
Single-project Claude Code session, fixed set of secretsA. op run
Cross-project shell where you constantly use one API keyB. Shell integration
Agent that picks tools dynamically, unknown secrets in advanceC. MCP server
CI/CD pipelineA. op run with service account token
Multi-tenant SaaS, per-customer API keysC. MCP server with vault-per-tenant

The patterns are composable. A typical production setup uses B for personal keys (Anthropic, OpenAI), A for project secrets (database URLs, third-party APIs), and C when agents need just-in-time access to a broader vault.

Comparison: 1Password CLI vs Alternatives

ToolAuth ModelLocal CacheMCP NativeAudit LogFree TierBest For
1Password CLIVault-based, biometric unlockYes (encrypted)Yes (official)Per-secret access log14-day trial, then paidDeveloper-first teams already on 1Password
DopplerAPI tokenNoCommunity MCPYesFree up to 5 usersMulti-environment SaaS deployment
InfisicalAPI tokenNoCommunity MCPYesSelf-hostable, freeSelf-hosted teams, kubernetes
HashiCorp VaultToken / OIDC / certNoCommunity MCPEnterprise featureOSS freeLarge enterprises with existing Vault
SOPS + ageGPG / age keysN/A (file-based)NoGit historyFreeGit-native secrets, smaller teams
AWS Secrets ManagerIAMNoCommunity MCPCloudTrail$0.40/secret/monthAWS-only stacks

Key trade-offs:

  • 1Password CLI is the only option here with a polished GUI that non-developers can use. If your team includes designers, PMs, or contractors who need access to subsets of secrets, 1Password’s UX matters.
  • Doppler / Infisical are environment-first (dev/staging/prod separation built in). 1Password’s vault model can replicate this with naming conventions, but it is not as native.
  • HashiCorp Vault is overkill for teams under ~20 engineers. It is the right answer at scale but requires dedicated operational effort.
  • SOPS is the simplest and cheapest. Use it if all your secrets are committed encrypted to Git and your team is comfortable with age/GPG key management.

For most Claude Code users (solo developers, small teams, agencies), 1Password CLI strikes the best balance of ergonomics, ecosystem (Touch ID, MCP server, mobile vault), and price. Start a free trial if you do not already have an account.

Common Pitfalls

Pitfall 1: .env referenced files not in .gitignore. Even though .env only contains op:// references (no plaintext), check that environment-specific overrides (.env.local, .env.production) are still gitignored. Misnaming a file .env.production.local.backup is a common way to commit a stale plaintext secret.

Pitfall 2: Forgetting to sign in. op run silently fails if you have not signed in this session. The command runs your program with the literal string op://... in the environment variable. Always verify with echo $VAR | head -c 20 after first injection.

Pitfall 3: Service account tokens in CI logs. Service account tokens unlock the vault without biometric prompts. They are full credentials — treat them as you would treat a root API key. Store them only in the CI provider’s secret store, never in committed configuration.

Pitfall 4: MCP server token rotation. The 1Password MCP server holds its service account token for the entire Claude Code session. If you rotate the token, you must restart Claude Code. There is no live-reload.

Pitfall 5: Subagent inheritance. Subagents spawned via the Task tool inherit the parent’s environment. If you injected secrets via Pattern B (shell integration), every subagent sees them. Use Pattern A or C if you want subagent-scoped access.

Real Production Patterns

Pattern: per-repo .env with team-shared vault. A .env checked into the repo with op:// references means new team members clone, run op run --env-file=.env -- npm run dev, and they are working. No more “what do I put for STRIPE_KEY?” questions in Slack.

Pattern: agent fanout with vault-scoped service accounts. For a Claude Code orchestrator that spawns subagents to handle different microservices, give each subagent a distinct MCP server configuration pointing at a different service account, each scoped to a single vault. The orchestrator never sees the subagent’s secrets.

Pattern: rotation without restart. Pattern C lets you rotate a key in 1Password’s vault, and the next agent turn reads the new value. Pattern A and B require a process restart. For long-running agent loops, Pattern C is the only safe choice.

FAQ

Does 1Password CLI work without the desktop app? Yes, but you lose biometric unlock. Without the desktop app, op signin prompts for your master password each session. Service account tokens work entirely headless.

Can I use op run in Docker? Yes. Build with 1password-cli installed, pass OP_SERVICE_ACCOUNT_TOKEN as a build/runtime env var, and prefix your CMD with op run --env-file=.env --. Do not mount your local 1Password app credentials into the container — use service accounts.

What is the difference between op run and op inject? op run resolves references at process spawn time and passes them as env vars. op inject substitutes references inside file content (e.g., generate a config file with secrets baked in). Use op run for processes; use op inject for one-off templated file generation. Do not commit the output of op inject.

Does 1Password CLI support secret rotation? Yes, but rotation is a vault operation (you update the value in 1Password). The CLI always reads the current value. There is no “rotate” subcommand because rotation is an upstream concern (e.g., calling Anthropic’s API to mint a new key, then updating the vault).

How do I share op:// references across team members without leaking vault structure? Use stable vault and item names that are agreed upon in your team’s onboarding doc. Avoid renaming items in 1Password — it breaks every op:// reference pointing at the old name. If you must reorganize, do it via op item edit --vault=NEW_VAULT rather than delete-and-recreate.

Can the 1Password MCP server access multiple vaults? Yes, if the underlying service account has access to multiple vaults. Best practice is to use vault-scoped service accounts per agent or per environment, so an exploited agent cannot escalate to other vaults.

Is op:// syntax standardized across 1Password products? Yes. The same op://VAULT/ITEM/FIELD syntax works in op run, op read, the 1Password Shell Plugins, the MCP server, and the Connect server. This is unusual stability for a secrets ecosystem — most competitors have changed reference syntax across versions.

What about Claude.ai (browser) — does this matter? Claude.ai (browser, no Claude Code) does not read your local filesystem. Secrets stored in 1Password CLI are only relevant when you are running Claude Code (the CLI) locally. The threat model only kicks in when an agent can read files.

Related Articles

Explore the collection

Browse all AI coding rules — CLAUDE.md, .cursorrules, AGENTS.md, and more.

Browse Rules