Skip to main content
Source: per-conversation-secrets/ OpenHands lets users store secrets in their vault for long-lived credentials. This example covers a different need: injecting a secret that belongs to one conversation only — for example, a customer’s OAuth token, a temporary CI credential, or a per-tenant API key.

Two Patterns

Pattern A — Secrets as Bash Environment Variables

Pass secrets at conversation-start time. The agent can then use $MY_KEY in any bash command it runs.
The secrets are available as environment variables in every bash command the agent runs, but are never stored in the conversation transcript.

Pattern B — Secrets as MCP Server Auth

The same secrets field also drives ${VARIABLE} expansion inside a plugin’s .mcp.json. When you ship a plugin with a placeholder like ${MCP_SECRET_TOKEN} in its MCP server config, OpenHands fills it in from the conversation’s secrets before dialing that MCP server.
.mcp.json inside the plugin
At conversation-start time, pass matching secrets:
OpenHands expands the placeholders before connecting to the MCP server. The token is never visible in the conversation transcript.

What Is a Plugin?

A plugin is a directory in a git repo with three files:
This example ships a working test-plugin/ in the repo — a ready-made plugin whose .mcp.json uses ${MCP_SERVER_URL} and ${MCP_SECRET_TOKEN}.

Quickstart

Mid-Conversation Injection (Legacy)

You can also inject secrets into a running conversation via the agent server’s /secrets endpoint. This is less common — most use cases are better served by passing secrets at conversation-start. See test_secrets.py for the implementation.

See Also