Skip to Main Content
Back to blog

Securing MCP servers with 1Password: Stop credential exposure in your agent configurations

by Nancy Wang and Robert Menke

November 19, 2025 - 4 min

Related Categories

If you’ve built anything with AI tools lately…

You’ve probably seen a file like this sitting in your project root:

{ "tools": {     "github": {       "endpoint": "https://api.github.com",       "auth": {         "token": "ghp_your-secret-token"       }     }   } }

That’s a typical mcp.json, the file many agentic development environments (like Cursor or Claude Code) use to tell an MCP server what APIs it can call and what credentials to use.

It’s handy. It works. It’s also a plaintext secret waiting to leak.

Push that repo to GitHub, sync it to a teammate, or even forget to .gitignore it, and your API key’s gone.

Shout-out: the developer who started a trend

One of the nicest parts of working in security is seeing the community invent safe patterns before vendors even document them.

A developer who goes by @codekiln wrote a great how-to showing how to secure Cursor’s mcp.json with the 1Password CLI.

Their approach is simple: instead of hardcoding tokens in your config, reference them from your 1Password vault and inject them at runtime using op run.

Here’s the core idea they shared:

op run --env-file=.env -- cursor mcp-server start

It’s small, but it changes everything. No plaintext credentials. No manual copy-paste. No tokens lying around in Git history.

You can read their full guide here: How to set up Cursor MCP with 1Password GitHub tokens.

“What 1Password is doing to secure agent configurations is exactly the future we envisioned when we created Hooks,” said Travis McPeak, Head of Security at Cursor. “Developers shouldn’t have to choose between security and productivity.” 

Pull secrets at runtime instead of storing them

This pattern works for any MCP or AI tool that uses environment variables for authentication: Cursor, Claude Code, local LangChain MCP servers, you name it.

You don’t have to wait for new SDKs or integrations. You can do it today with the 1Password CLI (op). Let’s walk through implementation: 

Step 1: Store your secrets in 1Password

Create a vault item for each token you need. For example:

  • Vault: AI

  • Item: GitHub Access Token

  • Field: token

Then grab that secret via a secret reference:

op read "op://AI/GitHub Access Token/token"

Format reminder:

op://<vault>/<item>/<field>

These are pointers, not real values. Only 1Password can resolve them when you launch a process with the CLI.

Step 2: Reference them in your .env

Your .env now looks like this:

GITHUB_TOKEN=op://AI/GitHub Access Token/token

OPENAI_API_KEY=op://AI/OpenAI Key/key

Each variable is a link to an encrypted secret, not the secret itself.

Step 3: Start your MCP server with op run

Wrap your command in op run to fetch and inject secrets at runtime:

op run --env-file=.env -- mcp-server start

Here’s what happens:

  1. op run reads your .env.

  2. It resolves any op:// references.

  3. It decrypts those secrets in memory.

  4. It sets them as environment variables for that process.

  5. When the process exits, the secrets disappear.

Verify it yourself:

op run --env-file=.env -- printenv | grep GITHUB_TOKEN

Outside of that shell, the token doesn’t exist.

Step 4: Keep mcp.json clean

Once your env variables are ready, your config can stay simple:

{   "tools": {     "github": {       "endpoint": "https://api.github.com",       "auth": { "token": "${GITHUB_TOKEN}" }     }   } }

You can safely version-control this file. No secrets, no cleanup commits.

Bonus: 1Password Environments (Beta)

If you want something more structured than local .env files, check out 1Password Environments.

It lets you define, sync, and rotate environment variables centrally across projects.

It’s still in beta but already works great alongside the CLI:

1password env init my-ai-project

op run --env-file=.env -- mcp-server start

Same security model, less config drift.

Why this works

Common problem

Fixed by

Plaintext secrets in code

Store them in 1Password vaults

Shared .env files

Use secret references

Secrets hanging around in memory

Decrypt only during process runtime

Manual rotation

Centralized management in 1Password

Audit gaps

Built-in logging and access control

You’re not changing how your dev tools work. Just how they get credentials.