Keyholder MCP is an MCP server over OpenBao. The agent sees credential and asks to run commands with them; the value is filled in only when the command runs (late binding), and the output comes back...
概要
Keyholder MCP is an MCP server over OpenBao. The agent sees credential and asks to run commands with them; the value is filled in only when the command runs (late binding), and the output comes back with the value masked. Access is temporary: a wrapped, single-use token with a TTL. Status: v0.3.0. Tested end to end against OpenBao 2.7.1; every tutorial is a real, re-checked run. Download keyholder-mcp (and the khcall debugging client) for Linux, macOS or Windows from Releases and check it against SHA256SUMS, or build it with Go 1.25+. You also need OpenBao. Then add keyholder-mcp to your MCP client with BAO_ADDR, BAO_WRAPPING_TOKEN, KEYHOLDER_SCOPE=my-project and KEYHOLDER_ALLOW=curl. Full walkthrough: Getting started. Client setup for Claude Code, Cursor and Codex: MCP clients. With OpenBao's AWS or GCP secrets plugin, credentials: ["aws:aws/creds/deploy"] gives the AWS CLI a key created for that run and revoked when it ends; gcp: gives gcloud an access token file.
README
Keyholder MCP
Let AI agents use your credentials without ever seeing them.
Português · Documentation · Tutorials
Keyholder MCP is an MCP server over OpenBao. The agent sees credential names and asks to run commands with them; the value is filled in only when the command runs (late binding), and the output comes back with the value masked. Access is temporary: a wrapped, single-use token with a TTL.
agent asks: curl -H "Authorization: Bearer {{vault://my-project/dev/API_TOKEN}}" https://api.example.com/health
agent reads: api says: hello, caller with header Authorization: Bearer [hidden:vault://my-project/dev/API_TOKEN]
Status: v0.3.0. Tested end to end against OpenBao 2.7.1; every tutorial is a real, re-checked run.
Tools
| Tool | Does | Returns |
|---|---|---|
keyholder_status |
Vault and session status | Sealed or not, remaining TTL, policies; never the token |
keyholder_list |
References in the project scope | vault:// names only |
keyholder_run |
Runs an allowed command with {{vault://...}} in args, env or files, and cloud credentials made for the run |
Exit code, masked stdout and stderr, references used |
Quick start
Download keyholder-mcp (and the khcall debugging client) for Linux, macOS or Windows from Releases and check it against SHA256SUMS, or build it with Go 1.25+. You also need OpenBao.
go build -o keyholder-mcp ./cmd/keyholder-mcp # or use a release binary
bao server -dev -dev-root-token-id=root-dev # in-memory, never with real secrets: see Persistent vault
export BAO_ADDR=http://127.0.0.1:8200 BAO_TOKEN=root-dev
bao kv put -mount=secret my-project/dev API_TOKEN=your-api-token
bao policy write my-project-read deploy/policy-project-read.hcl
bao token create -policy=my-project-read -ttl=8h -explicit-max-ttl=8h -wrap-ttl=5m -field=wrapping_token
Then add keyholder-mcp to your MCP client with BAO_ADDR, BAO_WRAPPING_TOKEN, KEYHOLDER_SCOPE=my-project and KEYHOLDER_ALLOW=curl. Full walkthrough: Getting started. Client setup for Claude Code, Cursor and Codex: MCP clients.
Cloud credentials
With OpenBao’s AWS or GCP secrets plugin, credentials: ["aws:aws/creds/deploy"] gives the AWS CLI a key created for that run and revoked when it ends; gcp: gives gcloud an access token file. See Cloud credentials.
Guarantees and limits
- Values never pass through MCP messages; the executed command does receive them, as any real use of a credential does.
- Commands run without a shell, only if named in
KEYHOLDER_ALLOW, and only with references insideKEYHOLDER_SCOPE. BAO_*,VAULT_*andKEYHOLDER_*never reach the child process.- Masking matches the exact value only. Never allow shells or interpreters (
sh,bash,python,env). - It does not protect against a hostile agent running as your own OS user.
Details: Security model.
How it compares
Other MCP servers for OpenBao and Vault (mcp-vault, openbao-mcp, HashiCorp’s vault-mcp-server) give the agent tools to read and manage the vault, so the model can receive secret values. Keyholder has no tool that reads a value: the agent only uses credentials, through commands, and reads masked output. Side by side, with sources: How it compares.
Documentation
| Page | Content |
|---|---|
| Getting started | From zero to an agent using a credential |
| Tutorials | Quickstart, temporary access, guardrails, masking, cloud, persistent vault; real outputs |
| Persistent vault | OpenBao with data on disk, TLS and unsealing, for real secrets |
| Configuration | Every variable, tool and field |
| Security model | What is protected and what is not |
| Architecture | Components, access flow, packages |
| Specification | Requirements, decisions, acceptance criteria, roadmap |
| Code review | AurumCode rules for security, review and SOLID |
The site sources are in docs/ (English) and docs/pt-BR/ (Portuguese).
Contributing
See CONTRIBUTING.md. Every pull request is reviewed by AurumCode with the rules in .aurumcode/skills/. Security issues: SECURITY.md.
License
MIT.
インストール
This server does not publish a one-line install command.
Open the repository installation guide