Skip to main content
Glama
sec73
by sec73

Klaxon

The alarm tells you that. Klaxon tells you what.

Klaxon connects a language model directly to your Wazuh 5 cluster. You ask questions in plain language; it queries the indexer, reads the schema, tests decoders, and reports what it actually found — including when it found nothing, and why.

Works with Claude Desktop, Claude Code, and local models through Ollama. Nothing leaves your network: Klaxon runs beside your cluster and talks to it directly.


What you can use it for

Understand what your SIEM is actually collecting. Which fields carry data and which are mapped but always empty. How complete your normalisation is. Where a decoder is dropping information you assumed was there.

Investigate without writing queries. "Show me blocked connections by source country in the last 24 hours." "Which users logged in, and how many of those were over the network?" No query DSL, no dashboard clicking.

Debug decoders. Push a raw log line through the decoder chain and see which decoders matched, what they produced, and where the chain stopped.

Check before and after a change. Field coverage measured over a time window and over the whole datastream. When those two numbers diverge, something in your normalisation changed — a decoder fix, a new integration, a broken one.

Produce recurring reports. Findings by severity and agent, coverage per index — as fixed tools that a small local model can call reliably.

What it will not do

Klaxon is read-only. It queries, it never writes, deletes or reconfigures.

It has no concept of who is asking. Every request runs with the credentials in its environment, so anyone who can reach it can read everything those credentials can. Run it as wazuh-readonly, not admin.

It does not replace your dashboards, and it will not tell you what to do about what it finds.


Related MCP server: wazuh-mcp

Requirements

  • Wazuh 5.0 or later, indexer reachable over HTTPS

  • Python 3.11+

  • An MCP client — Claude Desktop, Claude Code, ollmcp, or any other

search and schema also work against a Wazuh 4.x indexer. The other tools are 5.x-specific.


Setup

1. Install

python3 -m venv .venv
.venv/bin/pip install klaxon-mcp

2. Configure

Copy .env.example to .env and fill in your endpoints:

WAZUH_INDEXER_URL=https://indexer.example:9200
WAZUH_INDEXER_USER=wazuh-readonly
WAZUH_INDEXER_PASSWORD=...

Only WAZUH_INDEXER_URL is required. Add WAZUH_MANAGER_URL for the manager tool and WAZUH_ENGINE_URL for tester_sessions — see Configuration.

3. Wrap it so the credentials stay in one place:

cat > run-klaxon.sh <<'EOF'
#!/usr/bin/env bash
set -a; . "$(dirname "$0")/.env"; set +a
exec "$(dirname "$0")/.venv/bin/klaxon-mcp"
EOF
chmod +x run-klaxon.sh

4. Register with your client

Claude Desktop~/.config/Claude/claude_desktop_config.json on Linux, ~/Library/Application Support/Claude/ on macOS:

{
  "mcpServers": {
    "klaxon": {
      "command": "/path/to/klaxon/run-klaxon.sh"
    }
  }
}

Restart Claude Desktop completely afterwards.

Claude Code:

claude mcp add klaxon /path/to/klaxon/run-klaxon.sh

Ollama — via ollmcp:

uv tool install --upgrade ollmcp
ollmcp mcp add klaxon -- /path/to/klaxon/run-klaxon.sh
ollmcp -m qwen3:14b

First questions to ask

Once connected, these work as plain prompts:

Which fields under wazuh.agent. are populated in network-activity?

How many events per category in the last 24 hours?

Show me the field coverage for event.* in network-activity.

Give me the findings overview for the last 48 hours.

Run this log line through the decoder chain: (paste a raw line)

A useful first move on an unfamiliar cluster is asking for field coverage on the index you care about. It tells you what is actually there before you build a question around a field that turns out to be empty.

Using a local model

Klaxon works with local models, but the two halves of the job are not equally easy for them.

Measured with Qwen3 14B at 32k context: calling a tool with fixed parameters and running simple aggregations is reliable. Writing nested query DSL by hand is not — it tends to invent .keyword suffixes and misplace sub-aggregations.

Two things help:

Use the fixed tools. findings_overview and field_coverage need no query DSL at all. field_coverage(index=..., prefix="event.") is a parameter fill, not a construction task.

Give it the field conventions. A short system prompt prevents most failures:

You work with Klaxon against a Wazuh 5 indexer.
- Never guess field names. Call klaxon.schema first for an unfamiliar index.
- The .keyword suffix does not exist in Wazuh 5.
- Agent data is under wazuh.agent.*, rule data under wazuh.rule.*.
  The time field is @timestamp.
- For questions about a specific action, first query the available
  event.action values, then filter on them.
- Read the DIAGNOSTICS block. An empty aggregation usually means
  wrong field, not no data.

Open-ended exploration — "find anything unusual" — is where local models fall short, because "unusual" needs a baseline they do not have. Ask specific questions instead, or use a stronger model for that part.


Tools

Tool

What it does

search

Any OpenSearch query against any index. Raw JSON back, aggregations included.

schema

Which fields exist, and which of them actually carry data.

field_coverage

How complete each field is — in a time window and over all history.

findings_overview

Findings by severity, agent, rule title and category.

logtest

Push a log line through the decoder chain and see what matched.

manager

Read-only access to the Wazuh manager API.

detectors

List and inspect Security Analytics detectors.

tester_sessions

Which logtest environments exist — the usual cause of a failing logtest.

Full parameter reference: docs/TOOLS.md. Design rationale: ARCHITECTURE.md.

One thing worth knowing up front

Klaxon always tells you when a result is thinner than it looks. An empty aggregation, a capped result set, a query against an index that does not exist — each gets a note before the data, because in OpenSearch all three come back as a perfectly successful HTTP 200 with nothing in it.

The most common case: agent.id exists in the Wazuh 5 schema and is never populated. The real field is wazuh.agent.id. Aggregate on the wrong one and you get zero buckets, no error, no warning — a result that looks like "no data" and means "wrong field". schema and field_coverage make that visible.


Configuration

All configuration is environment variables. Nothing is read from a config file and no credential is baked into the Docker image.

Variable

Default

WAZUH_INDEXER_URL

— (required)

WAZUH_INDEXER_USER / _PASSWORD

empty

WAZUH_MANAGER_URL

empty (disables manager)

WAZUH_MANAGER_USER / _PASSWORD

empty

WAZUH_ENGINE_URL

empty (disables tester_sessions)

WAZUH_VERIFY_SSL

true (setting it false logs a warning at startup)

WAZUH_TIMEOUT

60

WAZUH_SEARCH_MAX_SIZE

100 (0 disables the cap)

WAZUH_SCHEMA_FIELD_LIMIT

200

WAZUH_SCHEMA_PROBE_BATCH

100

WAZUH_LOGTEST_SPACE

custom

WAZUH_LOGTEST_TRACE_LEVEL

ASSET_ONLY

Those are three separate endpoints: the indexer, the manager API, and the engine's own HTTP server — the last runs inside the manager container but on a different port from the manager API.


Docker

docker build -t klaxon-mcp .
docker run --rm -i --env-file .env klaxon-mcp

-i is required: the server communicates over stdio.

If Wazuh runs on the Docker host itself, localhost inside the container is the container. Either add --add-host=host.docker.internal:host-gateway and use that hostname in .env, or run with --network host.


Running it on another machine

By default Klaxon speaks stdio and is started by your MCP client as a child process. To run it elsewhere — next to the Wazuh cluster, say — serve it over HTTP:

export WAZUH_MCP_AUTH_TOKEN=$(openssl rand -hex 32)
klaxon-mcp --transport http --host 0.0.0.0 --port 8000 \
           --allowed-host klaxon.example:8000
claude mcp add --transport http klaxon https://klaxon.example:8000/mcp \
  --header "Authorization: Bearer $WAZUH_MCP_AUTH_TOKEN"

Read this before opening the port

The tools have no concept of a caller identity. Every request is executed with the Wazuh credentials from the environment. Anyone who can open a TCP connection to that port can read your entire SIEM. Over stdio this does not arise, because the process is spawned by the client and inherits its trust boundary; a listening socket is a different proposition entirely.

Three controls, in order of importance:

  1. WAZUH_MCP_AUTH_TOKEN — a shared secret required as Authorization: Bearer <token>, compared in constant time. Without it the server logs SERVING WITHOUT AUTHENTICATION at startup and serves anyone.

  2. TLS — the server speaks plain HTTP. A bearer token over cleartext is a token you have published. Terminate TLS in a reverse proxy in front of it.

  3. --allowed-host — DNS rebinding protection. Locked to loopback names on a loopback bind; on a public bind it uses your allowlist or warns that the protection is off.

The most defensible setup is to bind loopback and let a proxy handle TLS and authentication:

klaxon-mcp --transport http --host 127.0.0.1 --port 8000

GET /healthz is exempt from authentication for load-balancer probes.

Also worth considering: the tool output contains whatever your SIEM contains — IP addresses, usernames, hostnames, login times. All of it reaches the model you point at Klaxon. If that model is hosted elsewhere, so is the data. Under GDPR that is a processing decision, not a technical detail.

Transport options are listed in docs/TOOLS.md.


Troubleshooting

An aggregation returns nothing but there is clearly data. Almost always the wrong field. agent.id and rule.level are mapped in Wazuh 5 but never populated; the real fields are wazuh.agent.id and wazuh.rule.level. Ask for the schema with the relevant prefix.

logtest says the environment does not exist. The logtest "environment" is a tester session, and sessions are created when a policy is imported — not derived from your decoders. They live in engine state, so a rebuilt container loses them. Use tester_sessions to see which ones exist; test usually works when custom does not.

A field shows 0 % coverage but you can see values in the documents. Some fields are mapped "index": falseevent.original is one. They are stored and returned but not searchable, so exists finds nothing. field_coverage reports these as unmeasurable rather than empty.

manager returns 404 on /rules. That is correct. Wazuh 5 has no rule content type in the engine; detection moved to the OpenSearch Security Analytics plugin. Use detectors instead.

Counts stop at 10,000. OpenSearch caps hits.total unless the query sets track_total_hits: true. Klaxon flags this, and the fixed tools set it themselves.


Development

.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest
.venv/bin/mypy

The suite covers the input guards, the diagnostics layer and the network transport, plus the acceptance criteria that do not need a live cluster.


License

Apache-2.0 — see LICENSE.


Built by sec73 GmbH.

Wazuh is a registered trademark of Wazuh Inc. Klaxon is an independent project and is not affiliated with, endorsed by, or sponsored by Wazuh Inc.

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    A Model Context Protocol server that enables querying and analyzing Wazuh security logs stored in OpenSearch, with features for searching alerts, getting detailed information, generating statistics, and visualizing trends.
    Last updated
    9
    2
  • A
    license
    A
    quality
    A
    maintenance
    An MCP server for the Wazuh SIEM/XDR platform that enables users to query agents, security alerts, detection rules, and decoders through Claude or other MCP clients. It provides specialized tools and prompts for investigating security alerts, performing agent health checks, and generating environmental security overviews.
    Last updated
    28
    33
    3
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    AI-powered MCP server that enables security analysts to query Wazuh SIEM/XDR for alert triage, threat hunting, compliance audits, and incident response through natural language prompts.
    Last updated
    28
    13
    MIT

View all related MCP servers

Related MCP Connectors

  • MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.

  • GibsonAI MCP server: manage your databases with natural language

  • Official Microsoft MCP Server to query Microsoft Entra data using natural language

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sec73/klaxon'

If you have feedback or need assistance with the MCP directory API, please join our Discord server