Content
# crowdsec-mcp
Read-only MCP server exposing CrowdSec Local API (LAPI) data as tools.
Runs on openclaw-pc (Ubuntu, user: dumaki) alongside existing MCP servers.
All tools are strictly GET-only. Credentials are read fresh from disk on every
call and never logged or cached in memory.
---
## Tools
| Tool | Description | Auth required |
|------|-------------|---------------|
| `crowdsec_get_decisions` | Active bans/decisions with optional type/origin filter | Bouncer key |
| `crowdsec_get_alerts` | Recent alerts with IP, scenario, time filters | Bouncer key (falls back to machine JWT) |
| `crowdsec_get_metrics` | Parser hits, scenario overflows, active decision counts | None (Prometheus) |
| `crowdsec_search_ip` | All decisions + alerts for a given IP, across all enrolled machines | Bouncer key |
| `crowdsec_get_bouncers` | Registered bouncers and last activity | Machine JWT |
| `crowdsec_get_machines` | Enrolled agent machines (canary-pi, ids-pi) and last heartbeat | Machine JWT |
---
## Installation (on openclaw-pc)
```bash
# Clone or copy the files
mkdir -p /home/dumaki/crowdsec-mcp
cd /home/dumaki/crowdsec-mcp
# Install Python dependencies (use a venv to keep things isolated)
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
```
---
## Step 1 — Generate a bouncer API key
Run this on **openclaw-pc** (the machine hosting the LAPI):
```bash
sudo cscli bouncers add crowdsec-mcp-readonly
```
Example output:
```
Api key for 'crowdsec-mcp-readonly':
<your-key-here>
Please keep this key since you will not be able to retrieve it!
```
Copy the key — it is shown only once.
---
## Step 2 — Obtain machine credentials (for bouncers/machines endpoints)
The `crowdsec_get_bouncers` and `crowdsec_get_machines` tools require a machine
(watcher) login/password rather than a bouncer key. Either register a new machine
or use the credentials of an existing enrolled machine.
To register a new read-only machine on the LAPI:
```bash
sudo cscli machines add crowdsec-mcp-machine --password 'choose-a-strong-password'
```
Note the machine ID (`crowdsec-mcp-machine`) and password you chose.
---
## Step 3 — Add credentials to the existing .env
**Append** to `/etc/sherman-executor/.env` — do not replace the file:
```bash
sudo tee -a /etc/sherman-executor/.env <<'EOF'
# CrowdSec LAPI — added for crowdsec-mcp
CROWDSEC_BOUNCER_API_KEY=<paste-bouncer-key-here>
CROWDSEC_MACHINE_LOGIN=crowdsec-mcp-machine
CROWDSEC_MACHINE_PASSWORD=<paste-machine-password-here>
# Optional: change if your CrowdSec Prometheus port differs from the default
# CROWDSEC_METRICS_PORT=6060
EOF
```
Verify the .env is not world-readable:
```bash
ls -la /etc/sherman-executor/.env
# Should show -rw------- or -rw-r----- (not world-readable)
```
---
## Step 4 — Register in OpenClaw MCP config
Edit the OpenClaw MCP configuration file. On openclaw-pc this is typically:
```
~/.config/openclaw/settings.json
```
or
```
~/.claude/settings.json
```
Add the `crowdsec` server entry inside the `mcpServers` object:
```json
{
"mcpServers": {
"crowdsec": {
"command": "/home/dumaki/crowdsec-mcp/.venv/bin/python3",
"args": ["/home/dumaki/crowdsec-mcp/server.py"]
}
}
}
```
If you are not using a venv, replace the command with the system Python:
```json
{
"mcpServers": {
"crowdsec": {
"command": "python3",
"args": ["/home/dumaki/crowdsec-mcp/server.py"]
}
}
}
```
Restart OpenClaw (or the agent process) to pick up the new server.
---
## Step 5 — Verify the server starts cleanly
```bash
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0"}}}' \
| /home/dumaki/crowdsec-mcp/.venv/bin/python3 /home/dumaki/crowdsec-mcp/server.py
```
You should see a JSON response with `serverInfo.name: "crowdsec"`.
---
## Testing each tool with curl
These commands test the underlying LAPI endpoints directly.
Replace `$BOUNCER_KEY` with your key or `export BOUNCER_KEY=<key>` first.
### Get current decisions (all)
```bash
curl -s -H "X-Api-Key: $BOUNCER_KEY" http://localhost:8080/v1/decisions | jq .
```
### Get decisions — bans only
```bash
curl -s -H "X-Api-Key: $BOUNCER_KEY" \
"http://localhost:8080/v1/decisions?type=ban" | jq .
```
### Get decisions — from CrowdSec community feed
```bash
curl -s -H "X-Api-Key: $BOUNCER_KEY" \
"http://localhost:8080/v1/decisions?origin=crowdsec" | jq .
```
### Get recent alerts (last hour)
```bash
curl -s -H "X-Api-Key: $BOUNCER_KEY" \
"http://localhost:8080/v1/alerts?since=1h" | jq .
```
### Get alerts for a specific scenario
```bash
curl -s -H "X-Api-Key: $BOUNCER_KEY" \
"http://localhost:8080/v1/alerts?scenario=crowdsecurity/ssh-bf" | jq .
```
### Search an IP address
```bash
IP="1.2.3.4"
echo "=== Decisions ==="
curl -s -H "X-Api-Key: $BOUNCER_KEY" \
"http://localhost:8080/v1/decisions?ip=${IP}" | jq .
echo "=== Alerts ==="
curl -s -H "X-Api-Key: $BOUNCER_KEY" \
"http://localhost:8080/v1/alerts?ip=${IP}" | jq .
```
### Get parser/scenario metrics (Prometheus — no auth)
```bash
curl -s http://localhost:6060/metrics | grep '^cs_'
```
For a cleaner summary of just bucket overflows (decisions triggered) by scenario:
```bash
curl -s http://localhost:6060/metrics \
| grep cs_bucket_overflowed_total \
| sort -t= -k2 -rn
```
### Get bouncers list (requires machine JWT)
First obtain a JWT:
```bash
JWT=$(curl -s -X POST http://localhost:8080/v1/watchers/login \
-H "Content-Type: application/json" \
-d '{"machine_id":"crowdsec-mcp-machine","password":"<your-machine-password>"}' \
| jq -r .token)
curl -s -H "Authorization: Bearer $JWT" \
http://localhost:8080/v1/bouncers | jq .
```
### Get machines list (requires machine JWT)
```bash
curl -s -H "Authorization: Bearer $JWT" \
http://localhost:8080/v1/machines | jq .
```
---
## Auth reference
| Endpoint | Auth type | .env variable(s) |
|----------|-----------|-----------------|
| `GET /v1/decisions` | Bouncer key (`X-Api-Key`) | `CROWDSEC_BOUNCER_API_KEY` |
| `GET /v1/alerts` | Bouncer key, falls back to machine JWT | Both sets |
| `GET /metrics` | None | — |
| `GET /v1/bouncers` | Machine JWT | `CROWDSEC_MACHINE_LOGIN`, `CROWDSEC_MACHINE_PASSWORD` |
| `GET /v1/machines` | Machine JWT | `CROWDSEC_MACHINE_LOGIN`, `CROWDSEC_MACHINE_PASSWORD` |
---
## Security notes
- The server performs **no write operations**. Every tool function calls `_assert_readonly("GET")`
before any network request, and the HTTP client uses `httpx.Client.get()` directly (not the
generic `.request()` method) so the method cannot be overridden at runtime.
- Credentials are read from disk via `python-dotenv` at the start of each tool call. No value
is stored in a module-level variable between calls.
- The server never prints, returns, or logs the API key or machine password.
- The `.env` file at `/etc/sherman-executor/.env` should be owned by root and readable only by
the processes that need it (mode `640` or tighter).
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
markitdown
Python tool for converting files and office documents to Markdown.
Filesystem
Node.js MCP Server for filesystem operations with dynamic access control.
TrendRadar
TrendRadar: Your hotspot assistant for real news in just 30 seconds.
mempalace
The highest-scoring AI memory system ever benchmarked. And it's free.
mempalace
The highest-scoring AI memory system ever benchmarked. And it's free.