@modular-intelligence/siem-query
v1.0.2
Published
MCP server for multi-SIEM query interface (Splunk, Elasticsearch, Wazuh)
Downloads
24
Readme
SIEM Query MCP Server
A comprehensive multi-SIEM query interface that provides unified access to multiple security information and event management (SIEM) platforms. This MCP (Model Context Protocol) server enables Claude to execute queries across Splunk, Elasticsearch, and Wazuh, with additional tools for query translation, validation, and explanation.
Overview
This server provides access to three major SIEM platforms through a unified interface, plus utility tools for working with SIEM queries:
- Splunk - Execute SPL (Search Processing Language) queries for log analysis and security investigations
- Elasticsearch - Execute KQL/Lucene queries for distributed search and analytics
- Wazuh - Query Wazuh alerts, events, and security monitoring data
Query utilities include Sigma rule translation, syntax validation, and natural language query explanations.
Perfect for security investigations, threat hunting, alert correlation, query optimization, and SIEM-agnostic threat detection.
Tools
| Tool | SIEM | Description |
|------|------|-------------|
| splunk-search | Splunk | Execute SPL queries with flexible time ranges and result limits |
| elastic-search | Elasticsearch | Execute KQL/Lucene queries for document search and analysis |
| wazuh-search | Wazuh | Query Wazuh alerts and security events with agent filtering |
| query-translate | All | Translate Sigma detection rules to SIEM-specific query syntax |
| query-validate | All | Validate query syntax and detect potential errors or issues |
| query-explain | All | Generate plain English explanations of SIEM queries |
Splunk Search
Execute SPL queries against a Splunk instance to search logs and events.
Input Parameters:
{
query: string // SPL search query (e.g., "error OR failed")
index: string // Splunk index to search (optional, default: main)
time_range: string // Time range in Splunk format (e.g., "-24h")
max_results: number // Maximum number of results to return (1-10000)
}Example Request:
{
"query": "EventCode=4625 | stats count by src_ip",
"index": "security",
"time_range": "-24h",
"max_results": 100
}Example Output:
{
"platform": "splunk",
"query": "search index=security EventCode=4625 | stats count by src_ip earliest=-24h | head 100",
"results": [
{
"src_ip": "192.168.1.100",
"count": 42
},
{
"src_ip": "10.0.0.50",
"count": 18
},
{
"src_ip": "172.16.0.20",
"count": 5
}
],
"count": 3,
"time_range": "-24h"
}Elasticsearch Search
Execute KQL or Lucene queries against an Elasticsearch cluster.
Input Parameters:
{
query: string // KQL or Lucene query string
index: string // Index pattern to search (e.g., "logs-*")
time_range: string // Time range in Splunk format (e.g., "-1h")
max_results: number // Maximum number of results to return (1-10000)
}Example Request:
{
"query": "status:500 AND method:POST",
"index": "logs-web-*",
"time_range": "-1h",
"max_results": 50
}Example Output:
{
"platform": "elasticsearch",
"query": "status:500 AND method:POST",
"index": "logs-web-*",
"results": [
{
"@timestamp": "2024-01-15T10:30:45.123Z",
"status": 500,
"method": "POST",
"path": "/api/users",
"response_time": 2500,
"error": "Database connection timeout"
},
{
"@timestamp": "2024-01-15T10:31:20.456Z",
"status": 500,
"method": "POST",
"path": "/api/events",
"response_time": 1800,
"error": "Memory limit exceeded"
}
],
"count": 2,
"time_range": "-1h"
}Wazuh Search
Query Wazuh alerts and security events with optional agent filtering.
Input Parameters:
{
query: string // Wazuh query in key=value format (e.g., "rule.level=10")
agent_id: string // Wazuh agent ID to filter by (optional)
time_range: string // Time range in Splunk format (e.g., "-7d")
max_results: number // Maximum number of results to return (1-10000)
}Example Request:
{
"query": "rule.level=10;rule.groups=web_application_attack",
"agent_id": "001",
"time_range": "-7d",
"max_results": 200
}Example Output:
{
"platform": "wazuh",
"query": "rule.level=10;rule.groups=web_application_attack",
"agent_id": "001",
"results": [
{
"timestamp": "2024-01-14T15:30:00.000Z",
"rule": {
"id": 31105,
"level": 10,
"description": "SQL injection attempt detected",
"groups": ["web_application_attack", "attack_attempt"]
},
"agent": {
"id": "001",
"name": "web-server-01"
},
"data": {
"srcip": "203.0.113.45",
"dstip": "192.0.2.1",
"http_method": "POST",
"uri": "/api/search?q=1' OR '1'='1"
}
},
{
"timestamp": "2024-01-14T16:45:30.000Z",
"rule": {
"id": 31108,
"level": 10,
"description": "XSS attempt detected",
"groups": ["web_application_attack"]
},
"agent": {
"id": "001",
"name": "web-server-01"
},
"data": {
"srcip": "203.0.113.46",
"dstip": "192.0.2.1",
"http_method": "GET",
"uri": "/search?q=<script>alert('xss')</script>"
}
}
],
"count": 2,
"time_range": "-7d"
}Query Translate
Translate Sigma detection rules to SIEM-specific query syntax.
Input Parameters:
{
sigma_rule: string // Sigma rule in YAML format
target_siem: string // Target SIEM: "splunk", "elastic", or "wazuh"
}Example Request:
{
"sigma_rule": "title: Suspicious PowerShell Download\ndescription: Detects PowerShell used to download files\ndetection:\n selection:\n EventID: 4688\n CommandLine: '*DownloadFile*'\n condition: selection\nlogsource:\n product: windows\n service: security",
"target_siem": "splunk"
}Example Output:
{
"source": "sigma",
"target_siem": "splunk",
"original_title": "Suspicious PowerShell Download",
"translated_query": "sourcetype=\"windows\" EventID=\"4688\" CommandLine=\"*DownloadFile*\"",
"logsource": {
"product": "windows",
"service": "security"
}
}Query Validate
Validate query syntax for target SIEM platforms and detect potential errors.
Input Parameters:
{
query: string // Query string to validate
target_siem: string // Target SIEM: "splunk", "elastic", or "wazuh"
}Example Request:
{
"query": "index=main source=\"*.log\" | stats count by host",
"target_siem": "splunk"
}Example Output:
{
"valid": true,
"errors": [],
"warnings": [],
"query": "index=main source=\"*.log\" | stats count by host",
"target_siem": "splunk"
}Query Explain
Generate plain English explanations of SIEM queries to understand what they do.
Input Parameters:
{
query: string // Query string to explain
target_siem: string // Target SIEM: "splunk", "elastic", or "wazuh"
}Example Request:
{
"query": "index=security EventCode=4625 | stats count by src_ip | sort -count",
"target_siem": "splunk"
}Example Output:
{
"summary": "Search and process events through 2 transformation step(s)",
"breakdown": [
"Search for events matching: EventCode=4625",
"Calculate statistics: count by src_ip",
"Sort results by: -count"
],
"query": "index=security EventCode=4625 | stats count by src_ip | sort -count",
"target_siem": "splunk"
}Configuration
Environment Variables
This server requires connection details for one or more SIEM platforms. Set these environment variables before running:
export SPLUNK_URL="https://your-splunk-instance:8089"
export SPLUNK_TOKEN="your-splunk-api-token"
export ELASTIC_URL="https://your-elasticsearch-instance:9200"
export ELASTIC_API_KEY="your-elasticsearch-api-key"
export WAZUH_URL="https://your-wazuh-instance:55000"
export WAZUH_USER="your-wazuh-username"
export WAZUH_PASSWORD="your-wazuh-password"Getting Credentials
Splunk
- Access your Splunk instance at https://your-splunk-instance:8089
- Navigate to Settings -> Tokens to create or retrieve an API token
- Use the token for SPLUNK_TOKEN
- URL format: https://splunk-host:8089 (default port is 8089)
Elasticsearch
- Access your Elasticsearch cluster at https://your-elastic-instance:9200
- Generate an API key via Management -> Dev Tools -> Elasticsearch API
- Use the encoded API key for ELASTIC_API_KEY
- URL format: https://elastic-host:9200
Wazuh
- Access your Wazuh manager API at https://your-wazuh-instance:55000
- Default credentials are admin/admin (change immediately in production)
- Uses Basic Auth with username and password
- URL format: https://wazuh-host:55000
Installation
Prerequisites
- Bun runtime (version 1.x or later)
- Node.js 18+ (alternative runtime)
- Network access to at least one configured SIEM platform
- Valid credentials or API keys for your SIEM instances
Steps
- Clone or download this repository:
git clone <repo-url>
cd siem-query- Install dependencies:
bun install- Build the project:
bun run build- Set environment variables:
export SPLUNK_URL="https://your-splunk:8089"
export SPLUNK_TOKEN="your-token"
export ELASTIC_URL="https://your-elastic:9200"
export ELASTIC_API_KEY="your-key"
export WAZUH_URL="https://your-wazuh:55000"
export WAZUH_USER="username"
export WAZUH_PASSWORD="password"- Run the server:
bun run startThe server will start listening on stdio transport.
Usage
Running the Server
Start the server with Bun:
bun run src/index.tsThe server implements the Model Context Protocol (MCP) and communicates via stdio transport. It can be integrated with Claude or other MCP clients.
Claude Desktop Configuration
Add the server to your Claude Desktop configuration at ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"siem-query": {
"command": "bun",
"args": [
"run",
"/path/to/siem-query/src/index.ts"
],
"env": {
"SPLUNK_URL": "https://your-splunk:8089",
"SPLUNK_TOKEN": "your-splunk-token",
"ELASTIC_URL": "https://your-elasticsearch:9200",
"ELASTIC_API_KEY": "your-elasticsearch-key",
"WAZUH_URL": "https://your-wazuh:55000",
"WAZUH_USER": "your-wazuh-username",
"WAZUH_PASSWORD": "your-wazuh-password"
}
}
}
}Claude Code MCP Settings
Configure the server in Claude Code's MCP settings (typically in .mcp.json or via settings UI):
{
"servers": {
"siem-query": {
"transport": "stdio",
"command": "bun",
"args": ["run", "/path/to/siem-query/src/index.ts"],
"env": {
"SPLUNK_URL": "https://your-splunk:8089",
"SPLUNK_TOKEN": "your-splunk-token",
"ELASTIC_URL": "https://your-elasticsearch:9200",
"ELASTIC_API_KEY": "your-elasticsearch-key",
"WAZUH_URL": "https://your-wazuh:55000",
"WAZUH_USER": "your-wazuh-username",
"WAZUH_PASSWORD": "your-wazuh-password"
}
}
}
}Example Usage in Claude
Once configured, you can use the tools directly in conversations with Claude:
Request: "Search Splunk for failed login attempts in the last 24 hours and show me the top 10 source IPs"
Claude will call:
{
"tool": "splunk-search",
"input": {
"query": "EventCode=4625 | stats count by src_ip | sort -count",
"index": "security",
"time_range": "-24h",
"max_results": 10
}
}Request: "Check Elasticsearch for HTTP 500 errors in the last hour"
Claude will call:
{
"tool": "elastic-search",
"input": {
"query": "status:500",
"index": "logs-*",
"time_range": "-1h",
"max_results": 100
}
}Request: "Translate this Sigma rule to Splunk format: [Sigma YAML rule]"
Claude will call:
{
"tool": "query-translate",
"input": {
"sigma_rule": "title: Suspicious Activity\ndetection:\n selection:\n EventID: 4688\n condition: selection",
"target_siem": "splunk"
}
}Request: "Validate this Splunk query and check for syntax errors: index=main | stats count"
Claude will call:
{
"tool": "query-validate",
"input": {
"query": "index=main | stats count",
"target_siem": "splunk"
}
}Request: "Explain what this Wazuh query does: rule.level=10;agent.id=001"
Claude will call:
{
"tool": "query-explain",
"input": {
"query": "rule.level=10;agent.id=001",
"target_siem": "wazuh"
}
}Security
This server implements comprehensive security controls to prevent injection attacks, enforce read-only access, and protect sensitive credentials:
Query Restrictions
Splunk SPL Blocking
- Blocked destructive commands: delete, sendalert, outputlookup, outputcsv, collect, mcollect
- No shell command injection characters allowed: semicolons, ampersands, backticks, dollar signs
- Maximum query length: 5,000 characters
- All queries are read-only searches only
Elasticsearch Protection
- No destructive HTTP methods allowed (DELETE, PUT)
- Write operations blocked at query validation layer
- Maximum query length: 5,000 characters
- Only read operations permitted (GET, POST searches)
Wazuh Query Restrictions
- Query format strictly enforced as key=value pairs separated by semicolons
- No shell metacharacters allowed: semicolons, ampersands, backticks, dollar signs
- Maximum query length: 5,000 characters
- Alert queries only, no configuration modifications
Credential Protection
- All credentials passed via environment variables only
- No credentials logged or returned in responses
- Credentials never sent to Claude or logged in query results
- API keys and passwords handled securely in memory
Input Validation
- Query syntax validation before execution
- Malicious command detection (regex-based blocking)
- Parenthesis and quote matching verification
- Special character validation for each SIEM type
- Query length limits enforced pre-execution
What Gets Blocked
The server rejects:
- Queries containing blocked destructive SPL commands
- Elasticsearch DELETE/PUT operations
- Queries exceeding 5,000 character limit
- Queries with unmatched quotes or parentheses
- Queries containing shell injection metacharacters
- Missing or invalid SIEM configuration variables
- Elasticsearch write operations
Error Handling
- Invalid queries return descriptive error messages
- API authentication failures reported with guidance
- Configuration errors provide setup instructions
- Network timeouts handled gracefully
- Invalid input caught before SIEM queries execute
License
ISC License - see LICENSE file for details
