Wazuh MCP Server: Claude Desktop + OpenSearch (Часть 2)

Введение

В Части 1 мы подключили AWS Bedrock Claude к чату Wazuh Dashboard через ML Commons. Этот путь отлично подходит для аналитиков, работающих внутри Wazuh UI. В этой части мы открываем второй канал: Model Context Protocol (MCP), который позволяет любому совместимому клиенту - Claude Desktop, пользовательским приложениям, CI-пайплайнам - обращаться к данным Wazuh Indexer через стандартизированный интерфейс инструментов.

Мы добавим opensearch-mcp-server-py (официальный MCP-сервер OpenSearch, лицензия Apache 2.0) четвёртым сервисом в тот же docker-compose.yml и откроем его на порту 9900. Этот сервис говорит на языке MCP Streamable HTTP и оборачивает REST API Wazuh Indexer в готовые инструменты: SearchIndexTool, LogPatternAnalysisTool, DataDistributionTool и другие.

Почему не встроенный MCP-сервер OpenSearch? Встроенный эндпоинт /_plugins/_ml/mcp появился в OpenSearch 3.0. Wazuh Indexer 4.14.x работает на OpenSearch 2.19.x и не получит бэкпорт функции до 3.x. Standalone Python-сервер работает с любой версией OpenSearch.

Что такое Model Context Protocol (MCP)

Model Context Protocol - открытый стандарт от Anthropic для подключения LLM к внешним источникам данных и инструментам. MCP определяет единый интерфейс взаимодействия между клиентом (Claude Desktop, IDE, пользовательское приложение) и сервером (любой источник данных).

Ключевые концепции:

  • MCP-сервер - процесс, который предоставляет набор инструментов (tools). Каждый инструмент имеет имя, описание и JSON Schema для входных параметров. В нашем случае сервер opensearch-mcp-server-py оборачивает REST API OpenSearch в 11 инструментов
  • MCP-клиент - приложение, которое подключается к серверу и вызывает инструменты от имени LLM. Claude Desktop, Claude Code, Amazon Q Developer CLI - примеры клиентов
  • Transport - способ связи между клиентом и сервером. Поддерживаются stdio (локальный процесс) и stream (SSE/HTTP по сети)

LLM не вызывает API напрямую. Вместо этого она получает список доступных инструментов с описаниями, формирует вызов с нужными параметрами, а клиент передаёт его серверу и возвращает результат. Это позволяет одному MCP-серверу обслуживать любого совместимого клиента без интеграционного кода.

Архитектура

Архитектурная диаграмма: Claude Desktop -> mcp-remote -> opensearch-mcp-server -> Wazuh Indexer

Схема взаимодействия компонентов MCP-интеграции с Wazuh

Claude Desktop запускает mcp-remote как дочерний процесс через stdio. mcp-remote устанавливает SSE-соединение с wazuh.opensearch-mcp на порту 9900. MCP-сервер транслирует вызовы инструментов в REST API запросы к Wazuh Indexer (OpenSearch 2.19.x) по HTTPS с self-signed сертификатами внутри Docker bridge-сети.

Добавление MCP-сервиса в Docker Compose

Создадим папку для Dockerfile:

mkdir -p wazuh-docker/single-node/config/mcp

Создаём wazuh-docker/single-node/config/mcp/Dockerfile:

FROM python:3.12-slim AS builder

RUN pip install --no-cache-dir --prefix=/install opensearch-mcp-server-py

FROM python:3.12-slim

LABEL maintainer="pyToshka" \
      description="OpenSearch MCP Server for Wazuh Indexer"

RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    rm -rf /var/lib/apt/lists/* && \
    groupadd -r mcp && useradd -r -g mcp -d /app -s /sbin/nologin mcp

COPY --from=builder /install /usr/local

ENV OPENSEARCH_SSL_VERIFY="false" \
    OPENSEARCH_ENABLED_CATEGORIES="core_tools,skills_tools"

EXPOSE 9900

USER mcp

HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD curl -sf http://localhost:9900/health || exit 1

ENTRYPOINT ["python", "-m", "mcp_server_opensearch", \
            "--transport", "stream", "--host", "0.0.0.0"]

Зависимости устанавливаются на этапе сборки образа, поэтому контейнер стартует мгновенно без повторного pip install при каждом рестарте.

Добавьте следующий сервис в существующий docker-compose.yml после сервиса wazuh.dashboard:

  wazuh.opensearch-mcp:
    build: ./config/mcp
    hostname: wazuh.opensearch-mcp
    restart: always
    ports:
      - "9900:9900"
    environment:
      - OPENSEARCH_URL=https://wazuh.indexer:9200
      - OPENSEARCH_USERNAME=${INDEXER_USERNAME}
      - OPENSEARCH_PASSWORD=${INDEXER_PASSWORD}
    depends_on:
      - wazuh.indexer

Сервер работает в single mode и получает все настройки через переменные окружения. OPENSEARCH_SSL_VERIFY=false и OPENSEARCH_ENABLED_CATEGORIES заданы в Dockerfile по умолчанию. OPENSEARCH_SSL_VERIFY=false отключает проверку сертификата внутри Docker-сети, где используются self-signed certs. Трафик не покидает bridge-сеть docker-compose.

Собираем и запускаем:

docker compose up -d --build
docker compose ps

Проверка сервиса

Проверяем что health-эндпоинт отвечает:

curl -sf http://localhost:9900/health

Получаем список доступных инструментов через MCP-эндпоинт:

curl -s -X POST http://localhost:9900/mcp/ \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \
  | grep '^data: ' | sed 's/^data: //' \
  | jq '[.result.tools[].name]'

Ожидаемый ответ:

[
  "DataDistributionTool",
  "LogPatternAnalysisTool",
  "ListIndexTool",
  "IndexMappingTool",
  "SearchIndexTool",
  "GetShardsTool",
  "GenericOpenSearchApiTool",
  "ClusterHealthTool",
  "CountTool",
  "MsearchTool",
  "ExplainTool"
]

Подключение Claude Desktop

Создайте или обновите файл конфигурации Claude Desktop.

macOS:

"$HOME/Library/Application Support/Claude/claude_desktop_config.json"

Linux:

~/.config/claude/claude_desktop_config.json

Claude Desktop не поддерживает прямое подключение к remote MCP-серверу по URL. Для связи со streaming-сервером используется mcp-remote - npm-пакет, который выступает мостом между stdio-интерфейсом Claude Desktop и remote SSE-эндпоинтом.

Добавьте сервер wazuh в секцию mcpServers:

{
  "mcpServers": {
    "wazuh": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://localhost:9900/sse"
      ]
    }
  }
}

Флаг -y автоматически подтверждает установку mcp-remote при первом запуске. Требуется установленный Node.js.

Перезапустите Claude Desktop. В разделе Connectors появится сервер wazuh с пометкой LOCAL DEV и все 11 инструментов:

Claude Desktop Connectors: сервер wazuh подключён с 11 инструментами OpenSearch

Сервер wazuh в панели Connectors Claude Desktop с полным списком MCP-инструментов

Использование MCP-инструментов из Claude Desktop

После подключения можно задавать Claude Desktop вопросы, которые вызывают инструменты с обращением к живым данным Wazuh.

Просмотр индексов

Покажи все индексы wazuh-* с количеством документов, отсортируй по размеру.

При первом вызове инструмента Claude Desktop запросит разрешение на использование. Нажмите Always allow для автоматического одобрения последующих вызовов к серверу wazuh.

Claude Desktop запрашивает разрешение на использование GenericOpenSearchApiTool из MCP-сервера wazuh

Claude Desktop запрашивает разрешение на вызов MCP-инструмента

Claude вызовет ListIndexTool и отформатирует ответ в виде читаемой таблицы:

Таблица индексов Wazuh с количеством документов и размером

Результат ListIndexTool: таблица индексов wazuh-* отсортированная по размеру

Аналитическая сводка по индексам Wazuh от Claude

Claude анализирует состав индексов и выделяет ключевые метрики

Поиск алертов

Найди последние 50 алертов с уровнем правила 10 и выше за последние 2 часа.
Верни имя агента, описание правила, IP источника и метку времени.

Это запускает SearchIndexTool с автоматически сконструированным телом Query DSL для индекса wazuh-alerts-4.x-*.

Сводка по распределению уровней алертов Wazuh

Claude сначала анализирует распределение уровней алертов в системе

Таблица алертов Wazuh с CIS Benchmark findings

Таблица алертов уровня 7: результаты CIS Benchmark сканирования

Анализ состава алертов и рекомендации от Claude

Claude объясняет состав алертов и даёт рекомендации по настройке

Анализ паттернов логов

Проанализируй паттерны логов аутентификации в wazuh-alerts-4.x-* за сегодня.
Сравни со вчерашним днём как baseline и выдели аномальные всплески.

LogPatternAnalysisTool выполняет сравнение baseline vs текущего периода и возвращает обнаруженные отклонения паттернов.

Итог анализа паттернов логов: данные для сравнения отсутствуют

Claude анализирует активность по дням и объясняет отсутствие auth-логов

Сравнение сегодня vs вчера и таблица CIS SCA findings по SSH

Baseline-сравнение и auth-релевантные CIS SCA findings

Распределение значений полей

Покажи распределение поля rule.groups в wazuh-alerts-4.x-* за последние 24 часа.

DataDistributionTool возвращает частотное распределение значений поля - удобно для понимания состава алертов с первого взгляда.

Claude Desktop вызывает DataDistributionTool для анализа распределения rule.groups

Claude задействует DataDistributionTool с историческим сравнением

Визуализация распределения rule.groups: sca vs ossec с графиком активности по дням

Многоуровневая визуализация: распределение за 24 часа, за всё время и активность по дням

Анализ распределения rule.groups с рекомендациями по настройке агентов

Claude анализирует состав групп и даёт рекомендации по подключению агентов

Здоровье кластера

Проверь состояние кластера Wazuh Indexer: статус, количество нод, шардов и pending tasks.

ClusterHealthTool возвращает состояние кластера (green/yellow/red), количество нод и шардов, незавершённые задачи. Быстрая проверка работоспособности без захода в Dashboard.

Дашборд здоровья кластера: green, 1 нода, 35 шардов, 0 pending tasks

ClusterHealthTool: статус кластера, ресурсы ноды и распределение шардов по типам индексов

Детальный анализ состояния кластера с рекомендациями по heap и шардам

Claude анализирует каждый показатель и предупреждает о heap 61%

Полная таблица шардов кластера Wazuh Indexer

Детализация всех 35 шардов: индексы, состояние, количество документов и размер

Структура индекса

Покажи маппинг полей индекса wazuh-alerts-4.x-* - какие поля доступны для поиска?

IndexMappingTool возвращает полную схему индекса: имена полей, типы данных, анализаторы. Полезно перед построением сложных DSL-запросов, чтобы знать какие поля существуют и какого они типа.

Claude Desktop вызывает IndexMappingTool для получения маппинга wazuh-alerts

Claude вызывает IndexMappingTool и готовит интерактивный справочник

Интерактивный справочник полей индекса wazuh-alerts: 230+ полей в 10 категориях

230+ полей сгруппированы по категориям: Core, Rule, Agent, Data, SCA, Syscheck, Cloud, Decoder, MITRE, Geo

Анализ особенностей маппинга: dynamic template, типы IP-полей, compliance-поля

Claude объясняет особенности маппинга: dynamic template, различие ip vs keyword, compliance-поля

Подсчёт алертов

Сколько алертов в каждом индексе wazuh-alerts-4.x-* за последнюю неделю?
Разбей по дням.

CountTool и MsearchTool позволяют быстро оценить объём данных без загрузки самих документов. Claude может комбинировать несколько вызовов для построения временной шкалы активности.

График алертов по дням за неделю: 187 алертов в 2 индексах

Визуализация активности: 187 алертов за неделю, активность только в 2 из 8 дней

Разбивка алертов по дням и индексам с анализом пробелов

Детальная разбивка по дням и индексам с объяснением 6-дневного пробела

Агрегация по source IP

Найди топ-10 source IP по количеству алертов в wazuh-alerts-4.x-* за последнюю неделю.
Используй агрегацию terms по полю data.srcip.

SearchIndexTool поддерживает полный синтаксис Query DSL включая агрегации. Claude автоматически конструирует запрос с terms aggregation и форматирует результат в читаемую таблицу.

Анализ отсутствия data.srcip: все алерты от SCA-проверок без сетевого источника

Claude объясняет почему data.srcip пусто и какие события его заполняют

Готовый DSL-запрос с terms aggregation по data.srcip

Claude генерирует готовый DSL-запрос для использования после подключения агентов

Произвольные API-вызовы

Через GenericOpenSearchApiTool выполни:
GET /_cat/indices/wazuh-*?h=index,docs.count,store.size&s=docs.count:desc&v

GenericOpenSearchApiTool позволяет вызывать любой эндпоинт OpenSearch с произвольным путём, методом, параметрами и телом запроса - мощный запасной вариант для операций, не охваченных специализированными инструментами.

Результат GenericOpenSearchApiTool: сырой вывод _cat/indices с 19 индексами Wazuh

GenericOpenSearchApiTool выполняет произвольный API-запрос и возвращает сырой вывод _cat

Справочник инструментов

Core Tools (включены по умолчанию)

ИнструментОписание
ListIndexToolСписок индексов с метаданными (docs, size, health)
IndexMappingToolМаппинги полей и настройки любого индекса
SearchIndexToolQuery DSL-поиск, до 100 документов за вызов
GetShardsToolИнформация о шардах и их распределении по нодам
ClusterHealthToolСтатус здоровья кластера и счётчики шардов
CountToolПодсчёт документов по запросу
ExplainToolОбъяснение scoring для конкретного документа и запроса
MsearchToolВыполнение нескольких поисковых запросов за один вызов
GenericOpenSearchApiToolПроизвольный API-вызов с кастомным путём, методом, телом

Skills Tools (включены по умолчанию)

ИнструментОписание
DataDistributionToolАнализ частотного распределения значений полей
LogPatternAnalysisToolОбнаружение аномальных паттернов логов относительно baseline

Набор категорий контролируется через OPENSEARCH_ENABLED_CATEGORIES. По умолчанию включены core_tools и skills_tools. Дополнительные категории (search_relevance и другие) можно включить при необходимости.

Переменные окружения

ПеременнаяОписаниеЗначение по умолчанию
OPENSEARCH_URLURL кластера OpenSearch(обязательная)
OPENSEARCH_USERNAMEИмя пользователя для basic auth(обязательная)
OPENSEARCH_PASSWORDПароль для basic auth(обязательная)
OPENSEARCH_SSL_VERIFYПроверка SSL-сертификатаtrue
OPENSEARCH_TIMEOUTТаймаут подключения (секунды)-
OPENSEARCH_MAX_RESPONSE_SIZEМаксимальный размер ответа (байты)10485760 (10 MB)
OPENSEARCH_ENABLED_CATEGORIESВключённые категории инструментовcore_tools,skills_tools
OPENSEARCH_DISABLED_CATEGORIESОтключённые категории-
OPENSEARCH_ENABLED_TOOLSСписок включённых инструментов (через запятую)-
OPENSEARCH_DISABLED_TOOLSСписок отключённых инструментов (через запятую)-
OPENSEARCH_ENABLED_TOOLS_REGEXRegex-паттерн для включения инструментов-
OPENSEARCH_DISABLED_TOOLS_REGEXRegex-паттерн для отключения инструментов-
OPENSEARCH_TOOL_CATEGORIESJSON-строка с определением кастомных категорий-
OPENSEARCH_SETTINGS_ALLOW_WRITEРазрешить write-операцииtrue
OPENSEARCH_NO_AUTHПодключение без аутентификацииfalse
OPENSEARCH_HEADER_AUTHHeader-based аутентификацияfalse
OPENSEARCH_MEMORY_MONITOR_INTERVALИнтервал мониторинга памяти (секунды)60

Для AWS-аутентификации (IAM) вместо basic auth:

ПеременнаяОписание
AWS_IAM_ARNARN IAM-роли
AWS_REGIONРегион AWS
AWS_ACCESS_KEY_IDAccess Key
AWS_SECRET_ACCESS_KEYSecret Key
AWS_SESSION_TOKENSession Token (временные credentials)
AWS_PROFILEИмя AWS-профиля
AWS_OPENSEARCH_SERVERLESStrue для OpenSearch Serverless (AOSS)

Полезные ссылки


Навигация по серии:


Смотрите также