Wazuh MCP Server
Retrieves security alerts from Elasticsearch indices containing Wazuh data, transforming them into standardized MCP messages.
Uses Flask to expose an HTTP endpoint for serving transformed security event data to clients.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Wazuh MCP Servershow me recent critical security alerts from the last hour"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Wazuh MCP Server
A Model Context Protocol (MCP) server for the Wazuh SIEM.
Lets an MCP client — Claude, Open WebUI backed by a local model, or any client that speaks Streamable HTTP — query alerts, agents, vulnerabilities and compliance data, and dispatch active responses, with scope-based access control and audit logging.
Quick Start · Clients · Tools · Security · Configuration · Docs · Changelog · Upgrading
Overview
55 tools in 8 toolsets: alerts, agents, vulnerabilities, threat analysis, compliance (PCI-DSS, HIPAA, SOX, GDPR, NIST, ISO 27001:2022), manager/cluster health, and active response with verification and rollback. Also 5 guided prompts, 6 resources and 3 resource templates.
Read-only by default. The 14 state-changing tools require the
wazuh:writescope, which is never granted implicitly.MCP transport: Streamable HTTP at
/mcp. Serves protocol revision 2026-07-28 (stateless requests) and theinitializehandshake for 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05. The legacy HTTP+SSE endpoint/ssereturns410 Gone.Authentication: bearer tokens minted from an API key; OAuth 2.0 (authorization code + PKCE) with sign-in by API key or at an OpenID Connect provider (Entra ID, Google Workspace, Okta, Keycloak); or no auth for local development.
Deployment: Docker Compose or a published multi-arch image; optional Redis for multi-instance sessions; optional multi-cluster routing.
Local models: a vLLM + Open WebUI stack (
compose.local-llm.yml) and toolset filtering for small models. The only tool that calls a service outside your Wazuh deployment is the optionalsearch_external_context(You.com), which can be disabled on its own.
Supported Wazuh versions: 4.8.0 through 4.14.7. Alert, vulnerability and alert-backed compliance tools need the Wazuh Indexer. See WAZUH_COMPATIBILITY.md.
Related MCP server: wazuh-mcp
Quick Start
Requires Docker with Compose v2 and a Wazuh Manager API user.
git clone https://github.com/gensecaihq/Wazuh-MCP-Server.git
cd Wazuh-MCP-Server
cp .env.example .envSet the Wazuh connection in .env:
WAZUH_HOST=your-wazuh-manager
WAZUH_USER=your-api-user
WAZUH_PASS=your-api-password
# Needed for alert, vulnerability and alert-backed compliance tools
WAZUH_INDEXER_HOST=your-wazuh-indexer
WAZUH_INDEXER_USER=your-indexer-user
WAZUH_INDEXER_PASS=your-indexer-passwordThe Manager's TLS certificate is verified. A stock Wazuh install uses a self-signed API certificate that cannot pass verification, so either reissue it for your host and set WAZUH_CA_BUNDLE, or, for a first test, add WAZUH_ALLOW_SELF_SIGNED=true (connects without verification; logged at startup). Details: Manager TLS.
Generate the signing secret and an API key. compose.yml runs the server with ENVIRONMENT=production, which refuses to start without AUTH_SECRET_KEY:
echo "AUTH_SECRET_KEY=$(openssl rand -hex 32)" >> .env
echo "MCP_API_KEY=wazuh_$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')" >> .envStart the server and check it:
docker compose up -d
curl http://localhost:3000/health # liveness
curl http://localhost:3000/ready # checks Manager/Indexer reachabilityExchange the API key for a bearer token (valid for TOKEN_LIFETIME_HOURS, default 24):
curl -s -X POST http://localhost:3000/auth/token -H 'Content-Type: application/json' \
-d "{\"api_key\": \"$(grep ^MCP_API_KEY= .env | cut -d= -f2)\"}"The key is read-only. To allow active-response tools, add MCP_API_KEY_SCOPES="wazuh:read wazuh:write" to .env, recreate the container with docker compose up -d (restart keeps the old environment), and mint a new token.
Compose publishes the port on 127.0.0.1 only. The server speaks plain HTTP; put a TLS-terminating reverse proxy in front before exposing it (set MCP_BIND to change the host bind address).
python3 deploy.py (or deploy.bat on Windows) performs the same steps, generating AUTH_SECRET_KEY and MCP_API_KEY if they are missing.
Pre-built image
Multi-arch images (amd64, arm64) are published to GitHub Container Registry and can be pulled without logging in:
docker pull ghcr.io/gensecaihq/wazuh-mcp-server:latest # tracks main
docker pull ghcr.io/gensecaihq/wazuh-mcp-server:5.0.0 # latest tagged releaselatest is built from main and may include changes listed under Unreleased in the changelog. Release images are tagged 5.0.0, 5.0 and v5.0.0 (4.3.0 and earlier have no v-prefixed tag). Upgrading from 4.x: read UPGRADING.md first.
docker run -d --name wazuh-mcp-server --env-file .env -e MCP_HOST=0.0.0.0 -e ENVIRONMENT=production \
-p 127.0.0.1:3000:3000 ghcr.io/gensecaihq/wazuh-mcp-server:latestMCP_HOST=0.0.0.0 is required inside a container because .env.example sets MCP_HOST=127.0.0.1 for bare-metal installs. -e wins over --env-file, so ENVIRONMENT=production holds even if your .env sets another value.
Connecting Clients
All clients use the Streamable HTTP endpoint https://<your-host>/mcp.
Client | Auth mode | How it authenticates |
Claude custom connectors (claude.ai, Claude Desktop) |
| OAuth authorization code with PKCE. The server pre-registers a public client, |
Open WebUI, LibreChat, scripts and other MCP clients |
|
|
In OAuth mode, set OAUTH_ISSUER_URL to the server's public HTTPS URL (otherwise it is derived from each request, which behind a proxy may not be the public URL). Dynamic Client Registration (/oauth/register) is off unless OAUTH_ENABLE_DCR=true, and cannot be combined with OAUTH_IDP_ISSUER.
Guides: Claude Integration · Local LLMs
Local LLMs
The server does not call a model; it only executes tools. To keep SIEM data on-premises, pair it with a local model:
cat >> .env <<EOF
VLLM_API_KEY=$(openssl rand -hex 32)
WEBUI_SECRET_KEY=$(openssl rand -hex 32)
EOF
docker compose -f compose.yml -f compose.local-llm.yml up -dThis adds vLLM (default model Qwen3.6-35B-A3B FP8, about 42 GB of VRAM on one NVIDIA GPU; not published on a host port) and Open WebUI on 127.0.0.1:8080. In Open WebUI's admin settings, add an MCP (Streamable HTTP) tool server at http://wazuh-main-server:3000/mcp with a bearer token.
For smaller models, expose fewer tools with WAZUH_TOOLSETS / WAZUH_DISABLED_TOOLS, and check tool selection before rollout with evals/tool_selection.py (25 SOC scenarios, including two prompt-injection cases, against any OpenAI-compatible endpoint; no tools are executed). Model sizing, Ollama and LiteLLM are covered in the Local LLM Guide.
Tools
55 tools, grouped into toolsets that can be enabled with WAZUH_TOOLSETS (comma-separated; default all). R = wazuh:read, W = wazuh:write.
Toolset | Count | Tools |
| 5 R |
|
| 6 R |
|
| 3 R |
|
| 5 R |
|
| 1 R |
|
| 6 R |
|
| 10 R |
|
| 9 W |
|
| 5 W |
|
| 5 R |
|
Totals: 41 read tools, 14 write tools. Tokens without
wazuh:writedo not see the write tools intools/list.In multi-cluster mode a 56th tool,
list_wazuh_clusters(system, read), is added and every tool accepts an optionalcluster_id.WAZUH_DISABLED_TOOLShides individual tools. Hidden tools are removed fromtools/listand refused bytools/call; unknown toolset or tool names stop the server at startup.Every tool carries MCP annotations derived from its scope: read tools are
readOnlyHint: true; containment tools aredestructiveHint: true; rollback tools aredestructiveHint: false; onlysearch_external_contextisopenWorldHint: true.Input schemas are closed (
additionalProperties: false); undeclared arguments are refused.Timestamp filters accept ISO 8601 or OpenSearch date math (
now-24h).Prompts:
security_investigation,threat_hunt,compliance_audit,vulnerability_assessment,iso27001_assessment.
Per-tool parameters: API documentation.
Active response behaviour
Results report
execution_status: "dispatched": Wazuh confirms the command was delivered to the agent, not that it ran. Confirm the effect with the matchingwazuh_check_*tool.Blocks are permanent until removed. Wazuh ignores the timeout for API-triggered commands, so a positive
durationis refused.wazuh_firewall_allowandwazuh_host_allowrequire an operator-deployed undo command (WAZUH_AR_FIREWALL_UNDO_COMMAND,WAZUH_AR_HOSTDENY_UNDO_COMMAND); without one they refuse.
Security Model
Control | Behaviour |
Scopes (RBAC) | Each tool requires |
Bearer tokens | JWTs signed with |
OAuth | Authorization code flow with mandatory S256 PKCE, single-use codes, refresh-token rotation with replay detection, and revocation. Users sign in with a |
Action guardrails | IP-blocking tools refuse loopback, the Manager's address (when |
Wazuh TLS | The Manager and Indexer certificates are verified by default, against the system store or |
Audit log | Every write-tool call that passes the scope and confirmation checks is logged before and after execution (logger |
Redaction | Credentials and tokens are redacted from tool output in every response format, and from server logs. |
Input validation | Typed validation of agent IDs, IPs, paths and command names; Indexer queries are built as Query DSL, not by string interpolation. |
Rate limiting | Sliding window, default 100 requests per 60 s ( |
Resource bounds | Circuit breaker on Wazuh calls: opens after 5 consecutive failures, retries after 60 s. Oversized tool results are truncated with a note ( |
Container | Runs as UID 1000; |
There is no built-in TLS listener; terminate TLS at a reverse proxy or load balancer. Report vulnerabilities as described in SECURITY.md.
Configuration
All settings are environment variables (usually via .env). The ones most deployments touch:
Variable | Default | Purpose |
| — | Manager API connection (required) |
|
| Manager API port |
| — | CA PEM used instead of the system store to verify the Manager and Indexer; see Manager TLS |
|
|
|
| — | Indexer connection; an |
|
| Indexer port |
|
|
|
|
|
|
| generated per process outside production | Token signing key; use the same value on every instance |
| generated per process if unset (printed only in development) | A single |
|
| Space-separated scopes for |
| derived from the request | Public HTTPS URL of the server, for |
| — | OpenID Connect provider for OAuth sign-in (with |
|
| Write tools require |
|
| Bind address and port |
|
| CORS allow-list (exact match) |
| all enabled | Limit the exposed tools |
| — | Shared session store for multi-instance deployments |
|
| Multi-cluster topology; single-cluster mode when absent |
|
|
|
| — | Enables |
Complete reference, including OAuth TTLs, rate limits, sessions and active-response settings: Configuration Guide. Multi-cluster setup: Multi-Cluster Guide and config/clusters.json.example.
Running from source
python -m venv .venv && source .venv/bin/activate
pip install -e ".[redis,gcf]" # extras are optional
set -a; . ./.env; set +a # the server reads the environment, not .env
python -m wazuh_mcp_serverRequires Python 3.11 or later.
HTTP Endpoints
Endpoint | Method | Description |
| POST, GET, DELETE | MCP Streamable HTTP |
| POST, GET | Same handler as |
| GET, POST | Returns |
| GET | Liveness; no dependency checks |
| GET | Readiness; 503 when the Manager, Indexer or memory headroom check fails |
| GET | Prometheus metrics |
| POST | Exchange an API key for a bearer JWT |
| GET | OAuth metadata (RFC 8414), |
| GET | Protected-resource metadata (RFC 9728), |
| GET/POST | OAuth endpoints, |
| GET | OpenAPI documentation |
Project Layout
src/wazuh_mcp_server/
├── server.py # FastAPI app, MCP protocol handling, CORS/Origin checks, tool definitions and dispatch
├── toolsets.py # Toolset membership, WAZUH_TOOLSETS resolution, tool annotations
├── auth.py # API keys and bearer JWTs
├── oauth.py # OAuth 2.0 authorization server (PKCE, API-key sign-in)
├── oidc.py # OpenID Connect sign-in at an external identity provider
├── config.py # Environment configuration and startup validation
├── security.py # Rate limiting, request and input validation, log redaction
├── clusters.py # Multi-cluster registry and Cross-Cluster Search routing
├── session_store.py # In-memory and Redis session storage
├── resilience.py # Circuit breakers, retries, graceful shutdown
├── monitoring.py # Prometheus metrics, structured logging
├── gcf_format.py # Optional GCF response encoding
└── api/
├── wazuh_client.py # Wazuh Manager REST API client
└── wazuh_indexer.py # Wazuh Indexer (OpenSearch) clientDocumentation
Document | Contents |
Every environment variable, auth modes, RBAC | |
Connecting Claude custom connectors | |
vLLM, Open WebUI, Ollama, LiteLLM, tool-selection eval | |
Named clusters and Cross-Cluster Search | |
Deployment, monitoring, maintenance | |
Multi-instance deployment, compact output | |
Common problems and fixes | |
Per-tool parameters | |
Hardening guidance | |
Protocol conformance notes | |
Supported Wazuh versions | |
Release notes and policies |
Related project: Wazuh Autopilot builds automated SOC workflows on top of this server.
Contributing
See CONTRIBUTING.md. Bugs, feature requests and questions go to Issues, and security reports to a private security advisory.
License
Acknowledgments
Thanks to everyone who has contributed code, reviews, bug reports and design feedback. See also ACKNOWLEDGMENTS.md.
Code and pull requests
@andrzej-piotrowski-pl — ISO 27001:2022 compliance tools: Annex A control mapping, domain scoring, gap analysis (#74)
@blackwell-systems — opt-in GCF response encoding for record tools (#102, #104)
@lucascruzb — period-wide alert aggregation via scroll, the basis of
get_alerts_aggregated(#79)@kanylbullen — compact output mode for token-efficient responses (#65)
@mouse-value-add — optional You.com web-search context (#85)
@DrRSatzteil —
tools/listpagination fix (#70)@SiM22 — MCP 2025-06-18 support for Windsurf compatibility (#66)
@aiunmukto —
.env.example(#12), an early CI workflow and the Glama registry listing@Karibusan — dependency fixes (#38)
@lwsinclair — MseeP.ai listing (#9)
@markeclaudio — OpenID Connect sign-in (#123), active-response guard-rails (#124, #125), session-store bounds (#126), Manager TLS verification by default (#127)
@MilkyWay88 and @taylorwalton — early pull requests on configuration, logging and packaging
Bug reports and discussions
@cbassonbgroup, @cybersentinel-06, @daod-arshad, @mamema, @marcolinux46, @matveevandrey, @punkpeye, @tonyliu9189, @Uberkarhu, @bl4ck5w4n07, @gnix45, @hackdefendr, @melmasry1987, @Vasanth120v, @wqfh
Built on and works with
Wazuh — open source security platform
Model Context Protocol — the protocol this server implements
vLLM, Ollama and Open WebUI — local model serving and chat, used in the local LLM stack
Contributors
Avatar | Username | Contributions |
💻 Code, 🐛 Issues, 🔀 PRs, 💬 Discussions | ||
💻 Code, 🐛 Issues, 🔀 PRs | ||
💻 Code, 🔀 PRs, 💬 Discussions | ||
💻 Code, 🔀 PRs | ||
💻 Code, 🔀 PRs | ||
💻 Code, 🔀 PRs | ||
💻 Code, 🔀 PRs | ||
💻 Code, 🔀 PRs | ||
💻 Code, 🔀 PRs | ||
💻 Code, 🔀 PRs | ||
💻 Code, 🔀 PRs | ||
🔀 PRs | ||
🔀 PRs | ||
🔀 PRs | ||
🐛 Issues | ||
🐛 Issues | ||
🐛 Issues | ||
🐛 Issues | ||
🐛 Issues | ||
🐛 Issues | ||
🐛 Issues | ||
🐛 Issues | ||
🐛 Issues | ||
💬 Discussions | ||
💬 Discussions | ||
💬 Discussions | ||
💬 Discussions | ||
💬 Discussions | ||
💬 Discussions |
Legend: 💻 Code · 🐛 Issues · 🔀 Pull Requests · 💬 Discussions
Auto-updated by GitHub Actions
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP-Native LLM Orchestration Agent
Zero-setup MCP gateway securely connecting AI to your tools with authentication and workflows
Authenticated LLM MCP Agent
MCP server unifying ERPs, CRMs, APIs and knowledge base for Claude, ChatGPT and Gemini.
Related MCP Servers
AlicenseBqualityDmaintenanceConnects Claude and other MCP clients to Elasticsearch data, allowing users to interact with their Elasticsearch indices through natural language conversations.32,662 npm719Apache 2.0- AlicenseBqualityBmaintenanceAn 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.2840 npm6MIT
- AlicenseAqualityCmaintenanceAI-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.2813MIT
- AlicenseNot gradedqualityDmaintenanceA production-ready Model Context Protocol (MCP) server for seamless integration between Wazuh SIEM and Large Language Models (LLMs).93AGPL 3.0