Secret Vault
БесплатноНе проверенLocal, encrypted password vault with AES-256-GCM and PBKDF2, exposing MCP tools for secure credential management, password generation, and search.
Описание
Local, encrypted password vault with AES-256-GCM and PBKDF2, exposing MCP tools for secure credential management, password generation, and search.
README
Local, encrypted password vault exposed as a Model Context Protocol (MCP) server. Secrets live on disk in AES-256-GCM ciphertext, unlocked by a master password derived via PBKDF2-HMAC-SHA256 (600,000 iterations). The master password is never written, never logged, and never transmitted.
Designed to be consumed by any MCP client (opencode, Claude Desktop, Cursor, etc.) via stdio transport.
Why
- Local-first: no network, no cloud, no telemetry.
- Strong crypto: AES-256-GCM with fresh 12-byte nonce per write; PBKDF2 with OWASP-recommended 600k iterations.
- MCP-native: all 8 vault operations are first-class tools the LLM can call.
- Auditable: ~87% test coverage, small surface, no exotic dependencies.
Tools
| Tool | Description | Inputs |
|---|---|---|
add_secret |
Add a new entry | name, username, password, url?, notes? |
get_secret |
Fetch an entry; password revealed only when reveal_password=true |
name, reveal_password=false |
list_secrets |
List all entries without exposing passwords | — |
update_secret |
Update one or more fields of an existing entry | name, username?, password?, url?, notes? |
delete_secret |
Remove an entry by name | name |
generate_password |
Generate a strong random password | length=20, upper=true, lower=true, digits=true, symbols=true, exclude_ambiguous=false |
search_secrets |
Case-insensitive substring search across name/url/username/notes |
query |
vault_status |
Vault metadata: entry count, last access timestamp, version | — |
All tools return JSON. Errors are returned as {"error": "..."} without stack traces or internal state.
Examples
Once registered in your MCP client, the 8 tools are available to the LLM. You invoke them with natural language — the client translates into MCP tools/call.
In opencode / Claude Desktop / Cursor (natural language):
# Store a secret
> add a secret called github with username felipe and password xK9!mP2qR8vN4wL7
# List everything (no passwords exposed)
> show me all my saved credentials
# Retrieve one (without exposing the password)
> get the github entry
# Retrieve and reveal
> get the github entry and show me the password
# Generate a strong password
> generate a 40-character password with symbols, no ambiguous characters
# Search across all fields
> find any entry that mentions "opencode"
# Update (rotate a password)
> rotate the password for the github entry to a new generated one
# Delete
> delete the entry called old-mailbox
# Status
> how many entries are in the vault and when was it last accessed?
Equivalent raw tool calls (what the client sends over JSON-RPC):
{ "method": "tools/call", "params": { "name": "add_secret",
"arguments": { "name": "github", "username": "felipe", "password": "xK9!mP2qR8vN4wL7" } } }
{ "method": "tools/call", "params": { "name": "list_secrets" } }
{ "method": "tools/call", "params": { "name": "get_secret",
"arguments": { "name": "github", "reveal_password": true } } }
{ "method": "tools/call", "params": { "name": "generate_password",
"arguments": { "length": 40, "symbols": true, "exclude_ambiguous": true } } }
{ "method": "tools/call", "params": { "name": "search_secrets",
"arguments": { "query": "opencode" } } }
{ "method": "tools/call", "params": { "name": "update_secret",
"arguments": { "name": "github", "password": "<new-generated>" } } }
{ "method": "tools/call", "params": { "name": "delete_secret",
"arguments": { "name": "old-mailbox" } } }
{ "method": "tools/call", "params": { "name": "vault_status" } }
Calling from a Python script (using the official mcp client):
import asyncio, os
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main():
params = StdioServerParameters(
command="/home/felipe/infra/secret-vault-mcp/.venv/bin/python3",
args=["-u", "/home/felipe/infra/secret-vault-mcp/server.py"],
env={**os.environ, "VAULT_MASTER_PASSWORD": "your-long-passphrase"},
)
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
await session.call_tool("add_secret", {
"name": "github", "username": "felipe", "password": "xK9!mP2qR8vN4wL7",
"url": "https://github.com",
})
result = await session.call_tool("get_secret", {
"name": "github", "reveal_password": True,
})
print(result.content[0].text)
asyncio.run(main())
Typical workflows:
# Onboarding: create a few entries
> store these credentials: github/felipe/<gen-32>, aws-root/admin/<gen-40>, redis-local/redis/<gen-24>
# Daily use: look up a password to paste into another tool
> get the aws-root entry and reveal the password
# Rotation: replace a weak/old password
> generate a 32-character password, then update the github entry with it
# Audit: what do I have stored?
> list all entries and group them by URL domain
# Cleanup: remove obsolete entries
> delete entries named "test-1", "test-2", and "demo"
Security Model
- Cipher: AES-256-GCM, 12-byte random nonce per encryption operation.
- KDF: PBKDF2-HMAC-SHA256, 600,000 iterations, 16-byte random salt.
- Storage layout (XDG Base Directory):
vault.enc— ciphertext, mode0600vault.salt— salt, mode0600vault.lock—flockfor inter-process serialization
- Concurrency:
flock(inter-process) +threading.RLock(intra-process re-entrant). - Atomic writes: temp file +
os.replace— no partial writes. - Master password: required at server start via
VAULT_MASTER_PASSWORD; never logged, never printed, never cached to disk. - Passwords in responses:
list_secretsalways returnspassword="".get_secretreturnspassword=""unlessreveal_password=true.
⚠️ Threat model: protects against at-rest disclosure of the vault files (e.g. disk theft, backup leakage). Does not protect against a compromised runtime or a malicious MCP client that calls
reveal_password=trueon your behalf. Treat the master password as the root of trust.
Setup
cd ~/infra/secret-vault-mcp
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env
# edit .env and set VAULT_MASTER_PASSWORD
Run
# via the MCP stdio transport (used by opencode/Claude Desktop/Cursor)
python server.py
# or with the master password inline
VAULT_MASTER_PASSWORD="my-long-passphrase" python server.py
Tests
pytest # 47 tests
pytest --cov=auth --cov=client --cov=models --cov=server
Current coverage: ~87% (target ≥80%).
File Layout (Runtime)
$XDG_DATA_HOME/secret-vault-mcp/ (default: ~/.local/share/secret-vault-mcp/)
├── vault.enc # AES-256-GCM ciphertext
├── vault.salt # 16-byte salt (0600)
└── vault.lock # flock file
Override the directory with XDG_DATA_HOME.
Project Layout
secret-vault-mcp/
├── auth.py # VaultConfig + constants (KDF, cipher, paths)
├── client.py # VaultClient (encrypt/decrypt, CRUD, lock, search, generate)
├── models.py # Pydantic models (SecretEntry, SecretUpdate, VaultState)
├── server.py # FastMCP server + tool definitions
├── tests/
│ ├── conftest.py
│ ├── test_auth.py
│ ├── test_client.py
│ └── test_server.py
├── pyproject.toml
├── .env.example
├── .gitignore
├── LICENSE
├── .github/workflows/ci.yml
└── README.md
Register in opencode
Add the following to ~/.config/opencode/opencode.jsonc:
{
"mcp": {
"secret-vault": {
"type": "stdio",
"command": "/home/felipe/infra/secret-vault-mcp/.venv/bin/python3",
"args": ["-u", "/home/felipe/infra/secret-vault-mcp/server.py"],
"env": {
"VAULT_MASTER_PASSWORD": "your-long-passphrase-here"
},
"enabled": true
}
}
}
🔐 Keep
VAULT_MASTER_PASSWORDout of version control. Consider using a secret loader (1Password CLI,pass, system keyring) to inject it at startup.
CI
GitHub Actions runs ruff + pytest on every push/PR and creates a GitHub release on push to main using ncipollo/release-action.
License
MIT © 2026 Felipe Moura (@n8nfelipe)
Установка Secret Vault
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/n8nfelipe/secret-vault-mcpFAQ
Secret Vault MCP бесплатный?
Да, Secret Vault MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Secret Vault?
Нет, Secret Vault работает без API-ключей и переменных окружения.
Secret Vault — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Secret Vault в Claude Desktop, Claude Code или Cursor?
Открой Secret Vault на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Secret Vault with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
