MCP server for Holster, a local-first secret vault with audit logs and agent tooling.
Project description
Holster MCP
Holster MCP exposes local Holster Doctor checks to MCP-compatible agents. The server is local-first: free tools shell out to the bundled holster-doctor binary and never send repository contents to a network service.
Install
From PyPI:
pip install holster-mcp
Development install:
cd /path/to/holster/mcp
python3.11 -m pip install -e '.[dev]'
Runtime command:
holster-mcp
MCP client config:
{
"mcpServers": {
"holster": {
"command": "uvx",
"args": ["holster-mcp"]
}
}
}
See the main Holster README for vault and holster-cli release binary installation.
License: MIT for the MCP package.
Binary Resolution
The server locates holster-doctor in this order:
HOLSTER_DOCTOR_BIN- Packaged wheel binary at
holster_mcp/bin/holster-doctor holster-doctoronPATH- Repo-local
target/release/holster-doctor - Repo-local
target/debug/holster-doctor
Free Tools
holster.scan_repo
Input:
{"path": "/absolute/repo/path", "depth": 3}
Output:
{
"ok": true,
"scanned_files": 15,
"findings": [
{
"file": "src/main.py",
"line": 12,
"secret_kind": "openai_api_key",
"severity": "error",
"suggestion": "Rotate this key and move it into a local vault."
}
]
}
holster.check_gitignore
Input:
{"path": "/absolute/repo/path"}
Output:
{
"ok": true,
"missing_patterns": [".env.local"],
"existing_safe": [".env"],
"existing_unsafe": [],
"suggested_append": ".env.local\n*.pem"
}
holster.rotation_playbook
Input:
{"provider": "github"}
Output:
{
"ok": true,
"provider": "github",
"steps": ["Create a replacement token...", "Update local consumers...", "Revoke the old token..."],
"estimated_minutes": 15,
"warnings": ["Do not revoke the old credential until the replacement has been verified."]
}
Platform Wheels
Day 1 wheels are built for:
- macOS ARM (
aarch64-apple-darwin) - Linux x86_64 (
x86_64-unknown-linux-gnu)
The wheels bundle the platform's holster-doctor binary and are intentionally not universal.
Paid Tools
Paid tools are local-only wrappers around holster-cli and are gated by a Holster license.
License Configuration
License lookup order:
license_keyargument passed to a paid MCP toolHOLSTER_LICENSE_KEY~/.holster/config.toml
Supported config.toml shapes:
license_key = "holster_live_ABCDEFGHIJKLMNOPQRSTUVWX"
vault_path = "/absolute/path/to/holster-vault.db"
or:
[license]
key = "holster_live_ABCDEFGHIJKLMNOPQRSTUVWX"
[vault]
path = "/absolute/path/to/holster-vault.db"
License cache:
~/.holster/licenses.db
If no license is configured, the first paid-tool call creates a local 7-day trial key with prefix holster_trial_.
Vault Configuration
Vault path lookup order:
- explicit tool argument where supported
HOLSTER_VAULT_PATH~/.holster/config.toml
holster.vault_add
Input:
{
"provider": "github",
"account": "nauta-ai",
"secret": "user-pasted-secret",
"label": "primary"
}
Output:
{"ok": true, "vault_entry_id": "123e4567-e89b-12d3-a456-426614174000", "error": null}
The secret value is never placed in CLI argv, logs, or structured error output.
holster.vault_rotate
Day 2 supports github and stripe.
Without new_secret, the tool returns the provider playbook and waits for the human to rotate/paste the replacement:
{
"provider": "github",
"account": "nauta-ai",
"vault_entry_id": "old-id"
}
With new_secret, the replacement is added to the local vault and the old entry is marked superseded when the installed CLI supports that command.
holster.audit_log
Input:
{"provider": "github", "account": "nauta-ai", "since_days": 30}
Output:
{"ok": true, "events": [{"ts": "...", "action": "add", "provider": "github", "account": "nauta-ai", "ok": true}]}
License Architecture
flowchart TD
A["Paid MCP tool call"] --> B["Resolve license key from arg/env/config"]
B --> C{"Key present?"}
C -- "No" --> D["Create local 7-day trial in ~/.holster/licenses.db"]
C -- "Yes" --> E["Read ~/.holster/licenses.db"]
D --> F{"Trial valid?"}
E --> G{"Cached license valid?"}
G -- "Valid" --> H["Dispatch paid tool"]
G -- "Expired but within 7-day grace" --> I["Dispatch with license_warning"]
G -- "Missing/stale live key" --> J["Stripe refresh: Customer.retrieve + Subscription.list"]
J -- "Active" --> K["Update cache valid_until + last_checked"]
J -- "Inactive/error/no API key" --> L["Return license_required_or_expired"]
F -- "Valid" --> H
F -- "Expired" --> L
K --> H
I --> H
H --> M["Local holster-cli subprocess"]
The background poller refreshes cached live licenses every 10 minutes after a paid tool validates. There is no webhook receiver in Day 2 and no telemetry in V1.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file holster_mcp-0.1.0.tar.gz.
File metadata
- Download URL: holster_mcp-0.1.0.tar.gz
- Upload date:
- Size: 18.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
07fd8d04e7c88557a7e45d2c0ad6e3e405801845c886bdefc9233249144e0fef
|
|
| MD5 |
c510f44357a7187aeee488e719c1170f
|
|
| BLAKE2b-256 |
5dcbccfcab8cd8b9a09c2d7e70652888d79bf6b1b1c055f0a8b6cace55d285a8
|
Provenance
The following attestation bundles were made for holster_mcp-0.1.0.tar.gz:
Publisher:
pypi.yml on nauta-ai/holster
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
holster_mcp-0.1.0.tar.gz -
Subject digest:
07fd8d04e7c88557a7e45d2c0ad6e3e405801845c886bdefc9233249144e0fef - Sigstore transparency entry: 1564214474
- Sigstore integration time:
-
Permalink:
nauta-ai/holster@27113e18d79015f47789b4e94d1ef100da88900c -
Branch / Tag:
refs/tags/mcp-v0.1.0 - Owner: https://github.com/nauta-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@27113e18d79015f47789b4e94d1ef100da88900c -
Trigger Event:
push
-
Statement type:
File details
Details for the file holster_mcp-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: holster_mcp-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.4 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ba76d634eced363de9525ab27184b76287209ed0a0b8dfcbd6491c0ab4146ea
|
|
| MD5 |
9ab7f694d853e0022956268b0c228801
|
|
| BLAKE2b-256 |
96e9831a59d5430e7ad50880982537d02305288da1cbf78609c5b0a680d6ddb1
|
Provenance
The following attestation bundles were made for holster_mcp-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
pypi.yml on nauta-ai/holster
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
holster_mcp-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
9ba76d634eced363de9525ab27184b76287209ed0a0b8dfcbd6491c0ab4146ea - Sigstore transparency entry: 1564214925
- Sigstore integration time:
-
Permalink:
nauta-ai/holster@27113e18d79015f47789b4e94d1ef100da88900c -
Branch / Tag:
refs/tags/mcp-v0.1.0 - Owner: https://github.com/nauta-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@27113e18d79015f47789b4e94d1ef100da88900c -
Trigger Event:
push
-
Statement type:
File details
Details for the file holster_mcp-0.1.0-cp311-cp311-macosx_11_0_arm64.whl.
File metadata
- Download URL: holster_mcp-0.1.0-cp311-cp311-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.3 MB
- Tags: CPython 3.11, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
837da5d83afb620e1633434cf25848344d813fd3ddb3b870b30ab7e8c887f9df
|
|
| MD5 |
7eea0eec0b42ae084d5a469f78e8c89a
|
|
| BLAKE2b-256 |
d24e430ff414d7336b9939cb5983b4bc3ba4db5fe8f80544bc757e0776092ac9
|
Provenance
The following attestation bundles were made for holster_mcp-0.1.0-cp311-cp311-macosx_11_0_arm64.whl:
Publisher:
pypi.yml on nauta-ai/holster
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
holster_mcp-0.1.0-cp311-cp311-macosx_11_0_arm64.whl -
Subject digest:
837da5d83afb620e1633434cf25848344d813fd3ddb3b870b30ab7e8c887f9df - Sigstore transparency entry: 1564214726
- Sigstore integration time:
-
Permalink:
nauta-ai/holster@27113e18d79015f47789b4e94d1ef100da88900c -
Branch / Tag:
refs/tags/mcp-v0.1.0 - Owner: https://github.com/nauta-ai
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@27113e18d79015f47789b4e94d1ef100da88900c -
Trigger Event:
push
-
Statement type: