Skip to main content

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:

  1. HOLSTER_DOCTOR_BIN
  2. Packaged wheel binary at holster_mcp/bin/holster-doctor
  3. holster-doctor on PATH
  4. Repo-local target/release/holster-doctor
  5. 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:

  1. license_key argument passed to a paid MCP tool
  2. HOLSTER_LICENSE_KEY
  3. ~/.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:

  1. explicit tool argument where supported
  2. HOLSTER_VAULT_PATH
  3. ~/.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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

holster_mcp-0.1.0.tar.gz (18.8 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

holster_mcp-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

holster_mcp-0.1.0-cp311-cp311-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

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

Hashes for holster_mcp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 07fd8d04e7c88557a7e45d2c0ad6e3e405801845c886bdefc9233249144e0fef
MD5 c510f44357a7187aeee488e719c1170f
BLAKE2b-256 5dcbccfcab8cd8b9a09c2d7e70652888d79bf6b1b1c055f0a8b6cace55d285a8

See more details on using hashes here.

Provenance

The following attestation bundles were made for holster_mcp-0.1.0.tar.gz:

Publisher: pypi.yml on nauta-ai/holster

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file holster_mcp-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for holster_mcp-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9ba76d634eced363de9525ab27184b76287209ed0a0b8dfcbd6491c0ab4146ea
MD5 9ab7f694d853e0022956268b0c228801
BLAKE2b-256 96e9831a59d5430e7ad50880982537d02305288da1cbf78609c5b0a680d6ddb1

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file holster_mcp-0.1.0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for holster_mcp-0.1.0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 837da5d83afb620e1633434cf25848344d813fd3ddb3b870b30ab7e8c887f9df
MD5 7eea0eec0b42ae084d5a469f78e8c89a
BLAKE2b-256 d24e430ff414d7336b9939cb5983b4bc3ba4db5fe8f80544bc757e0776092ac9

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page