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.
# 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/- 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
- Access to a BunkerWeb API (default
http://localhost:8888)
# 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 .envpip install bunkerweb-mcpThe 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.
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
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 |
docker compose up --buildThe compose file maps host.docker.internal so the container can reach a locally running BunkerWeb API on port 8888.
uvicorn bunkerweb_mcp.main:app --host 0.0.0.0 --port 8080docker build -t bunkerweb-mcp .
docker run --rm -p 8080:8080 --env-file .env bunkerweb-mcpDeploy 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 -fKey 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.
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.
The server supports multiple transport protocols for MCP clients:
{
"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 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.
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 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.
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
The MCP server uses an AI-powered semantic search tool for BunkerWeb documentation via a remote search service.
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.0The 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 serviceTo run the MCP server without search:
# In .env
SEARCH_MODE=disabled
# In docker-compose.yml, comment out search-serviceQuery 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.
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.
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":{}}echo '{"id":"ping-1","tool":"ping","params":{}}' \
| websocat -H "Sec-WebSocket-Protocol: json" ws://localhost:8080/ws?token=$BUNKERWEB_WEBSOCKET_TOKENpip install -r requirements-dev.txt
pytestsrc/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
The MCP server includes comprehensive observability features:
Metrics are exposed at GET /metrics in Prometheus format:
curl http://localhost:8080/metricsAvailable 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
Distributed tracing with automatic instrumentation:
# Configure tracing via environment variables
OTEL_TRACING_ENABLED=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317Traces are automatically generated for:
- HTTP requests (FastAPI)
- Outgoing API calls (httpx)
- Tool executions
View traces in Jaeger UI at http://localhost:16686
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: 10Start the full observability stack (Prometheus, Grafana, Jaeger):
docker-compose -f docker-compose.monitoring.yml up -dAccess:
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000 (admin/admin)
- Jaeger UI: http://localhost:16686
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
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
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.
The MCP server includes several performance optimizations introduced in Sprint 2:
Enabled by default - Caches read-only API operations to reduce latency and load on BunkerWeb API.
# Configure in .env
CACHE_ENABLED=true # Default: trueCache 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).
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/minuteWhen enabled, exceeding rate limits returns HTTP 429 or WebSocket error.
For high-traffic deployments, increase Uvicorn workers:
# Docker environment variable
WORKERS=4 # Default: 1
# Local development
uvicorn bunkerweb_mcp.main:app --workers 4Kubernetes 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.
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.shPerformance 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/.
- 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
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:8085Critical: Include both hostname alone and with port (e.g., apps,apps:8085).
See docs/security.md for detailed configuration guide.
- 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.
- 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
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.
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
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
MIT