Wazuh MCP Server
Blue Team MCP Server (Wazuh SIEM)
Un servidor MCP defensivo para Claude Desktop / cualquier cliente MCP: la contraparte de blue team de las herramientas ofensivas. 123 herramientas + 4 recursos en Wazuh SIEM, inteligencia de amenazas multiproveedor, correlación APT 3-Sum impulsada por MITRE, graficado de ataques, flujos de trabajo de investigación LangGraph y forensia de host. Solo lectura por defecto.
Programador: NAuliajati (csirt[at]tangerangkota[.]go[.]id)
Arquitectura
main.py -> mcp_server/ (package)
├─ core/ HTTP client, redaction, audit, config, attack graph, IOC store
├─ wazuh/ Indexer (OpenSearch) + Manager API (JWT auth)
├─ correlation/ 3-Sum engine (pure computation, MITRE-driven)
├─ threat_intel/ CrowdSec, ThreatFox, OTX, URLhaus, GreyNoise + shared cache
├─ agents/ LangGraph investigation + playbook workflows
└─ tools/ 49 tool modulesCada llamada de herramienta fluye a través de una única canalización en el decorador @blueteam_tool: los tres nodos más conectados del grafo de código:
audit (_audit_log) -> call -> redact (_redact_alert_data) -> truncate (_truncate_if_needed)Todo el HTTP saliente fluye a través de un interruptor de circuito por grupo (http_client.CircuitBreaker: 5 fallos consecutivos -> abierto, 60s de enfriamiento, un único intento semia bierto). Los 429 y 4xx nunca cuentan como fallos, por lo que una caída en un upstream falla rápidamente en lugar de acumular reintentos entre herramientas.
Transporte | Caso de uso |
| Subproceso local / tubería SSH (predeterminado) |
| Servicio HTTP remoto ( |
Related MCP server: wrg-mcp-server
Inicio rápido
git clone <repo> && cd Wazuh-MCP-Server
sudo bash setup.sh # deps, venv, wrapper at /opt/blue-team-mcp
# configure (edit /opt/blue-team-mcp/config.env)
export WAZUH_INDEXER_URL="https://<host>:9200"
export WAZUH_INDEXER_USER="admin"
export WAZUH_INDEXER_PASSWORD="<indexer-password>"
export WAZUH_API_URL="https://<host>:55000" # optional — Manager API tools
export WAZUH_API_USER="wazuh-wui"
export WAZUH_API_PASSWORD="<api-password>"
export CROWDSEC_API_KEY="<key>" # optional — threat intel (free)
# inbound auth for the HTTP transport (REQUIRED when binding beyond 127.0.0.1)
export MCP_API_KEY="btm_<43-char-base64>" # generate: python3 -c "import secrets; print('btm_' + secrets.token_urlsafe(32))"
export MCP_API_KEY_SCOPES="wazuh:read wazuh:write" # optional — default wazuh:read (read-only)
# run (stdio)
mcp-server-blueteam
# or remote HTTP (MCP_API_KEY is mandatory here — the server refuses to bind otherwise)
MCP_TRANSPORT=streamable_http MCP_HOST=0.0.0.0 MCP_PORT=8001 \
MCP_API_KEY="btm_<43-char-base64>" mcp-server-blueteamConfiguración de Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"blue-team-mcp": {
"command": "ssh",
"args": ["-i", "~/.ssh/id_ed25519", "user@DEFENDER_HOST", "mcp-server-blueteam"],
"transport": "stdio"
}
}
}Configuración
Las credenciales provienen de variables de entorno, validadas al inicio. Cada clave de inteligencia de amenazas es opcional: las herramientas degradan con elegancia sin ellas.
Área | Variables | Notas |
Wazuh Indexer |
| OpenSearch (9200) — datos de alertas/eventos |
Wazuh Manager |
| API del Manager (55000) — reglas/agentes/configuración |
TLS |
| predeterminado |
Inteligencia de amenazas |
| 9 proveedores + RapidAPI + HudsonRock; todos opcionales |
Redacción |
| ver Seguridad y Privacidad |
Puerta forense |
| predeterminado |
Autenticación entrante |
| clave API precompartida + ámbitos para |
Endurecimiento entrante |
| límite de tasa por IP con ventana deslizante (req/min, |
Auditoría y persistencia |
| rastro de auditoría JSONL + almacenes (opcional) |
Control de acceso |
| omitir herramientas destructivas / categorías de herramientas |
Capacidades
Wazuh SIEM
Búsqueda de alertas (blueteam_wazuh_indexer_search, wazuh_alert_dsl_query), agregaciones estadísticas de cero documentos, descubrimiento de esquema (blueteam_index_schema), consultas de dominio/correo/geo/syscheck/cumplimiento y herramientas de la API del Manager (reglas, decodificadores, grupos, agentes, eventos de seguridad).
Correlación APT 3-Sum
three_sum_correlation ejecuta dos motores más una puntuación unificada:
Motor A — Umbral de riesgo multi-IoC impulsado por MITRE. Las alertas se clasifican por
rule.mitre.tactic(medianteMITRE_TACTIC_TO_CATEGORY) yrule.mitre.id(resuelto a través del paquete STIX de ATT&CK), puntuadas comorule.level × peso de táctica, y controladas por una regla de ataque encadenado de ≥2 categorías (threshold_scorepredeterminado 35).Motor B — Puntuación Z volumétrica de 3 fuentes (MAD + verificación de hombro) que señala picos simultáneos.
Además, resolución múltiple (1h/24h/7d), puntuación de severidad unificada y detección de degradación del Indexer.
Inteligencia de Amenazas
9 proveedores — CrowdSec, ThreatFox, OTX, URLhaus, GreyNoise, AbuseIPDB, VirusTotal, Netra, Argus — con un blueteam_threat_intel_aggregate unificado (fan-out concurrente) y una blueteam_unified_threat_score ponderada. Además, stealer_log_check (HudsonRock) y jarm_fingerprint (huella TLS para atribución de C2/malware, sin clave API), y 3 consultas RapidAPI (blueteam_ip_blacklist, blueteam_ioc_search, blueteam_breach_check).
Enriquecimiento de Alertas
blueteam_wazuh_alert_summarize, blueteam_beacon_detect, blueteam_attack_chain, blueteam_threat_card, blueteam_wazuh_alert_compare, blueteam_curated_threat_report.
Investigación, Grafos y Flujos de Trabajo
blueteam_investigate_ip, blueteam_attack_graph (clústeres networkx + PageRank), blueteam_pivot_suggest, blueteam_campaign_watch, blueteam_stix_killchain, blueteam_investigation_workflow y blueteam_playbook_run (LangGraph), además de una base de conocimiento de falsos positivos (blueteam_false_positive_kb) que suprime automáticamente los IOCs ruidosos conocidos en 3-Sum.
Forensia de Host y Dominio
WHOIS / CRT.sh, extracción de IOCs, huellas JARM, detección de typosquatting (blueteam_domain_permute), escaneo de webshells, exportación JSONL del lado del servidor, exportación de informes DOCX/XLSX/PPTX y 23 herramientas de forensia de host (lectores de registros, fail2ban, escaneo de rootkits, lynis, procesos/cron/usuarios).
Seguridad y Privacidad
Autenticación entrante (streamable_http)
streamable_http está protegido por una clave API precompartida en mcp_server/core/server_auth.py:
MCP_API_KEY— formatobtm_<43-char-urlsafe-base64>(47 caracteres). Almacenada solo como un digest SHA-256, comparada conhmac.compare_digest(tiempo constante).MCP_API_KEY_SCOPES— predeterminadowazuh:read(solo lectura). Añadewazuh:writepara desbloquear las 9 herramientas de escritura (blueteam_fail2ban_unban,blueteam_case_*,blueteam_set_owned_domains,blueteam_mark_investigated,blueteam_wazuh_export,blueteam_export_report,blueteam_capture_traffic). Cierre seguro: sin ámbito ⇒ solo lectura.Guardia de enlace (
main.py::_start_http_transport): un enlace no loopback sinMCP_API_KEYlanzaConfigurationErrory se niega a iniciar. Loopback permanece sin autenticación solo cuando no hay clave configurada; cuando se establece una clave, se aplica en cada solicitud.Guardia de profundidad JSON (
parse_json_body_safe): cada cuerpo POST está limitado a 1 MB (MAX_BODY_BYTES) y se rechaza si el anidamiento supera los 100 niveles (MAX_JSON_DEPTH) antes de que se ejecutejson.loads— bloquea el DoS por agotamiento de pila de cargas JSON-RPC profundamente anidadas.Limitador de tasa entrante (
SlidingWindowRateLimiter): límite por IP de cliente con ventana deslizante (BLUETEAM_HTTP_RATE_LIMIT, solicitudes/min, predeterminado0= desactivado) →429en exceso. Distinto deBLUETEAM_RATE_LIMIT, que controla herramientas destructivas (desbaneo de fail2ban, captura tcpdump) con un límite global por minuto.Validación de Origin (
_origin_allowed): un encabezadoOrigindebe ser un origen loopback o estar enBLUETEAM_ALLOWED_ORIGINS(orígenes exactos separados por comas), de lo contrario403. Bloquea el DNS-rebinding basado en navegador / la exfiltración de localhost. Las solicitudes sin encabezadoOrigin(clientes no navegador) no se ven afectadas. El middleware está siempre instalado: el límite de tasa y la validación de origen se aplican incluso en un enlace loopback sin autenticación.
Política de redacción
Política de tres estados (BLUETEAM_REDACTION_POLICY, predeterminado protect_victim):
Política | Comportamiento |
| Enmascaramiento basado en forma de correos electrónicos, IPs privadas, todos los dominios, rutas, user-agents — respaldo conservador cuando |
| Enmascarar solo los indicadores propiedad de la víctima (dominios propios, IPs privadas, identidades); los IOCs del atacante permanecen visibles. Recomendado para el triaje del SOC. |
| Solo eliminación de credenciales de capa 1 — estrictamente controlado detrás de |
La capa 1 (eliminación de credenciales) se aplica en todos los estados y nunca se puede omitir. El registro de IOCs de atacantes (core/attacker_registry.py) exime los indicadores de atacante confirmados del enmascaramiento basado en forma — nunca de la capa 1.
Desenmascarado de dos niveles sobre la política:
Nivel 1 —
reveal_owned=true— revela solo los activos propios*.tangerangkota.go.idal LLM, y desenmascara las claves de bucket de dominios propios en las herramientas de agregación (incluyendowazuh_alert_dsl_query). Nunca se expande más allá deBLUETEAM_OWNED_DOMAINS.Nivel 2 —
bypass_redaction=true+forensic_token— escribe datos sin procesar en disco; el LLM recibe solo la ruta del archivo, nunca el contenido sin procesar.
Establece BLUETEAM_OWNED_DOMAINS con los dominios de tu organización (separados por comas, p. ej. tangerangkota.go.id). Inspecciona con blueteam_owned_domains; actualiza en tiempo de ejecución con blueteam_set_owned_domains (controlado por BLUETEAM_ALLOW_RUNTIME_DOMAINS=true, desactivado por defecto).
Prompt de Análisis SOC (copiar y pegar para tu LLM)
Un prompt listo para pegar para un LLM local conectado a este servidor MCP. Dos formatos de salida —
Markdown (en línea) y DOCX (requiere officecli, blueteam_export_report).
⚠️ Calling convention & guardrails (read once — prevents "Field required" errors and false positives):
- Every tool takes a SINGLE ``params`` object. FastMCP double-nests it:
tool_invoke(name="<tool>", params={"params": {"field": value, ...}})
Call tool_inspect FIRST to read a tool's exact signature; never skip inspect on an unused tool.
- Default model = protect_victim: the LLM sees attacker public IPs/payloads/rule/severity/MITRE,
never internal emails, subdomains, private IPs (RFC1918), or internal paths.
- A private/RFC1918 srcip (10.x, 172.16-31.x, 192.168.x) is INTERNAL, never an attacker — do not
run threat-intel on it (those tools reject private IPs by design — SSRF guard).
- reveal_owned=true (Tier 1, LLM-safe): reveals only *.tangerangkota.go.id + @tangerangkota.go.id.
Accepted by the alert/aggregation tools — wazuh_domain_lookup, wazuh_alert_focused_crawl,
wazuh_email_lookup, wazuh_alert_dsl_query (unmasks owned-domain bucket keys), and others —
never expands beyond BLUETEAM_OWNED_DOMAINS.
- bypass_redaction=true + forensic_token (Tier 2, HUMAN ONLY): writes raw data to disk via
blueteam_wazuh_export; the LLM sees only the file path.
- ⚠️ NEVER pass redaction_policy="raw" OR bypass_redaction=true in a tool call — both are
HUMAN-ONLY and gated behind the operator forensic token, which the LLM does NOT hold. The
call fails with "requires the operator forensic token". For owned-domain visibility use
reveal_owned=true (above, no token); full raw forensics is blueteam_wazuh_export run by the
analyst on the server.
- redaction_policy="protect_victim" is accepted by 13 tools (blueteam_curated_threat_report,
blueteam_threat_card, blueteam_wazuh_alert_summarize, blueteam_wazuh_alerts,
blueteam_wazuh_geo_heatmap, blueteam_wazuh_indexer_search, three_sum_correlation,
wazuh_alert_aggregate_analysis, wazuh_alert_focused_crawl, wazuh_alert_timeline,
wazuh_attack_velocity, wazuh_domain_lookup, wazuh_email_lookup). blueteam_wazuh_export uses
bypass_redaction (NOT redaction_policy). Other tools reject redaction_policy — drop it and retry.
(Separately, wazuh_alert_dsl_query accepts reveal_owned=true but NOT redaction_policy.)
- blueteam_wazuh_export writes to BLUETEAM_EXPORT_DIR (default /var/log/blue-team-mcp/exports/)
with an AUTO-GENERATED filename (export_<timestamp>.jsonl). It has NO ``path`` parameter —
do not pass one (it will be rejected). Only blueteam_export_report accepts a ``path``.
LANGKAH 0 — Index schema (before any aggregation):
blueteam_index_schema(fields=["data.srcip","rule.id","rule.groups","agent.name",
"data.domain","data.url","GeoLocation.city_name"], response_format="json")
LANGKAH 1 — Full overview + own-asset forensics:
blueteam_curated_threat_report(since="24h", investigation_depth="deep",
response_format="json", redaction_policy="protect_victim")
wazuh_domain_lookup(domain="tangerangkota.go.id", since="24h", reveal_owned=true,
response_format="json", max_scanned=10000)
LANGKAH 2 — Per attacker (top 10): threat card + attack chain
blueteam_threat_card(srcip=<ip>, since="24h")
blueteam_attack_chain(srcip=<ip>, since="24h")
LANGKAH 3 — Unified threat intel:
blueteam_threat_intel_aggregate(indicator=<ip>, response_format="json")
argus_ip_lookup(ip=<ip>); otx_lookup(indicator=<ip>, section="general")
blueteam_ip_blacklist(ip=<ip>); blueteam_ioc_search(ip=<ip>) # RapidAPI
LANGKAH 4 — 3-Sum APT + auto-enrich + case:
three_sum_correlation(time_window_minutes=1440, follow_up="threat_intel",
multi_resolution=true, create_case=true, response_format="json",
redaction_policy="protect_victim")
LANGKAH 5 — Attack graph + pivot + campaign:
blueteam_attack_graph(window_days=30, top_n=20, response_format="json")
blueteam_pivot_suggest(ioc=<top_attacker_ip>)
blueteam_campaign_watch(response_format="json")
LANGKAH 6 — LangGraph investigation + verdict:
blueteam_investigation_workflow(alert_text="<...>", srcip=<ip>, window="24h",
use_attack_graph=true, generate_report=false, record_verdict=true, verdict_label="suspicious")
blueteam_mark_investigated(srcip=<ip>, verdict="<verdict>", case_id=<case_id>)
LANGKAH 7 — Compromised emails + breach/stealer check:
wazuh_compromised_emails_analysis(since="24h", response_format="json")
blueteam_breach_check(email=<email_dinas>); stealer_log_check(email=<email_dinas>)
LANGKAH 8 — MITRE kill-chain + C2 fingerprinting:
blueteam_stix_killchain(srcip=<ip>, since="24h")
jarm_fingerprint(host=<c2_domain_or_ip>, response_format="json")
blueteam_domain_permute(domain="tangerangkota.go.id") # typosquatting lookalikes
LANGKAH 9 — Suppression, telemetry, case review:
blueteam_false_positive_kb(); blueteam_owned_domains(); blueteam_metrics()
blueteam_case_list(); blueteam_case_get(case_id=<case_id>)
LANGKAH 10 — Geo heatmap:
blueteam_wazuh_geo_heatmap(since="24h", response_format="json")
Supplementary tools (by category — the full 123-tool set; LANGKAH 0–10 is the default path):
- Alert search/aggregation: blueteam_wazuh_indexer_search, blueteam_wazuh_alerts,
wazuh_alert_aggregate_analysis, wazuh_alert_focused_crawl, wazuh_alert_dsl_query,
wazuh_alert_timeline, wazuh_attack_velocity, blueteam_wazuh_alert_summarize,
blueteam_wazuh_alert_compare.
- Threat intel: crowdsec_ip_reputation(/bulk), threatfox_ioc_search(/bulk),
greynoise_ip_context, netra_ip_analysis, otx_lookup_bulk, urlhaus_lookup(/bulk),
urlhaus_hash_lookup, blueteam_lookup_domain_virustotal, blueteam_lookup_hash_virustotal,
blueteam_unified_threat_score, blueteam_mitre_lookup.
- Baselines & anomaly: blueteam_baseline_profile, blueteam_baseline_drift,
blueteam_calendar_heatmap, blueteam_beacon_detect.
- Wazuh Manager (agents/rules/config): blueteam_wazuh_agents, blueteam_wazuh_agents_summary,
blueteam_wazuh_get_cluster_nodes, blueteam_wazuh_get_rules, blueteam_wazuh_get_groups,
blueteam_wazuh_get_decoders, blueteam_wazuh_get_security_events, blueteam_wazuh_manager_logs,
blueteam_wazuh_get_rule_files, blueteam_wazuh_get_rule_file_content,
blueteam_wazuh_get_agent_sca, blueteam_wazuh_list_sca_policies, blueteam_wazuh_get_sca_policy_checks.
- Compliance/SCA/vuln: blueteam_wazuh_syscheck, blueteam_wazuh_compliance,
blueteam_wazuh_vulnerabilities.
- Host forensics: blueteam_read_auth_log, blueteam_read_syslog, blueteam_read_web_log,
blueteam_failed_logins, blueteam_last_logins, blueteam_who_is_logged_in,
blueteam_find_suid_files, blueteam_find_world_writable, blueteam_list_connections,
blueteam_list_listening_ports, blueteam_list_processes, blueteam_list_cron_jobs,
blueteam_list_users, blueteam_hash_file, blueteam_journalctl, blueteam_rootkit_scan,
blueteam_lynis_audit, blueteam_system_health, blueteam_sudo_history,
blueteam_check_open_firewall, blueteam_check_ssh_authorized_keys, blueteam_check_updates,
blueteam_fail2ban_status, blueteam_fail2ban_jail_status, blueteam_fail2ban_unban,
blueteam_capture_traffic.
- Domain/asset: blueteam_whois_lookup, blueteam_crtsh_lookup, blueteam_asset_context.
- Case/IOC/history: blueteam_case_create, blueteam_case_add_iocs, blueteam_case_add_verdict,
blueteam_case_list, blueteam_case_get, blueteam_extract_iocs, blueteam_ioc_lifecycle,
blueteam_investigate_ip, blueteam_playbook_run, blueteam_investigation_history,
blueteam_investigation_summary, blueteam_false_positive_tracker.
- Geo: blueteam_wazuh_geo_distribution (by country).
- Forensics/scanning/other: blueteam_check_webshell, blueteam_semantic_search,
blueteam_threat_hunt, blueteam_stix_analyze, blueteam_prompt_route.
- AI/LLM attack detection: blueteam_ai_bot_recon (AI-agent user-agents probing exploit paths).
- Sangfor blocklist: sangfor_blocklist_check(ip=<ip>) for a single IP;
sangfor_blocklist_list(limit=…, date_start="YYYY-MM-DD HH:MM:SS", date_end=…) for the list —
no ``since`` / ``offset`` params (use date_start/date_end).
—— FORMAT MARKDOWN: compose the report from steps 1–10 (ringkasan → subdomain → IOC →
threat intel → 3-Sum → attack graph → LangGraph → email → MITRE → geo).
—— FORMAT DOCX (officecli): blueteam_export_report(format="docx", title="<...>",
path="/var/log/blue-team-mcp/exports/laporan_24jam_<date>.docx", docx_sections=[...])
—— FORENSIC EXPORT (HUMAN ONLY): blueteam_wazuh_export(since="24h", bypass_redaction=true,
forensic_token="<BLUETEAM_FORENSIC_TOKEN>")
→ streams to /var/log/blue-team-mcp/exports/export_<timestamp>.jsonl (filename auto-generated;
NO ``path`` parameter). WITHOUT ``bypass_redaction=true`` the export is protect_victim-masked
(subdomains stay masked). Analyst reads the file on the server (cat/jq); the LLM assists only
with REDACTED analysis.Requisitos
Python 3.11+
mcp,httpx[http2],pydantic,networkx,langgraph,officecli-sdkVer
requirements.txt.
Desarrollo
Antes del merge:
python3 check_guardrails.py --strictdebe terminar con 0, y el registro permanece en stderr.
This server cannot be installed
Maintenance
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
- AlicenseAqualityAmaintenanceAn 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.28343MIT
- AlicenseNot gradedqualityAmaintenanceAn MCP server that exposes a 60+ tool security and threat-intel stack to AI agents, enabling secret scanning, Sigma rule generation, ransomware lookup, OSINT, and deep research.1MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that transforms Claude Code into an autonomous DFIR analyst by providing typed, audited forensic tools for disk, memory, timeline, registry, and IOC analysis on the SANS SIFT Workstation.Apache 2.0
- AlicenseNot gradedqualityDmaintenanceThis MCP server connects Claude Desktop to a Velociraptor instance and local forensic tools. It enables remote endpoint investigation and local evidence analysis through natural language commands.1MIT
Related MCP Connectors
Security-first WordPress MCP server. 129 tools for Claude, ChatGPT, Gemini. Free on wp.org.
Security scanner for MCP servers. Detect vulnerabilities, prompt injection, and tool poisoning.
MCP server for Pentest-Tools.com: run scans, manage findings and reports via your preffered LLM.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/INFOKOM-KI/Wazuh-MCP-Server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server