A production-ready HashiCorp Vault Model Context Protocol (MCP) server built with Python and FastMCP. This server provides a comprehensive interface to Vault's KV secrets engine and policy management through the MCP protocol, enabling AI assistants to securely interact with Vault.
- π Full Secret Management - Create, read, update, delete, and list secrets
- π Policy Management - Create, read, delete, and list Vault policies
- π KV v1 and v2 Support - Automatic version detection and appropriate API usage
- π’ Enterprise Support - Namespace support for Vault Enterprise deployments
- π― Custom Mount Points - Works with any KV mount point (not hardcoded to
secret/)
- π‘οΈ Thread-Safe - Proper Vault client management for concurrent operations
- π Comprehensive Error Handling - Detailed error messages for debugging
- π MCP-Safe Logging - All logs to stderr, preserving stdout for MCP protocol
- π§ͺ Health Checks - Built-in connection and authentication verification
- π§ Flexible Configuration - Environment-based configuration for easy deployment
- Python 3.10 or higher
- HashiCorp Vault server (1.14.0+)
- Valid Vault token with appropriate permissions
- Clone the repository:
git clone https://github.com/democratize-technology/vault-mcp.git
cd vault-mcp- Run the setup script (creates virtual environment and installs dependencies):
./run_server.shSet the required environment variables:
# Required
export VAULT_ADDR=https://your-vault-server:8200
export VAULT_TOKEN=hvs.your-vault-token
# Optional - Core Settings
export VAULT_KV_MOUNT=secret # KV mount point (default: kvv2)
export VAULT_KV_VERSION=2 # KV version 1 or 2 (default: 2)
export VAULT_NAMESPACE= # Vault Enterprise namespace
export DEBUG=1 # Enable debug logging
# Optional - Security Settings
export VAULT_MCP_ENABLE_PERMISSION_CHECKS=true # Enable path/policy restrictions
export VAULT_MCP_ALLOWED_PATHS=apps/,users/ # Comma-separated allowed paths
export VAULT_MCP_READONLY=true # Enable read-only mode
export VAULT_MCP_ALLOW_POLICY_MGMT=true # Allow policy operations
# Optional - Rate Limiting
export VAULT_MCP_RATE_LIMIT_MAX=200 # Max requests per window (default: 100)
export VAULT_MCP_RATE_LIMIT_WINDOW=120 # Window in seconds (default: 60)Add to your Claude Desktop configuration (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"vault": {
"command": "/path/to/vault-mcp/run_server.sh",
"env": {
"VAULT_ADDR": "https://your-vault-server:8200",
"VAULT_TOKEN": "hvs.your-vault-token",
"VAULT_KV_MOUNT": "secret"
}
}
}
}Important: Vault secrets have a two-level structure that often causes confusion:
The path parameter specifies WHERE the secret is stored:
"apps/myapp/database"- A secret containing database credentials"users/alice/personal"- Alice's personal secret store"certificates/web-server"- Web server certificate data
Keys are the individual data fields INSIDE each secret:
- A secret at path
"apps/myapp/database"might contain keys:username,password,host - A secret at path
"certificates/web-server"might contain keys:cert,private_key,ca_bundle
- β
Correct:
read_secret(path="apps/myapp/database")returns the entire secret - β Wrong:
read_secret(path="apps/myapp/database/username")will fail - π‘ Access keys from response:
response.data.data["username"]
Create or update a secret in Vault.
# Create secret at path "apps/myapp/config" with multiple keys
create_secret(
path="apps/myapp/config", # β This is the secret PATH
data={
"api_key": "secret123", # β These are KEYS within the secret
"db_pass": "secure456",
"service_url": "https://api.example.com"
}
)Read a secret from Vault.
# Read entire secret at path "apps/myapp/config"
read_secret(path="apps/myapp/config")
# This returns ALL keys within the secret:
# {
# "data": {
# "data": {
# "api_key": "secret123",
# "db_pass": "secure456"
# }
# }
# }
# To access a specific key, extract from response:
# response.data.data["api_key"]
# β WRONG: Cannot access individual keys via path
# read_secret(path="apps/myapp/config/api_key") # This will fail!Delete a secret (soft delete for KV v2).
delete_secret(path="apps/myapp/config")List secrets at a given path.
list_secrets(path="apps/")Read metadata for a KV v2 secret.
read_secret_metadata(path="apps/myapp/config")Create or update a Vault policy.
create_policy(
name="app-readonly",
policy='path "secret/data/apps/*" {\n capabilities = ["read", "list"]\n}'
)Read an existing policy.
read_policy(name="app-readonly")Delete a policy.
delete_policy(name="app-readonly")List all policies in Vault.
list_policies()Generate a properly formatted policy string.
generate_policy(path="secret/data/apps/*", capabilities=["read", "list"])Get information about the current KV mount configuration.
get_mount_info()Check Vault connection and authentication status.
health_check()- "Create a secret at apps/production with database credentials"
- "Read the API keys from apps/myapp/config"
- "List all secrets under the apps/ path"
- "Create a read-only policy for the apps/production/* path"
- "Check if Vault is accessible and properly configured"
- "Generate a policy that allows read and list on apps/*"
# Create and activate virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install development dependencies
pip install -r requirements.txt
pip install -r requirements-dev.txt
# Run unit tests
pytest
# Run tests with coverage
make test-cov
# Run integration tests (requires Docker)
make test-integration
# Run linting and formatting
make lint format
# Run type checking
make typecheck
# Run security audit
make audit
# Run all quality checks
make quality-fullexport DEBUG=1- JSON Protocol Errors: Ensure all logging goes to stderr, not stdout
- Authentication Failed: Verify VAULT_TOKEN is valid and has appropriate permissions
- Mount Not Found: Check VAULT_KV_MOUNT matches your Vault configuration
- Connection Refused: Verify VAULT_ADDR is correct and Vault is running
For basic operation, the token needs these permissions:
# KV v2 operations
path "kvv2/data/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
path "kvv2/metadata/*" {
capabilities = ["read", "list", "delete"]
}
# Policy management
path "sys/policies/acl/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
# Health checks
path "sys/health" {
capabilities = ["read"]
}We welcome contributions! Please see our Contributing Guidelines for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
For security issues, please see our Security Policy.
- Built with FastMCP - The fast, Pythonic way to build MCP servers
- Powered by hvac - HashiCorp Vault API client for Python
- Part of the Model Context Protocol ecosystem
- π§ Email: [email protected]
- π Issues: GitHub Issues
- π¬ Discussions: GitHub Discussions
Made with β€οΈ by Democratize Technology