https://github.com/e4c6/keepassxc-dbus-mcp
KeePassXC Secret Service MCP server for credentials (KeePassXC D-Bus MCP)
https://github.com/e4c6/keepassxc-dbus-mcp
credentials dbus keepassxc mcp python secret-service security
Last synced: 5 months ago
JSON representation
KeePassXC Secret Service MCP server for credentials (KeePassXC D-Bus MCP)
- Host: GitHub
- URL: https://github.com/e4c6/keepassxc-dbus-mcp
- Owner: e4c6
- License: mit
- Created: 2025-08-30T19:56:28.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2025-09-11T14:44:26.000Z (9 months ago)
- Last Synced: 2025-09-11T17:30:47.825Z (9 months ago)
- Topics: credentials, dbus, keepassxc, mcp, python, secret-service, security
- Language: Python
- Size: 752 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# keepassxc-dbus-mcp
## At a Glance
- Helps your agent manage credentials (including ssh keypairs) in a KeePassXC DB group
- Provides tools:
- `get_credential_detail`
- `get_credential_secret`
- `get_credential_secret_as_temp_file`
- `create_credential`
- `update_credential`
- `delete_credential`
- `list_credentials`
- `search_credentials`
- `create_keypair`
- `save_keypair`
- `retrieve_keypair`
- `list_keypairs`
- `delete_keypair`
Enables:
- "Can you generate a ssh pair and copy it over to `host`?" --> Agent generates a ssh pair and saves it in vault, proceeds with task
- "Can you create dummy credentials for MSSQL and deploy it on docker?" --> Agent generate credentials in vault, references them as temporary files while deploying docker
Following system instructions is sufficient:
```
* **Credentials at vault:** use the credential helper tool to store new credentials and fetch existing ones when needed.
```
## Description
An MCP stdio server that brokers secure access to credentials stored in KeePassXC via the FreeDesktop.org Secret Service API. It exposes a minimal set of tools to list, search, create, update, delete, and securely retrieve secrets. Unlock requests always go through KeePassXC’s native approval prompts.
Why this exists: it lets local agents fetch secrets securely without copying them into env vars or logs. Secrets are never printed to stdout and plaintext retrieval is gated off by default. Primarily prevents my credentials leaking into LLM interactions and helps me set up secure development environments. Can potentially be used to rotate passwords in an agentic manner. I use it extensively and found value in it, so I decided to share.
## Quick Start
1) Prerequisites
- Python 3.10+
- KeePassXC with FreeDesktop Secret Service enabled
- `uv` for dependency and venv management
The server works across modern Linux desktops; ensure KeePassXC is the active Secret Service provider and that your session exposes the user D‑Bus (see the Codex CLI / D‑Bus section below).
2) Install
- Dev: `uv sync --extra dev`
- Runtime only: `uv sync`
3) Run (stdio MCP)
- `uv run -m keepassxc_dbus_mcp.mcp_server`
- or after install: `uv run keepassxc-dbus-mcp`
## KeePassXC Secret Service Settings
- Enable Secret Service: Settings → Secret Service → "Enable KeePassXC Freedesktop.org Secret Service integration".
- Authorization tab: enable all of the following for best safety when using agents:
- Show notification when passwords are retrieved by clients
- Confirm when passwords are retrieved by clients
- Confirm when clients request entry deletion
- Prompt to unlock database before searching
These settings ensure human-in-the-loop confirmations and visibility whenever an agent accesses or deletes secrets.
Hardening (suggested): you can expose only a specific group to the Secret Service rather than the entire database. Create a group (for example, "System Exposed") and select it under "Exposed database groups" in KeePassXC.
## Tools
Use these from your MCP client.
- `list_credentials()` → `[{ path, label, attributes }]`
- `get_credential_detail(credential_path)` → attributes dict or 404
- `search_credentials(q)` → contains-based list
- `create_credential({ label, password, username?, url?, notes?, attributes? })` → `{ path }`
- `update_credential({ credential_path, label?, password?, username?, url?, notes?, attributes? })`
- `delete_credential(credential_path)`
- `get_credential_secret_as_temp_file(credential_path, timeout=60)` → `{ temp_file_path }`
- `get_credential_secret(credential_path)` → gated by env variable
## SSH Keypairs
Two‑item aggregate linked by `KeypairID`.
- `create_keypair({ label, email, passphrase?, generate_passphrase?, algorithm='ed25519' })` → `{ keypair_id, private_path, meta_path, fingerprint, public_key_ssh }`
- `save_keypair({ keypair_id?, label, email, private_key_pem, public_key_ssh, passphrase?, algorithm })`
- `retrieve_keypair({ keypair_id? | credential_path?, include_passphrase?=false })` → `{ private_key_temp_file, passphrase_temp_file?, public_key_ssh, ... }`
- `list_keypairs()` → `[{ keypair_id, label, type, email, sha } ]`
- `delete_keypair(keypair_id)`
### Using passphrase‑protected private keys
- The `retrieve_keypair` tool returns temp file paths for both private key and passphrase (if any). You can use any SSH_ASKPASS program, or generate a tiny temp script that prints the passphrase from that file:
- Example: `ASKPASS=$(mktemp); printf '#!/usr/bin/env bash\ncat "$SSH_KEY_PASSPHRASE_FILE"\n' > "$ASKPASS"; chmod +x "$ASKPASS"`
- Then run: `SSH_ASKPASS_REQUIRE=force SSH_ASKPASS="$ASKPASS" SSH_KEY_PASSPHRASE_FILE=/path/to/pass.tmp ssh -i /path/to/priv.tmp user@host`
- Remove the temp script and files when done.
### SSH Keypair Storage Model
- Each SSH keypair is stored as an aggregate consisting of two Secret Service items linked by a shared `KeypairID`:
- Private item:
- Secret: the private key (OpenSSH PEM)
- Attributes: `Aggregate=ssh-keypair`, `Part=private`, `KeypairID=`, `Algorithm=ed25519`, `Fingerprint=SHA256:...`, `Email=` (also mirrored in `UserName`), `Title=`
- Meta item:
- Secret: the passphrase (empty if none)
- Attributes: `Aggregate=ssh-keypair`, `Part=meta`, `KeypairID=`, `Algorithm=ed25519`, `Fingerprint=SHA256:...`, `PublicKeyOpenSSH=`, `Email=`, `Title=`
- Rationale: secrets are cleanly separated (private key vs. passphrase), and both remain first-class Secret Service items that KeePassXC can manage (unlock prompts, approvals). We avoid stuffing binary material into attributes.
- What you’ll see in KeePassXC: two entries with the same title/username; one is the private part, the other is the meta part. They belong together. The server groups them using `KeypairID`.
- How to work with them:
- Discover: `list_keypairs()` shows `{ keypair_id, label, type, email, sha }` for quick selection.
- Use: `retrieve_keypair()` gives temp file paths for private key and (optionally) passphrase.
- Update: `save_keypair()` can create new or update an existing pair by `keypair_id` and keeps both entries in sync.
- Delete: remove both entries with the same `KeypairID` (call `delete_credential` for each path). A dedicated delete-keypair tool can be added if needed.
## Environment Variables
- `LOG_LEVEL`: Default `INFO`. Use `DEBUG` for troubleshooting (still stderr).
- `ALLOW_PLAINTEXT_SECRET`: Default `false`. Set to `true` only for trusted local use or tests.
- `PREFER_SHM`: Default `true`. When enabled, secrets are written to a temp file on `/dev/shm` (tmpfs) if available, minimizing disk persistence. If `/dev/shm` is not writable, the helper automatically falls back to the system temp directory.
## Codex CLI / D‑Bus Environment
- Errors: “No D‑Bus session bus” or “org.freedesktop.secrets not provided by any .service files”
- Why: the helper connects to KeePassXC through the FreeDesktop.org Secret Service on the user’s D‑Bus session bus. When sessions are launched by tools (e.g., Codex CLI, tmux, systemd units, SSH), `DBUS_SESSION_BUS_ADDRESS` and/or `XDG_RUNTIME_DIR` may be missing. In that case, `secretstorage` cannot reach the bus and you’ll see errors like “No D‑Bus session bus” or “org.freedesktop.secrets not provided by any .service files”.
- Fix: ensure your agent/CLI session inherits the user bus:
- `XDG_RUNTIME_DIR=/run/user/` (1000 on most single‑user desktops)
- `DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user//bus`
- KeePassXC must be running and providing Secret Service (see settings above).
- Codex example (`config.toml`):
```toml
[mcp_servers.credential-store]
command = "uv"
args = ["--directory", "/home/keepassxc-dbus-mcp", "run", "-m", "keepassxc_dbus_mcp.mcp_server"]
## Tip: echo $XDG_RUNTIME_DIR and $DBUS_SESSION_BUS_ADDRESS in your shell and
env = { XDG_RUNTIME_DIR = "/run/user/1000", DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/user/1000/bus"}
```
## Field Mapping Notes
- KeePassXC exposes default entry fields via Secret Service using exact, case‑sensitive keys: `Title`, `UserName`, `URL`, `Notes` (and `Password`, which is retrieved separately as the secret).
- Simplified model: typed fields (`label`, `username`, `url`, `notes`) populate canonical keys. The `attributes` bag is for custom keys only; reserved keys are ignored.
- Reserved keys: `Title`, `UserName`, `URL`, `Notes`, `Aggregate`, `Part`, `KeypairID`, `Algorithm`, `Fingerprint`, `Email`, `PublicKeyOpenSSH`.
## Screenshots (flow overview)
- Access request: database interactions trigger the KeePassXC prompt. You can choose not to remember and reset remembered decisions at any time.
- Search credentials: quick free‑text query showing attributes returned by `search_credentials`.
- Retrieve secret to a temp file: using `get_credential_secret_as_temp_file` — secrets never hit stdout; files auto‑delete after the timeout.
- Safe usage in function calls:
## Tested Environment
- OS: Ubuntu 24.04.3 LTS (Noble)
- Kernel: Linux 6.8.0-64-generic x86_64
- Desktop: GNOME Shell 46.0 (X11 session; `XDG_SESSION_TYPE=x11`)
- Secret Service provider: KeePassXC 2.7.10