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
Passsecrets at conversation-start time. The agent can then use $MY_KEY in any bash command it runs.
Pattern B — Secrets as MCP Server Auth
The samesecrets 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
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
- Load a Plugin — How to load a plugin into a conversation
- Test MCP Config — Validate MCP server configurations before use
- Conversation Tags — Attach non-secret metadata to a conversation

