← all posts
the guide

MCP and Secrets: How AI Agents Should Handle Credentials

MCP secrets are safest when the server returns a result, not the value. 4 rules for an MCP server that provisions scoped API keys value-free, locally.

Shai Snir
mcp secretsmodel context protocolai agent securityapi key managementopen source

An MCP server handing a coding agent a 'minted, validated' receipt while the actual API key drops into a local .env.local, with Rocco guarding the value lane

Rocco built the MCP server so the agent gets a receipt, never the key. Good boundaries make good raccoons.

Rocco, the Ringtail bandit raccoon

🦝 Rocco: the tool call returns "done." the key goes in the drawer. the model reads the receipt.

The right way to handle secrets over MCP is to have the MCP server do the privileged work and return a result, not the secret value. Ringtail Keys is a local, open-source, MCP-native tool: your coding agent calls its MCP server to mint scoped API keys from the providers' official APIs, and the secret lands in .env.local and Infisical — value-free, so the credential never crosses the wire into the model's context.

What is MCP and why does it change how agents handle secrets?

The Model Context Protocol (MCP) is a standard way for a coding agent to call external tools — a server exposes actions, the agent invokes them, and results flow back into the model's context. That last part is the catch: anything an MCP tool returns becomes model context. If your MCP server hands back a raw sk_live_…, you've just piped a production secret into the transcript, the logs, and every downstream retry.

So MCP doesn't make secrets more dangerous — it makes the return value the thing to design carefully. A well-built MCP server treats "the secret" and "the result the agent needs" as two different objects. The MCP specification defines the transport; keeping values out of tool results is a discipline you layer on top.

How should an MCP server handle credentials?

Four rules keep an MCP server safe for secrets:

  • Return receipts, not values. A provision_key tool should return { variable: "STRIPE_SECRET_KEY", status: "minted", scopeValidated: true } — never the key string.
  • Do the privileged work server-side. The server calls the provider's official API and writes the secret to local files; the agent only triggers and confirms.
  • Run locally. An MCP server on your own machine means the secret never leaves your box for a rented middle server.
  • Scope every action. Mint least-privilege keys and require one human "allow" per provider, so a compromised agent session can't silently escalate.
Rocco, the Ringtail bandit raccoon

🦝 Rocco: if your tool returns the key, your logs collect keys. don't.

How does Ringtail's MCP server provision keys value-free?

Install and start the daemon, which exposes the MCP server:

curl -fsSL ringtail.sh | sh
ringtail up

Your coding agent — Claude Code, Cursor — connects to that MCP server and reads the variable names in .env.example. For each one it calls the server's provisioning tool. The server drives the provider's official API, the provider returns the secret to the server (local, on your machine), and the server writes it to .env.local and syncs to Infisical. The tool result the agent receives back is a status object: minted, scope validated. The value never traverses the MCP boundary into the model.

That's the whole design: the MCP call is the trigger, the local server holds the value, and the model gets a receipt. For the guarantee in isolation, see value-free credential provisioning, explained.

When should you use an MCP-native provisioning tool — and when not?

Use it when:

  • You live inside a coding agent and want it to set up infra without ever handling secret values.
  • You want the provisioning step to be a native tool call, not a copy-paste chore outside the agent.
  • You need least-privilege scoped keys minted per project via official APIs.
  • You want a local, open-source MCP server whose value-handling you can read and verify.

Don't reach for it when:

  • You want a hosted secrets vault to store keys you already have — that's storage; Ringtail vs Doppler covers where those fit.
  • You need a formal enterprise governance console with compliance reporting — Ringtail is a local acquisition tool.
  • A provider offers no key-minting API. Ringtail is honest: official APIs first, and a human handles the login where no API exists. There's no bot puppeting your dashboard.

Isn't it enough to just tell the agent "don't log the key"?

No — instructing a model to be careful is not a control, it's a hope. The secret is still in the context window, which means it's still subject to the runtime's logging, the inference provider's servers, and any error path that dumps context. A prompt saying "keep this private" doesn't remove the value from those systems.

Value-free MCP (Ringtail)"Return the key, ask nicely"
Secret crosses MCP boundaryNo — only a status objectYes — into model context
Where the value livesLocal server + .env.localModel context, then logs
EnforcementArchitectural (value never returned)A polite instruction
Scope per keyLeast-privilege, validated on mintWhatever you configured

The dependable control is architectural: never return the value. For the leak paths this closes, read why your AI agent shouldn't see your API keys, and for the hands-on version, how to give a coding agent API keys without leaking them.

What about MCP servers that need to use a secret, not just create it?

Some tools genuinely need to act with a credential — call an API on your behalf. The same principle holds: keep the secret inside the server and expose actions, not the value. A weather tool should expose get_forecast(city), using its API key internally, rather than returning the key so the agent can call the API itself. Ringtail's job is the acquisition step — minting and scoping the key — but the design rule generalizes: an MCP server's tools should be verbs the agent invokes, never a hand-off of the raw credential.

FAQ

How should AI agents handle secrets over MCP?

An MCP server should do the privileged work itself and return a result, not the secret value. When a coding agent calls a provisioning tool, the server should mint the key via the provider's official API, write it to local files, and return only a status like "minted, scope validated." Ringtail Keys works this way — it's an MCP-native, value-free tool, so the credential never crosses the MCP boundary into the model's context.

What are MCP secrets and why are they risky?

MCP secrets are credentials that flow through Model Context Protocol tool calls. They're risky because anything an MCP tool returns becomes part of the model's context, which can be logged, sent to inference servers, and replayed in error reports. The mitigation is to design tools that never return the raw value — Ringtail's MCP server returns a receipt while the secret lands in your local .env.local and Infisical.

Is Ringtail MCP-native?

Yes. Ringtail Keys exposes an MCP server that your coding agent connects to, so provisioning is a native tool call rather than a manual step. The agent triggers minting and confirms results, while the local server handles each provider's official API and keeps the secret values out of the model's context entirely.

Can an MCP server keep secrets out of the model context?

Yes, if it's designed to. The key is to have the server perform the privileged action and return only a status object, never the secret string. Ringtail Keys does exactly this: it runs locally, mints scoped keys via official APIs, writes values to .env.local and Infisical, and hands the agent back a "validated" receipt.

How do I set up Ringtail's MCP server?

Run curl -fsSL ringtail.sh | sh to install, then ringtail up to start the local daemon and its MCP server. Connect your coding agent to it, point it at a repo's .env.example, and it will mint each scoped key value-free — the values write to your local files while the agent only sees tool-call receipts. You approve one "allow" per provider the first time.

Rocco, the Ringtail bandit raccoon
that's the whole thing. want me to mint your keys like this — value-free, one allow per provider? i self-host in one command.