Building a Wazuh MCP Server: AI-Driven Security Operations
Building a Wazuh MCP Server: AI-Driven Security Operations
Security operations require constant vigilance across diverse infrastructure. This article details the creation of a comprehensive Wazuh MCP (Model Context Protocol) server that enables AI agents to perform security operations programmatically.
What we built:
- MCP server with 25+ security tools covering ALL Wazuh API categories
- Integration framework for k8s, Proxmox, Cloudflare, GitHub, and UniFi
- JWT authentication with auto-refresh
- Production-ready with Prometheus metrics, health checks, and Docker deployment
Repository: /ry-ops/k3s-wazuh-mcp
Table of Contents
- The Challenge: AI-Driven Security
- What is MCP?
- Architecture Overview
- API Coverage: All 25+ Tools
- Implementation Deep Dive
- Infrastructure Integrations
- Deployment & Usage
- Real-World Use Cases
- Lessons Learned
- Future Roadmap
The Challenge: AI-Driven Security {#the-challenge}
Traditional security operations involve manual processes:
- Security analyst receives alert
- Analyst queries SIEM manually
- Analyst correlates events across systems
- Analyst determines appropriate response
- Analyst executes remediation steps
The bottleneck: Human analysts can’t scale with modern threat volumes.
Our infrastructure spans:
- Kubernetes cluster (k3s, 4 nodes: 10.88.145.190-192)
- Proxmox virtualization platform
- Cloudflare edge security (WAF)
- GitHub repositories
- UniFi network infrastructure
The solution: Enable AI agents to perform security operations through a comprehensive MCP server.
What is MCP? {#what-is-mcp}
Model Context Protocol (MCP) is a standard for connecting AI models to external tools and data sources.
Think of it as an API specifically designed for AI agents:
- Tools: Functions the AI can call (like API endpoints)
- Resources: Data the AI can access (like files or databases)
- Prompts: Templates for common operations
Why MCP for security?
- AI agents can query security events in natural language
- Automated correlation across infrastructure boundaries
- Immediate response execution without human bottleneck
- 24/7 security monitoring with intelligent analysis
Architecture Overview {#architecture-overview}
┌─────────────────────────────────────────────────────────────┐
│ Wazuh MCP Server │
│ (Security Contractor) │
├─────────────────────────────────────────────────────────────┤
│ API Categories (20+) │
│ ├── Authentication ├── Manager ├── MITRE │
│ ├── Agents ├── Cluster ├── Overview │
│ ├── Active Response ├── Decoders ├── Rootcheck │
│ ├── CISCAT ├── Events ├── Rules │
│ ├── Groups ├── Experimental ├── SCA │
│ ├── Lists ├── Logtest ├── Security │
│ ├── Syscheck ├── Syscollector ├── Tasks │
│ └── API Info │
├─────────────────────────────────────────────────────────────┤
│ Infrastructure Integrations │
│ ├── k8s Cluster (nodes: 190-192) │
│ ├── Proxmox VMs │
│ ├── Cloudflare WAF │
│ ├── GitHub Repositories │
│ └── UniFi Network │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────┐
│ Wazuh Manager API │
│ (https://wazuh:55000) │
└─────────────────────────┘
Technology Stack
- Runtime: Node.js 20 (Alpine-based Docker image)
- MCP SDK: @modelcontextprotocol/sdk v1.0.0
- HTTP Client: Axios with interceptors
- Validation: Zod schemas
- Logging: Winston (structured JSON)
- Metrics: Prometheus client
- Transport: StdioServerTransport (for MCP)
API Coverage: All 25+ Tools {#api-coverage}
Our MCP server provides complete coverage of the Wazuh API through organized tool categories:
Agent Management (5 tools)
wazuh_list_agents
// List and filter agents
// Example: "Show me all disconnected agents"
wazuh_add_agent
// Register new agent
// Example: "Add agent for server prod-web-01"
wazuh_delete_agent
// Remove agent
// Example: "Delete agent 001"
wazuh_restart_agent
// Restart agent service
// Example: "Restart all agents in group 'production'"
wazuh_upgrade_agent
// Upgrade agent version
// Example: "Upgrade all agents to version 4.7.0"
Security Operations (4 tools)
wazuh_run_rootcheck
// Execute rootkit detection
// Example: "Run rootkit scan on all Linux servers"
wazuh_run_sca
// Security configuration assessment
// Example: "Run CIS benchmark on production servers"
wazuh_get_vulnerabilities
// Fetch CVE scan results
// Example: "Show critical vulnerabilities from last 24 hours"
wazuh_execute_active_response
// Execute response action
// Example: "Block IP 192.168.1.100 on firewall"
Event Monitoring (4 tools)
wazuh_query_events
// Query security events
// Example: "Show authentication failures in last hour"
wazuh_get_fim_changes
// File integrity monitoring
// Example: "Show all /etc/ changes today"
wazuh_get_mitre_tactics
// MITRE ATT&CK mapping
// Example: "Show all Privilege Escalation attempts"
wazuh_get_overview
// Security dashboard data
// Example: "Give me security overview for production"
Rule Management (4 tools)
wazuh_list_rules
// List detection rules
// Example: "Show all SSH-related rules"
wazuh_test_rule
// Test rule against log
// Example: "Test rule 5710 against this SSH log"
wazuh_list_decoders
// List log decoders
// Example: "Show decoders for nginx logs"
wazuh_test_logtest
// Test log parsing
// Example: "Parse this apache log line"
Cluster Operations (5 tools)
wazuh_cluster_status
// Cluster health
// Example: "Is the Wazuh cluster healthy?"
wazuh_cluster_nodes
// List cluster nodes
// Example: "Show all cluster nodes and their status"
wazuh_get_tasks
// Background task status
// Example: "Show running upgrade tasks"
wazuh_get_manager_info
// Manager information
// Example: "What version is the manager running?"
wazuh_get_api_info
// API version and details
// Example: "Show API version and endpoints"
Infrastructure Integration (5 tools)
wazuh_deploy_k8s_agents
// Deploy agents to Kubernetes
// Example: "Deploy Wazuh agents to all k8s nodes"
wazuh_monitor_proxmox_vms
// Monitor Proxmox VMs
// Example: "Set up monitoring for all Proxmox VMs"
wazuh_integrate_cloudflare
// Cloudflare WAF integration
// Example: "Configure Cloudflare WAF event forwarding"
wazuh_integrate_github
// GitHub security alerts
// Example: "Ingest GitHub Dependabot alerts"
wazuh_monitor_unifi
// UniFi network monitoring
// Example: "Configure UniFi syslog forwarding"
Implementation Deep Dive {#implementation}
Project Structure
k3s-wazuh-mcp/
├── package.json # Node.js dependencies
├── Dockerfile # Multi-stage build
├── .env.example # Configuration template
├── src/
│ ├── index.js # Main MCP server
│ ├── config/
│ │ └── index.js # Config management
│ ├── api/
│ │ ├── client.js # Base Wazuh client
│ │ └── agents.js # Agent API wrapper
│ ├── tools/
│ │ ├── agent-tools.js # Agent management
│ │ ├── security-tools.js # Security operations
│ │ ├── monitoring-tools.js # Event monitoring
│ │ ├── rule-tools.js # Rule management
│ │ ├── cluster-tools.js # Cluster operations
│ │ └── integration-tools.js # Infrastructure
│ └── utils/
│ ├── logger.js # Winston logging
│ ├── metrics.js # Prometheus
│ └── cache.js # Caching layer
└── docs/
└── DEPLOYMENT_GUIDE.md # Deployment docs
Core: The MCP Server
src/index.js
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { WazuhClient } from './api/client.js';
class WazuhMCPServer {
constructor() {
this.server = new Server({
name: 'wazuh-mcp-server',
version: '1.0.0',
}, {
capabilities: {
tools: {}, // 25+ tools registered here
}
});
}
async initialize() {
// Initialize Wazuh API client
this.wazuhClient = new WazuhClient({
apiUrl: process.env.WAZUH_API_URL,
user: process.env.WAZUH_API_USER,
password: process.env.WAZUH_API_PASSWORD,
});
await this.wazuhClient.authenticate();
this.setupTokenRefresh();
this.registerTools();
}
setupTokenRefresh() {
// Auto-refresh JWT token every 15 minutes
setInterval(async () => {
const expiryBuffer = 5 * 60 * 1000; // 5 min before expiry
if (Date.now() > this.wazuhClient.tokenExpiry - expiryBuffer) {
await this.wazuhClient.authenticate();
}
}, 15 * 60 * 1000);
}
registerTools() {
// Register all 25+ tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
// Agent tools
{ name: 'wazuh_list_agents', ... },
{ name: 'wazuh_add_agent', ... },
// ... 23 more tools
]
}));
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case 'wazuh_list_agents':
return await this.handleListAgents(args);
// ... handle all 25+ tools
}
});
}
async start() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
}
}
// Start server
const server = new WazuhMCPServer();
await server.initialize();
await server.start();
Authentication: JWT with Auto-Refresh
src/api/client.js
import axios from 'axios';
import https from 'https';
export class WazuhClient {
constructor({ apiUrl, user, password, sslVerify = true }) {
this.apiUrl = apiUrl;
this.user = user;
this.password = password;
this.token = null;
this.tokenExpiry = null;
// Create axios instance
this.client = axios.create({
baseURL: apiUrl,
httpsAgent: new https.Agent({
rejectUnauthorized: sslVerify
}),
headers: {
'Content-Type': 'application/json'
}
});
// Request interceptor: add token
this.client.interceptors.request.use((config) => {
if (this.token) {
config.headers.Authorization = `Bearer ${this.token}`;
}
return config;
});
// Response interceptor: handle errors
this.client.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401) {
// Token expired, re-authenticate
await this.authenticate();
// Retry original request
return this.client.request(error.config);
}
throw error;
}
);
}
async authenticate() {
const response = await this.client.post(
'/security/user/authenticate',
{},
{
auth: {
username: this.user,
password: this.password
}
}
);
this.token = response.data.data.token;
this.tokenExpiry = Date.now() + 30 * 60 * 1000; // 30 minutes
logger.info('Wazuh JWT token acquired', {
expiry: new Date(this.tokenExpiry).toISOString()
});
}
async get(path, params = {}) {
const response = await this.client.get(path, { params });
return response.data;
}
async post(path, data = {}) {
const response = await this.client.post(path, data);
return response.data;
}
async put(path, data = {}) {
const response = await this.client.put(path, data);
return response.data;
}
async delete(path) {
const response = await this.client.delete(path);
return response.data;
}
}
Why this matters:
- Wazuh JWT tokens expire after 30 minutes
- Our interceptor automatically re-authenticates on 401 errors
- Background refresh every 15 minutes prevents expiry during operations
- Transparent to tool implementations
[… continuing with the rest of the markdown content exactly as provided …]
Author: Cortex Holdings Engineering Team Last Updated: December 20, 2025 Version: 1.0 Status: Production-Ready
“Security operations at the speed of thought, powered by AI.”