The key-smith for AI agents — forge, guard, and rotate secrets so plaintext never enters the agent's context.
Keysmith is an MCP server + CLI for AI-agent-safe secret management. It treats masking as the last line of defense and works structurally to keep secrets from leaking: encrypted residency, masked views, handle-passing, self-healing rotation, and short-TTL dynamic credentials.
Built with Go. Single static binary, zero runtime dependencies.
AI agents increasingly need credentials (API keys, tokens, DB URLs) to do
their work. But every time an agent reads a .env file, the plaintext leaks
into its context, logs, and session history — permanently.
Keysmith fixes this with a layered security model:
| Layer | Mechanism | What it prevents |
|---|---|---|
| Encrypted residency | age (X25519) encrypted store at rest | Plaintext on disk; even a leaked context is harmless (blobs are ciphertext) |
| Masked views | resources/tools return sk******ij form |
Credentials entering agent context |
| Handle-passing | put reads value from a temp file arg, not the transcript |
Plaintext in tool-call transcripts |
| Self-healing rotation | scan --rotate detects leaks, kills the leaked value |
Stale leaked credentials keep working |
| Short-TTL (Vault) | dynamic DB creds expire in 1h | Leaked credentials become worthless |
go install github.com/sscodeai/keysmith/cmd/keysmith@latest
# or build from source
go build -o bin/keysmith ./cmd/keysmithRun the server on stdio transport (the standard MCP server mode):
keysmith -store ~/.keysmith
# or via env:
KEYSMITH_STORE=/path/to/store keysmithServe over HTTP/SSE for remote agents:
keysmith -store ~/.keysmith -http :8080
# endpoint: http://localhost:8080/sseServe MCP 2025 Streamable HTTP (single POST endpoint, stateless):
keysmith -store ~/.keysmith -http :8080 -streamable
# endpoint: http://localhost:8080/mcpUse HashiCorp Vault as the backend (dynamic short-TTL secrets):
export VAULT_TOKEN=<token>
keysmith -store ~/.keysmith -vault http://127.0.0.1:8200Configure it in your MCP client (Claude Code, Cursor, etc.):
{
"mcpServers": {
"keysmith": {
"command": "keysmith",
"args": ["-store", "~/.keysmith"]
}
}
}The store directory is created on first run with 0600 permissions, holding:
key.txt— your age private key (NEVER share; keep0600)secrets.enc— armored age-encrypted secrets blob
In addition to the MCP server, keysmith works as a standalone CLI sharing the same store:
keysmith list # all keys, masked values
keysmith get API_KEY # masked value
keysmith get API_KEY --unsafe # plaintext (last resort)
keysmith set API_KEY < value.txt # value from stdin, no shell-history leak
keysmith rotate API_KEY 32 # generate + store new strong secret
keysmith delete API_KEY # remove a key
keysmith scan [--rotate] [repo-dir] # scan git history for leaked secretsVault-backed commands (with -vault):
keysmith -vault http://127.0.0.1:8200 vault-kv-set API_KEY < value.txt
keysmith -vault http://127.0.0.1:8200 vault-kv-get API_KEY # masked
keysmith -vault http://127.0.0.1:8200 vault-kv-list
keysmith -vault http://127.0.0.1:8200 vault-db-creds app-role # dynamic short-TTL DB creds| Tool | Description | Security property |
|---|---|---|
list |
All keys with masked values | Values never plaintext |
get |
Single key, masked value | Values never plaintext |
put |
Store a secret | Value read from value_file arg, temp file auto-removed |
rotate |
Generate + store a new strong random secret | Returns masked value only |
delete |
Remove a key | — |
| URI | Description |
|---|---|
secret://secrets |
Masked view of all secrets (safe to read into context) |
The bundled SKILL.md (in skill/) teaches agents to route ALL secret
operations through this server — never cat a .env, never echo a token.
The AGENTS.md at the repo root encodes the same rules for agents working
on this codebase itself.
How the pieces relate — core primitives vs the automation/transport layers built on top of them:
flowchart TB
subgraph Core["Core primitives"]
STORE[age encrypted store<br/>internal/store]
MASK[masking rules<br/>internal/mask]
SCAN[leak-scan + self-healing<br/>keysmith scan --rotate]
VAULT[Vault short-TTL creds<br/>internal/vault]
end
subgraph Auto["Automation"]
CRON[scheduled leak-scan<br/>scripts/scan-cron.sh]
end
subgraph Access["Access"]
STDIO[stdio]
SSE[SSE -http]
STREAM[Streamable -streamable]
end
SCAN -->|scheduled| CRON
STORE --> SCAN
MASK --> STORE
VAULT -.->|optional backend| STORE
STDIO -.-> SSE
SSE -.-> STREAM
| Layer | Capability | Relationship |
|---|---|---|
| Core | age store + mask + rotate + scan | foundational primitives |
| Automation | scripts/scan-cron.sh |
schedules scan --rotate |
| Access | stdio / SSE / Streamable | three transports, one server |
One line: core primitives provide the power, automation makes it run by itself, transports decide how agents connect.
- At rest: always age-encrypted (X25519), armor format. A plaintext file
never exists on disk. Atomic writes (temp + rename),
0600perms. - In context: masked values only. Masking keeps first/last 2 chars
(
sk******ij) so credentials are distinguishable without being revealed. - In transcripts:
putnever takes the plaintext as an argument — it reads a temp file path and deletes the file after. - Masking rules: key-name markers (SECRET/TOKEN/PASSWORD/API_KEY/DSN...), known value prefixes (sk-, ghp_, glpat-, xoxb-, JWT...), and high-entropy alphanumeric runs (≥20 chars mixing letters+digits, Shannon entropy ≥3.5). URL-shaped values are masked per-segment: userinfo password always masked, high-entropy path/query runs masked, host/port stay clear. Pure-numeric values (timeouts, retries) are never masked.
go test ./... # unit tests (mask + store + vault + leakscan)
go vet ./... # static checks
python3 e2e_test.py # full MCP protocol round-tripThe bundled scripts/scan-cron.sh runs keysmith scan --rotate on one or
more repos, printing one line only when leaks are found (and rotated) —
silent when clean. Wire it into any cron:
# every 6 hours, scan two repos; only alerts when leaks found+rotated
0 */6 * * * /path/to/keysmith/scripts/scan-cron.sh ~/.keysmith /repo1 /repo2- Vault backend (dynamic short-TTL secrets — leaked credentials expire)
- HTTP/SSE transport (for remote agent scenarios)
- CLI subcommands (add/get/rotate/scan without MCP)
- Streamable HTTP transport (MCP 2025 standard, single POST endpoint)
- Scheduled leak-scan watchdog script (cron-driven self-healing)
- Multi-tenant / team mode (share store across agents with audit log)
- Cloud credentials (AWS STS / GCP short-lived)
Apache-2.0