Give AI agents the use of your secrets without the values: named secrets in the OS keyring, with Vault as a replica, injected into a command and redacted from its output. CLI + MCP + guard hook.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
- !Install pipes a remote script into a shell (curl | sh)
claude mcp add sealkeep -- npx -y @munhq/sealkeep{
"mcpServers": {
"sealkeep": {
"command": "npx",
"args": ["-y", "@munhq/sealkeep"],
"env": {
"STRIPE_SECRET_KEY": "<stripe_secret_key>",
"GITHUB_TOKEN": "<github_token>"
}
}
}
}STRIPE_SECRET_KEYGITHUB_TOKENResumen de MCP Servers
<p align="center"><img src="docs/brand/banner.png" alt="sealkeep: your agent uses the key, it never sees it" width="100%"></p>
<p align="center">
<a href="https://www.npmjs.com/package/@munhq/sealkeep"><img alt="npm" src="https://img.shields.io/npm/v/@munhq/sealkeep?color=a3122f"></a>
<a href="https://registry.modelcontextprotocol.io/v0/servers?search=io.github.munhq/sealkeep"><img alt="MCP registry" src="https://img.shields.io/badge/MCP_registry-io.github.munhq%2Fsealkeep-a3122f"></a>
<a href="https://github.com/munhq/sealkeep/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/munhq/sealkeep/actions/workflows/ci.yml/badge.svg"></a>
<a href="https://smithery.ai/servers/munhq/sealkeep"><img alt="Smithery" src="https://img.shields.io/badge/Smithery-munhq%2Fsealkeep-a3122f"></a>
<a href="LICENSE"><img alt="MIT" src="https://img.shields.io/badge/licence-MIT-a3122f"></a>
</p>
<p align="center">
[](cursor://anysphere.cursor-deeplink/mcp/install?name=sealkeep&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBtdW5ocS9zZWFsa2VlcCJdfQ==) [](vscode:mcp/install?%7B%22name%22%3A%22sealkeep%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40munhq%2Fsealkeep%22%5D%7D)
</p>
# sealkeep
sealkeep lets an AI agent use your secrets without seeing them.
You keep each secret one time, under a name such as `shared/stripe/test/SECRET_KEY`. The agent finds the name with `sealkeep list`, and runs a command with it. It never reads the value, and it never has to ask you for one.
The agent asks for a secret by its name. sealkeep puts the value into the environment of one command, runs the command, and replaces the value with `[sealkeep:NAME]` in all the output. The value does not go into the context, the transcript or a file.
```
agent ──► sealkeep run OPENROUTER_API_KEY -- sh -c 'curl -H "Authorization: Bearer $OPENROUTER_API_KEY" …'
│
├─ reads the value from a store ──► OS keyring (macOS Keychain, Secret Service, Windows Credential Manager)
│ └─► Vault KV v2 (a replica)
├─ starts the command with the value in its environment
└─ redacts the value from stdout and stderr ──► agent sees [sealkeep:OPENROUTER_API_KEY]
```
It has four parts:
1. **A CLI** (`sealkeep`): `set`, `list`, `run`, `import`, `scan`, `sync`, aliases and the store commands.
2. **An MCP server** (`sealkeep mcp`): the tools `list_secrets`, `run_with_secrets` and `store_status`. No tool returns a value.
3. **A guard hook** (`sealkeep guard`): it refuses the tool calls that would print a secret, for example `cat .env` or `sealkeep get`.
4. **A skill** that tells the agent when and how to use the CLI.
## Install
As an MCP server only (any client), the command is `npx -y @munhq/sealkeep`:
```json
{ "mcpServers": { "sealkeep": { "command": "npx", "args": ["-y", "@munhq/sealkeep"] } } }
```
In Claude Code, the plugin adds the MCP server, the skill and the guard hook in one step:
```
/plugin marketplace add munhq/sealkeep
/plugin install sealkeep@sealkeep
```
The full install below does the same for Claude Code, Codex and Cursor.
Linux and macOS:
```sh
curl -fsSL https://raw.githubusercontent.com/munhq/sealkeep/main/install.sh | sh
```
The script downloads the binary of the newest release, checks it against `SHA256SUMS`, copies it to `~/.local/bin`, and runs `sealkeep install`.
With Rust:
```sh
cargo install --locked --git https://github.com/munhq/sealkeep
sealkeep install
```
`sealkeep install` finds the AI clients on the machine. It adds the skill, the MCP server and the guard hook to each client:
| Client | Skill | MCP server | Guard hook |
|---|---|---|---|
| Claude Code (each config folder) | `<config>/skills/sealkeep` | `claude mcp add --scope user` | `<config>/settings.json`, PreToolUse on `Bash`, `Read`, `Grep` |
| Codex | `$CODEX_HOME/skills/sealkeep` | `codex mcp add` | `$CODEX_HOME/hooks.json`, PreToolUse (approve it one time with `/hooks`) |
| Cursor | `~/.cursor/skills/sealkeep` | `~/.cursor/mcp.json` | `~/.cursor/hooks.json`, beforeShellExecution |
Options: `--client claude,codex` installs into the named clients only. `--dry-run` shows the plan. `--no-skills`, `--no-mcp` and `--no-hooks` leave out a part. Before sealkeep changes a JSON file, it writes a backup (`<file>.bak-<unix time>`). `sealkeep uninstall` removes what `install` added.
Run `sealkeep doctor` to check the stores and the clients.
## Names
A name is `<scope>/<project>/<env>/<KEY>`:
| Part | Values | Example |
|---|---|---|
| scope | Who owns the secret: `personal`, the name of an employer or a client, or `shared` for one account that several scopes use | `personal`, `acme`, `shared` |
| project | The repository or the service | `example-app`, `stripe`, `ovh` |
| env | `prod`, `dev`, `test`, `local`. Leave it out when the secret has no environment (the API key of an account) | `prod` |
| KEY | The environment variable that the program reads | `DATABASE_URL` |
Folders are lower case (`a-z`, `0-9`, `.`, `_`, `-`). The key is upper case (`A-Z`, `0-9`, `_`) and is the variable that `run` sets.
```
personal/example-app/prod/DATABASE_URL
personal/example-app/dev/DATABASE_URL
personal/example-app/dev/STRIPE_SECRET_KEY -> shared/stripe/test/SECRET_KEY (alias)
acme/ovh/ovh-eu/APPLICATION_KEY
acme/cloudflare/API_TOKEN
shared/stripe/test/SECRET_KEY
shared/openrouter/API_KEY
```
**One value, one name.** When two projects use the same account, store the value one time under `shared/…`, and make an alias in each project folder. The project folder then has every variable that the project needs, and a rotation changes one value.
### Store a secret
```sh
sealkeep set shared/openrouter/API_KEY -d "OpenRouter, the main account" # writes to every store
```
sealkeep asks for the value two times, with no echo. To pipe a value in, use `--stdin`:
```sh
some-password-tool show openrouter | sealkeep set shared/openrouter/API_KEY --stdin
```
To find the secrets on a machine, run `scan`. It prints the path of each `.env` file, its key names, a class for each key (`secret`, `config` or `empty`), and a group number for each value that is in more than one place. It never prints a value. It also lists other files that often hold a credential, by path only:
```sh
sealkeep scan ~/code --max-depth 4
```
To copy a file into a folder:
```sh
sealkeep import ../example-app/.env --to personal/example-app/dev \
--map STRIPE_SECRET_KEY=shared/stripe/test/SECRET_KEY
sealkeep import ~/.ovh.conf --to acme/ovh # INI: one folder for each section
sealkeep set personal/github/PAT --from-file ~/.github-token
```
`import` reads dotenv files, and INI files (`.ini`, `.conf`, AWS `credentials`). It prints the names only. `--map KEY=NAME` stores the value at NAME and makes the project key an alias of it. If NAME already has a different value, `import` stops and says so. After the import, delete the source file, or keep it out of the reach of the agent.
### Let the agent use it
Tell the agent what to do. The skill tells it to run `sealkeep list` for the names, and `sealkeep run` for the command:
```sh
sealkeep run shared/openrouter/API_KEY -- sh -c 'curl -sS -H "Authorization: Bearer $API_KEY" https://openrouter.ai/api/v1/key'
sealkeep run --all personal/example-app/dev -- npm run dev
sealkeep run -e GITHUB_TOKEN=personal/github/PAT -- gh api user
```
A name sets the variable named by its key. `--all FOLDER` sets one variable for each secret in the folder, the same as a `.env` file. `--recursive` also takes the subfolders; two secrets with the same key are then an error. `-e VAR=NAME` sets a variable with a different name. `STORE:NAME` reads from one store only.
For a tool that reads its secrets from a file, `--dotenv` writes a temporary file that only you can read. The file is in `$XDG_RUNTIME_DIR/sealkeep` when it exists. sealkeep puts the path where the command has `{dotenv}`, and it removes the file when the command ends. This example gives Playwright MCP the login of a test account. The agent types the name `ADMIN_PASSWORD`, and Playwright puts in the value:
```sh
sealkeep run --dotenv personal/example-app/dev/ADMIN_EMAIL --dotenv personal/example-app/dev/ADMIN_PASSWORD \
-- npx @playwright/mcp@latest --secrets {dotenv}
```
`--secrets <path>` is an option of `@playwright/mcp` (see its README).
### See a value yourself
```sh
sealkeep get shared/openrouter/API_KEY
```
`get` works only when stdin and stdout are a terminal. An agent runs commands without a terminal, so `get` refuses, and the guard hook also refuses it.
## Stores
sealkeep looks up a bare name in the stores in the order of the config file. The first store that has the name gives the value.
The config file is `~/.config/sealkeep/config.toml` on Linux and `~/Library/Application Support/sealkeep/config.toml` on macOS. `$SEALKEEP_CONFIG` sets another path. With no file, sealkeep has one keyring store named `local`.
```toml
[[store]]
name = "local"
kind = "keyring"
[[store]]
name = "vault"
kind = "vault"
address = "http://127.0.0.1:{port}"
mount = "agent"
auth = "kubernetes"
role = "sealkeep"
jwt_command = ["kubectl", "-n", "vault", "create", "token", "sealkeep", "--duration", "10m"]
port_forward = ["kubectl", "-n", "vault", "port-forward", "svc/vault", "{port}:8200"]
[aliases]
"personal/example-app/dev/STRIPE_SECRET_KEY" = "shared/stripe/test/SECRET_KEY"
[guard]
block_dotenv = true
deny = ["vault kv get", "ansible-vault view"]
```
### The OS keyring
| OS | Store |
|---|---|
| macOS | the login Keychain |
| Linux, BSD | the Secret Service (GNOME Keyring, KWallet) on the session D-Bus |
| Windows | the Credential Manager |
Each secret is one entry with the service `sealkeep` and the secret name as the aLo que la gente pregunta sobre sealkeep
¿Qué es munhq/sealkeep?
+
munhq/sealkeep es mcp servers para el ecosistema de Claude AI. Give AI agents the use of your secrets without the values: named secrets in the OS keyring, with Vault as a replica, injected into a command and redacted from its output. CLI + MCP + guard hook. Tiene 1 estrellas en GitHub y su última actualización registrada es del 2026-10-12.
¿Cómo se instala sealkeep?
+
Puedes instalar sealkeep clonando el repositorio (https://github.com/munhq/sealkeep) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.
¿Es seguro usar munhq/sealkeep?
+
Nuestro agente de seguridad ha analizado munhq/sealkeep y le ha asignado un Trust Score de 87/100 (tier: Trusted). Revisa el desglose completo de comprobaciones superadas y flags en esta página.
¿Quién mantiene munhq/sealkeep?
+
munhq/sealkeep es mantenido por munhq. La última actividad registrada en GitHub es del 2026-10-12, con 0 issues abiertos.
¿Hay alternativas a sealkeep?
+
Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.
Despliega sealkeep en tu cloud
Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.
¿Mantienes este repo? Añade un badge a tu README
Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.
[](https://claudewave.com/repo/munhq-sealkeep)<a href="https://claudewave.com/repo/munhq-sealkeep"><img src="https://claudewave.com/api/badge/munhq-sealkeep" alt="Featured on ClaudeWave: munhq/sealkeep" width="320" height="64" /></a>Más MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
Reverse engineer anything with agents, from app behavior down to native binaries.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev