- Python 99.2%
- Dockerfile 0.7%
- Shell 0.1%
|
|
||
|---|---|---|
| .github/workflows | ||
| deploy | ||
| docs | ||
| n8n-workflows | ||
| prompts | ||
| scripts | ||
| src/bunkerweb_mcp | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .mcp.json | ||
| CLAUDE.md | ||
| docker-compose-mcp-only.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| pyproject.toml | ||
| pytest.ini | ||
| README.md | ||
| requirements-dev.txt | ||
| requirements.txt | ||
BunkerWeb MCP Server (Python)
A production-ready MCP server that exposes BunkerWeb's internal API to large language models via a constrained tool interface. The server provides both HTTP (for testing) and WebSocket (for MCP clients) JSON-RPC endpoints, strict input validation, and a resilient async client with retries.
Quick Start with Claude Code
# Install the package
git clone https://github.com/bunkerity/bunkerweb-mcp.git
cd bunkerweb-mcp
# For demo/testing you dont need to change anything
# Configure environment
cp .env.example .env
# Edit .env to set BUNKERWEB_BASE_URL
# Launch BunkerWeb Stack
docker compose up -d
# If you launch Claude in this repo, it will automatically read the .mcp.json file with mcp server url.
# You can then just launch Claude
claude
> List all BunkerWeb instances
> List my BunkerWeb services
> Review @config://global for security improvements
# If youu want to connect to a remote BunkerWeb mcp serveur
# We recommand to use BunkerWeb itself to protect the MCP service, and use SSL:
claude mcp add --transport http bunkerweb http://remote-ip:8080/mcp/
claude mcp add --transport http bunkerweb https://your-domain.com/mcp/
Features
- 37 comprehensive tools covering all BunkerWeb operations (instances, services, configs, bans, plugins, jobs, cache)
- 🔍 AI-powered semantic search in BunkerWeb Documentation via remote search service (optional, configurable)
- MCP resources for read-only data access (global config, job logs, active bans, instance status)
- Multiple transports: Stdio (for Claude Code), HTTP, WebSocket
- Official MCP SDK integration with FastMCP for compliant clients (Claude Code, VS Code, Claude Desktop)
- Robust async client with retry/backoff and typed Pydantic models
- Prompt catalog providing contextual guidance for each tool
- FastAPI app exposing
/rpcHTTP and/wsWebSocket JSON-RPC endpoints (legacy) - CLI entry point (
bunkerweb-mcp) for easy integration - Comprehensive documentation including CLAUDE.md with BunkerWeb expertise
- Optional authentication via shared-secret token or API bearer token
- Structured JSON logging with metrics for observability
- Unit tests with mocked HTTP transport
- Docker and Kubernetes deployment manifests
- ⚡ Performance optimizations (Sprint 2):
- Caching layer with configurable TTLs for read-only operations
- Optional rate limiting to protect against request floods
- Multi-worker support for high-traffic deployments
- Load testing suite with Locust for performance validation
Requirements
- Access to a BunkerWeb API (default
http://localhost:8888)
Installation
From Source
# Clone the repository
git clone https://github.com/bunkerity/bunkerweb-mcp.git
cd bunkerweb-mcp
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install in development mode
pip install -e .
# Or install from requirements
pip install -r requirements.txt
# Configure environment
cp .env.example .env
From PyPI (when published)
pip install bunkerweb-mcp
The requirements file pulls the MCP SDK directly from GitHub; ensure git is installed on the host before installing dependencies.
Update .env with your API base URL and either a token or basic credentials if required.
Development Context
The repository includes a CLAUDE.md file that provides Claude Code with comprehensive BunkerWeb expertise and best practices. This file is automatically loaded when working in this repository with Claude Code, giving the assistant context about:
- BunkerWeb architecture and components
- Security module configuration (ModSecurity, Antibot, etc.)
- Common operational workflows
- Troubleshooting guidelines
- Best practices for production deployments
Configuration
All settings are configurable via environment variables (see .env.example):
| Variable | Description | Default |
|---|---|---|
BUNKERWEB_BASE_URL |
Base URL to the BunkerWeb API | http://localhost:8888 |
BUNKERWEB_API_TOKEN |
Optional static bearer token | empty |
BUNKERWEB_BASIC_USERNAME |
Optional username for HTTP Basic auth | empty |
BUNKERWEB_BASIC_PASSWORD |
Optional password for HTTP Basic auth | empty |
BUNKERWEB_REQUEST_TIMEOUT_SECONDS |
HTTP timeout in seconds | 30 |
BUNKERWEB_MAX_RETRIES |
Retry attempts for transient failures | 3 |
BUNKERWEB_RETRY_BACKOFF_INITIAL |
Initial backoff delay (seconds) | 0.5 |
BUNKERWEB_RETRY_BACKOFF_MAX |
Maximum backoff delay (seconds) | 5.0 |
BUNKERWEB_WEBSOCKET_TOKEN |
Shared-secret required by /ws and /rpc |
empty |
BUNKERWEB_LOG_LEVEL |
Logging level | INFO |
BUNKERWEB_PROMPT_CATALOG |
Optional JSON file with per-tool prompts | built-in catalog |
RATE_LIMIT_ENABLED |
Enable rate limiting (Sprint 2) | false |
RATE_LIMIT_TOOLS |
Rate limit for /tools endpoint | 30/minute |
RATE_LIMIT_RPC |
Rate limit for /rpc endpoint | 100/minute |
RATE_LIMIT_WS |
Rate limit for WebSocket messages | 500/minute |
CACHE_ENABLED |
Enable caching layer (Sprint 2) | true |
WORKERS |
Number of Uvicorn workers (Docker only) | 1 |
Running the server
HTTP mode (recommended)
docker-compose
docker compose up --build
The compose file maps host.docker.internal so the container can reach a locally running BunkerWeb API on port 8888.
Local (uvicorn)
uvicorn bunkerweb_mcp.main:app --host 0.0.0.0 --port 8080
Docker
docker build -t bunkerweb-mcp .
docker run --rm -p 8080:8080 --env-file .env bunkerweb-mcp
Kubernetes
Deploy to Kubernetes with BunkerWeb ingress controller integration:
# Quick deployment
kubectl apply -f deploy/kubernetes/namespace.yaml
kubectl apply -f deploy/kubernetes/secret.yaml # Edit credentials first
kubectl apply -f deploy/kubernetes/configmap.yaml
kubectl apply -f deploy/kubernetes/deployment.yaml
kubectl apply -f deploy/kubernetes/service.yaml
# Optional: External access via BunkerWeb ingress
kubectl apply -f deploy/kubernetes/ingress.yaml
# Optional: Autoscaling and monitoring
kubectl apply -f deploy/kubernetes/hpa.yaml
kubectl apply -f deploy/kubernetes/servicemonitor.yaml
# Verify deployment
kubectl get pods -n bunkerweb
kubectl logs -n bunkerweb -l app=mcp-bunkerweb --tail=100 -f
Key features:
- BunkerWeb ingress controller with ModSecurity WAF and Antibot protection
- Horizontal Pod Autoscaler (2-10 replicas based on CPU/memory)
- Prometheus metrics and OpenTelemetry tracing
- Health checks with
/healthand/readyendpoints - Configurable via ConfigMap and Secrets
For detailed deployment instructions, troubleshooting, and configuration options, see deploy/kubernetes/README.md.
Stdio mode (recommended for local use)
If you installed the package locally (pip install -e .), Claude Code and VS Code can launch the server as a subprocess via stdio, without Docker.
Configuration examples for Claude Code, VS Code, and Claude Desktop are in the dedicated section: MCP integration > Stdio Transport.
Important: use the absolute path to the virtualenv binary in
command(get it withwhich bunkerweb-mcp). Relative commands can fail because MCP clients do not inherit your shell PATH.
MCP integration
The server supports multiple transport protocols for MCP clients:
Stdio Transport (Recommended for Claude Code and VS Code)
Claude Code — .mcp.json
{
"mcpServers": {
"bunkerweb": {
"type": "stdio",
"command": "/path/to/your/.venv/bin/bunkerweb-mcp",
"env": {
"BUNKERWEB_BASE_URL": "http://<bunkerweb-api-host>:8888",
"BUNKERWEB_API_TOKEN": "your-api-token-here"
}
}
}
}
VS Code — .mcp.json
VS Code uses servers (not mcpServers):
{
"servers": {
"bunkerweb": {
"type": "stdio",
"command": "/path/to/your/.venv/bin/bunkerweb-mcp",
"env": {
"BUNKERWEB_BASE_URL": "http://<bunkerweb-api-host>:8888",
"BUNKERWEB_API_TOKEN": "your-api-token-here"
}
}
}
}
Adapt command to your actual virtualenv path (which bunkerweb-mcp after activating it) and set BUNKERWEB_BASE_URL to your BunkerWeb API address.
For Claude Desktop, add the same block to your claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json, Linux: ~/.config/Claude/claude_desktop_config.json) — the type field can be omitted as Desktop defaults to stdio:
{
"mcpServers": {
"bunkerweb": {
"command": "/path/to/your/.venv/bin/bunkerweb-mcp",
"env": {
"BUNKERWEB_BASE_URL": "http://<bunkerweb-api-host>:8888",
"BUNKERWEB_API_TOKEN": "your-api-token-here"
}
}
}
}
Verify the server is detected by Claude Code:
claude mcp list
# bunkerweb: /path/to/your/.venv/bin/bunkerweb-mcp (stdio)
Note: The stdio transport runs the server as a subprocess communicating via stdin/stdout — no port, no Docker required.
HTTP Transport (For Remote Servers)
Point MCP-compatible clients at the streamable HTTP endpoint:
- Transport: Streamable HTTP
- URL:
http://localhost:8080/mcp
Configure in .mcp.json:
{
"mcpServers": {
"bunkerweb": {
"url": "http://localhost:8080/mcp",
"transport": "http"
}
}
}
Legacy Transports
Legacy JSON-RPC transports remain available for existing workflows:
- HTTP:
/rpcendpoint - WebSocket:
/wsendpoint
Use the BUNKERWEB_WEBSOCKET_TOKEN value when a client requires authentication; the same secret protects all transports.
MCP Resources
The server exposes read-only resources that can be referenced in Claude Code conversations using the @ syntax:
| URI | Description |
|---|---|
@config://global |
Current global BunkerWeb configuration |
@logs://jobs |
Scheduler job execution history |
@bans://active |
Currently active IP bans |
@instances://status |
Health status of all instances |
Example usage in Claude Code:
> Review @config://global and suggest security hardening improvements
> Check @bans://active for any suspicious patterns
Semantic Search
The MCP server uses an AI-powered semantic search tool for BunkerWeb documentation via a remote search service.
⚠️ IMPORTANT: The search functionality has been externalized to a separate service for better scalability and reduced image size. It is not yet available to the public
Configuration
Add to your .env file:
# Enable or disable search
SEARCH_MODE=disabled # 'remote' or 'disabled'
# Search service URL
SEARCH_API_URL=https://search.example.com
# Request timeout
SEARCH_TIMEOUT=10.0
Using with Docker Compose
The included docker-compose.yml runs both services:
# Start both MCP and search service
docker-compose up -d
# Check search service health
curl http://localhost:8000/health
# MCP server will automatically use search service
Disable Search
To run the MCP server without search:
# In .env
SEARCH_MODE=disabled
# In docker-compose.yml, comment out search-service
Tool catalogue
Query the /tools endpoint for JSON descriptors. Available tools include:
Documentation & Search:
search_bunkerweb_docs: Semantic search across BunkerWeb documentation (query,limit,category)
Instance Management:
ping: Check API reachabilityhealth: Read the API health probelist_instances: List registered BunkerWeb instancesreload_instances: Reload configuration across all instances (testflag supported)reload_instance: Reload a specific instance (hostname, optionaltest)
Security & Bans:
list_bans: Retrieve active bansban_ip: Ban one or multiple IPs (bansarray withip,exp,reason,service)unban_ip: Remove bans (bansarray withip, optionalservice)
Services:
list_services: List services (with_draftsflag)get_service: Fetch details for a specific service (service,full,methods,with_drafts)delete_service: Delete a service (service)
And 27 more tools covering configs, plugins, jobs, and cache management.
Each descriptor now carries a prompt field sourced from the prompt catalog. MCP clients can surface these short instructions to keep assistant answers consistent across tools.
Prompt catalog
The server ships with prompts/tool_prompts.json, a curated set of guidance strings keyed by tool name. At startup the catalog is loaded once and injected into tool descriptors as well as every RPC/WebSocket response. Override the location with BUNKERWEB_PROMPT_CATALOG if you need custom wording.
JSON-RPC usage
HTTP example
curl -X POST http://localhost:8080/rpc \
-H "Content-Type: application/json" \
-H "X-MCP-Token: $BUNKERWEB_WEBSOCKET_TOKEN" \
-d '{"id":"1","tool":"list_instances","params":{}}
WebSocket example (websocat)
echo '{"id":"ping-1","tool":"ping","params":{}}' \
| websocat -H "Sec-WebSocket-Protocol: json" ws://localhost:8080/ws?token=$BUNKERWEB_WEBSOCKET_TOKEN
Tests
pip install -r requirements-dev.txt
pytest
Project layout
src/bunkerweb_mcp/
├─ main.py # FastAPI app + JSON-RPC endpoints
├─ cli.py # CLI entry point for stdio mode
├─ mcp_adapter.py # MCP server integration
├─ client.py # Resilient async client for BunkerWeb
├─ tools.py # MCP tools with strict validation
├─ config.py # Environment-driven settings
├─ prompt_catalog.py # Prompt loading helpers
├─ exceptions.py # Domain-specific exceptions
├─ search_client.py # Lightweight HTTP client for search service
├─ schemas/ # Pydantic models for requests/responses
└─ utils/logging.py # Structured logging helpers
prompts/
└─ tool_prompts.json # Default tool prompts exposed to MCP clients
Observability
The MCP server includes comprehensive observability features:
Prometheus Metrics
Metrics are exposed at GET /metrics in Prometheus format:
curl http://localhost:8080/metrics
Available metrics:
mcp_tool_calls_total{tool_name, status}- Total tool calls by statusmcp_tool_duration_seconds- Tool execution duration histogrammcp_active_websockets- Active WebSocket connectionsbunkerweb_api_requests_total{endpoint, method, status}- BunkerWeb API requestsbunkerweb_api_errors_total{endpoint, error_type}- API errorsmcp_cache_hits_total{cache_type}- Cache hitsmcp_cache_misses_total{cache_type}- Cache missesmcp_search_queries_total{mode, status}- Search queries
OpenTelemetry Tracing
Distributed tracing with automatic instrumentation:
# Configure tracing via environment variables
OTEL_TRACING_ENABLED=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317
Traces are automatically generated for:
- HTTP requests (FastAPI)
- Outgoing API calls (httpx)
- Tool executions
View traces in Jaeger UI at http://localhost:16686
Health Checks
Liveness probe - Checks if the server is running:
curl http://localhost:8080/health
# Response: {"status": "healthy", "timestamp": "..."}
Readiness probe - Checks if the server can handle requests:
curl http://localhost:8080/ready
# Response: {"status": "ready", "checks": {"bunkerweb_api": true, "search_service": true}, "timestamp": "..."}
Kubernetes configuration:
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
Monitoring Stack
Start the full observability stack (Prometheus, Grafana, Jaeger):
docker-compose -f docker-compose.monitoring.yml up -d
Access:
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000 (admin/admin)
- Jaeger UI: http://localhost:16686
Grafana Dashboard
Pre-built dashboard with 8 panels:
- Tool Calls Rate
- Tool Success Rate
- Active WebSockets
- Tool Latency (P50/P95/P99)
- BunkerWeb API Errors
- Cache Hit Rate
- BunkerWeb API Latency
- Search Results Count
Import from deploy/grafana/dashboards/mcp-bunkerweb.json
Alerting
Pre-configured Prometheus alerts in deploy/prometheus/alerts.yml:
- High tool error rate (>10%)
- High latency (P95 > 5s)
- BunkerWeb API errors
- Low cache hit rate (<30%)
- Service health issues
Structured Logging
Logs are emitted as single-line JSON for ingestion by log processors. Each tool_call log carries a metrics object with the tool name and duration_seconds for latency tracking. Adjust BUNKERWEB_LOG_LEVEL as needed.
See docs/OBSERVABILITY.md for the complete observability guide.
Performance Tuning
The MCP server includes several performance optimizations introduced in Sprint 2:
Caching Layer
Enabled by default - Caches read-only API operations to reduce latency and load on BunkerWeb API.
# Configure in .env
CACHE_ENABLED=true # Default: true
Cache TTLs (configured in src/bunkerweb_mcp/cache.py):
list_services: 300s (5 minutes)global_config: 600s (10 minutes)list_instances: 60s (1 minute)list_bans: 30s (30 seconds)
Cache is automatically invalidated on write operations (create, update, delete).
Rate Limiting
Disabled by default - Optional protection against request floods.
# Enable in .env for production
RATE_LIMIT_ENABLED=true # Default: false
RATE_LIMIT_TOOLS=30/minute
RATE_LIMIT_RPC=100/minute
RATE_LIMIT_WS=500/minute
When enabled, exceeding rate limits returns HTTP 429 or WebSocket error.
Multi-Worker Deployment
For high-traffic deployments, increase Uvicorn workers:
# Docker environment variable
WORKERS=4 # Default: 1
# Local development
uvicorn bunkerweb_mcp.main:app --workers 4
Kubernetes resource allocation:
resources:
requests:
cpu: "100m" # Baseline for single worker
memory: "256Mi"
limits:
cpu: "500m" # Increase for multiple workers
memory: "512Mi"
Recommendation: Set WORKERS to CPU count × 2 for production deployments.
Load Testing
Verify performance with the included Locust test suite:
# Install locust
pip install -r requirements-dev.txt
# Run load test
./scripts/load-test.sh
# Or customize parameters
HOST=http://localhost:8080 USERS=200 RUN_TIME=10m ./scripts/load-test.sh
Performance targets (Sprint 2):
- Throughput: > 1000 req/s sustained
- P95 latency: < 100ms
- Error rate: 0% at 100 concurrent users
Reports are generated in ./load-test-reports/.
Performance Tips
- Enable caching (
CACHE_ENABLED=true) for read-heavy workloads - Disable rate limiting by default (set
RATE_LIMIT_ENABLED=false) unless under attack - Use multiple workers (
WORKERS=4) only for high traffic (>100 req/s) - Monitor cache hit rate via logs to tune TTLs
- Increase resources in Kubernetes based on load test results
Security notes
DNS Rebinding Protection (Important!)
The MCP server includes built-in DNS rebinding protection. You must configure allowed hosts:
# In your .env file - REQUIRED for production
MCP_ENABLE_DNS_REBINDING_PROTECTION=true
MCP_ALLOWED_HOSTS=yourdomain.com,yourdomain.com:443,internal-host,internal-host:8085
Critical: Include both hostname alone and with port (e.g., apps,apps:8085).
See docs/security.md for detailed configuration guide.
Other Security Best Practices
- Populate
BUNKERWEB_API_TOKENwhen the target API requires authentication. - When using HTTP Basic auth, set
BUNKERWEB_BASIC_USERNAMEandBUNKERWEB_BASIC_PASSWORDvia secrets management. - Set
BUNKERWEB_WEBSOCKET_TOKENto require a shared secret for both/rpcand/ws. - Ensure the MCP server runs on a trusted network; the API can modify BunkerWeb state.
- Use HTTPS via reverse proxy (nginx, Traefik, or BunkerWeb) in production.
Documentation
Project Documentation
- Architecture Decision Records (ADR) - Major architectural decisions with context and rationale
- Sprint 3: Maintenability - Code quality and documentation improvements
- Observability Guide - Complete guide to metrics, tracing, and monitoring (Sprint 4)
- Migration Guide - Guide for upgrading from v1.x to v2.x
- Security Guide - DNS rebinding protection and security best practices
- Claude Development Guide - BunkerWeb expertise for Claude Code
API Documentation
All tool handlers include comprehensive Google-style docstrings with:
- Detailed functionality description
- Parameter specifications with types and defaults
- Return value format documentation
- Exception handling guidance
- Usage examples
Example: src/bunkerweb_mcp/tools.py contains 40+ fully documented handlers.
Architecture Decisions
Key architectural choices are documented in ADRs:
- ADR-0001: FastMCP SDK - MCP protocol implementation
- ADR-0002: Externalize Search - Search service architecture
- ADR-0003: Pydantic V2 - Data validation framework
- ADR-0004: Async HTTPX - HTTP client choice
Contributing
See individual ADRs for architectural guidance when proposing changes. All new tool handlers must include:
- Complete Google-style docstrings
- Unit tests with >80% coverage
- Updates to relevant ADRs if architectural changes are involved
License
MIT