packmate/docs/MCP.md
2026-10-23 11:42:44 +03:00

20 KiB
Raw Permalink Blame History

MCP для Packmate

MCP работает отдельным контейнером и предоставляет 22 инструмента с единым полным доступом. Любой действительный токен может использовать каждый из них, включая создание и удаление сервисов, паттерны IGNORE, избранное и Lookback. Ролей analyst/operator/admin нет.

Запуск

В .env включите MCP и задайте случайный токен длиной не менее 32 ASCII-символов без пробелов:

PACKMATE_MCP_ENABLED=true
PACKMATE_MCP_TOKEN=<случайный-токен>
PACKMATE_MCP_BIND=127.0.0.1
PACKMATE_MCP_PORT=65002
PACKMATE_MCP_ALLOWED_HOSTS=127.0.0.1:*,localhost:*,[::1]:*
PACKMATE_MCP_JOB_TIMEOUT_SECONDS=30
PACKMATE_MCP_JOB_MAX_MIB=32
PACKMATE_PUBLIC_URL=http://your-packmate-host:65000

Сгенерировать токен: python3 -c 'import secrets; print(secrets.token_hex(32))'. Затем выполните обычную команду:

docker compose up --build -d

Endpoint: http://127.0.0.1:65002/mcp, транспорт Streamable HTTP. Клиент должен передавать Authorization: Bearer <токен> в каждом запросе. Токен задаётся в настройках MCP-клиента, а не в сообщениях агенту. Поле headers/переменная окружения для него зависит от конкретного клиента. Клиент без возможности передавать Bearer header не поддерживается. Встроенного OAuth-сервера нет.

Для подключения с другой машины можно использовать SSH-туннель:

ssh -N -L 65002:127.0.0.1:65002 user@your-packmate-host

Для прямого подключения через HTTPS reverse proxy настройте bind/allowed hosts под его адрес. Не ставьте произвольный * в allowed hosts. Browser Origin-запросы к MCP не разрешены; обычный серверный MCP-клиент работает без Origin. LIVE-захват рассчитан на Linux Docker Engine с host network; Docker Desktop видит сеть своей VM, а не все интерфейсы Windows.

По умолчанию MCP отключён: /healthz отвечает состоянием, остальные запросы получают 503. Отключение MCP не отключает Packmate. Активный MCP без корректного токена отказывается запускаться.

Сервисы и паттерны видны людям

Создавайте сервисы до начала анализа трафика: Packmate сохраняет стримы только известных сервисов. Все изменения MCP проходят через обычные backend-сервисы с их WebSocket-уведомлениями. Созданный агентом сервис появляется в навбаре, паттерн — в меню Patterns. FIND подсвечивает совпадения в новых пакетах; для истории используйте start_lookback. IGNORE означает удаление/несохранение будущих совпавших стримов, а не только скрытие в UI.

Пример аргументов create_service:

{
  "port": 8080,
  "settings": {
    "name": "Shop",
    "http": true,
    "urldecode_http_requests": true,
    "merge_adjacent_packets": true,
    "parse_web_sockets": false,
    "decrypt_tls": false
  }
}

Пример аргументов create_pattern:

{
  "settings": {
    "name": "Outgoing flags",
    "match": {"target": "content", "type": "regex", "value": "FLAG\\{[A-Za-z0-9_]+\\}"},
    "action": "FIND",
    "direction": "OUTPUT",
    "service_port": 8080,
    "color": "#ff9800"
  }
}

Для IP: target равен source_ip, destination_ip или either_ip, type — regex. Паттерны создаются включёнными. При повторе идентичного запроса возвращается существующий неудалённый объект; выключенный существующий паттерн автоматически не включается. Это проверка текущих данных перед созданием, не гарантия exactly-once при одновременной записи из нескольких независимых приложений. После ошибки сети проверьте список объектов.

update_pattern меняет имя и цвет. Для изменения выражения/направления/действия создайте новый паттерн и отключите старый: так исторические совпадения не получают новое значение задним числом. update_service принимает полную конфигурацию декодирования, а не частичный patch.

Инструменты

Инструменты Назначение
get_overview Захват, потери, очередь, настройки retention, сервисы, лимиты анализа
search_traffic Самостоятельный поиск по сохранённым сообщениям без создания паттерна
aggregate_traffic Число совпавших сообщений по сервисам, адресам или минутам
get_stream, read_packet Метаданные стрима, страницы сообщений и фрагменты payload
set_favorites Защита находок от retention, с подтверждением доступных ID
list_services, create_service, update_service, delete_service Общие с UI сервисы
list_patterns, validate_pattern, create_pattern, update_pattern, set_pattern_enabled, delete_pattern Общие с UI паттерны
start_lookback Сохранение исторических совпадений и обновление UI
get_job, get_job_results, cancel_job, delete_job Прогресс, результаты и управление задачами
start_pcap_import Запуск уже настроенного файла в режиме FILE

В этой версии нет изменения retention на лету, остановки/перезапуска LIVE capture, загрузки новых PCAP/TLS-ключей, экспорта исходного PCAP и журнала событий с долговечным курсором. Это следующие этапы API; ограничений по ролям на существующие инструменты нет.

Поиск и задачи

{
  "query": {
    "last_minutes": 5,
    "service_ports": [8080],
    "direction": "outgoing",
    "client_ip": {"type": "cidr", "value": "10.60.0.0/16"},
    "match": {"target": "content", "type": "regex", "value": "FLAG\\{[^}]+\\}"}
  },
  "limit": 100,
  "context_bytes": 160
}

search_traffic, aggregate_traffic и start_lookback сразу возвращают job_id. Вызывайте get_job примерно раз в секунду, затем get_job_results с offset и limit. Результаты содержат ссылки на нужный стрим в браузере. Одна выдача — максимум 50 результатов.

Время фильтрует начало сохранённого стрима. last_minutes фиксируется при создании задачи; эффективные from_ms, to_ms, snapshot_ms возвращаются в query. Все абсолютные времена — Unix milliseconds UTC. Окно — максимум 24 часа. source_ip/destination_ip относятся к сообщению, client_ip вычисляется с учётом incoming. Для адресов доступны exact/CIDR/regex. pattern_id отбирает стримы с уже сохранённым паттерном.

Поиск выполняется по сохранённому преобразованному содержимому. Оно может быть распаковано, декодировано или склеено настройками сервиса. Между отдельными сохранёнными сообщениями regex не переносится. Текст — UTF-8 с заменой некорректных последовательностей, точные байты — hex/base64. Конец диапазона в MCP — exclusive; текстовые смещения измеряются Unicode codepoints, бинарные — байтами. В UI остаются его прежние позиции совпадений.

Проверяйте coverage_complete, scan_exhausted, reason, skipped_oversize_packets и unavailable_packets. Завершившаяся задача с result_limit или byte_budget проверила только часть диапазона. Контент сообщений больше 64 KiB не обрезается для поиска, а пропускается с отдельным счётчиком: иначе regex с $ мог бы дать ложное совпадение на конце обрезанного фрагмента. Большой payload можно читать последовательно через read_packet.

Для продолжения частичного поиска передайте эффективный query предыдущей задачи и замените его cursor на next_scan_cursor. Порядок: (stream_timestamp, stream_id, packet_id). Это read-committed чтение живой БД, а не замороженный snapshot. Cleaner может удалять стримы между страницами; незакоммиченные или ещё собираемые соединения не входят в результаты. coverage_complete означает отсутствие известных пропусков в просмотренной доступной выборке, а не доказательство наличия всей истории сетевого трафика.

Lookback работает только для FIND; применяет сервис и направление самого паттерна. Совпадения записываются порциями до 16 сообщений. Повторное применение не дублирует найденные позиции. MCP Lookback сохраняет до 256 совпадений на сообщение, в том числе для старых literal-паттернов. Уже начатая очистка, занятая блокировка, слишком большой payload или более 2048 старых совпадений на сообщении дают unavailable_packets. Отмена останавливает дальнейшую работу; выполненные записи сохраняются, а текущая транзакция могла успеть закоммититься. Если ответ на запись Lookback не получен из-за отмены, таймаута или ошибки, курсор остаётся перед неподтверждённой страницей, а сообщения учитываются в unavailable_packets. Продолжение с этим курсором повторит страницу без дубликатов, вместо пропуска потенциально незаписанных подсветок.

Одновременно доступны две задачи, хранится максимум 32 задачи, TTL результатов — 15 минут после завершения. Для освобождения места используйте delete_job. Задачи и результаты хранятся в памяти MCP и теряются при его перезапуске; созданные сервисы/паттерны и Lookback-совпадения остаются в БД.

Ограничение нагрузки

MCP имеет отдельный контейнер (1 CPU, 512 MiB), ограниченные кеши regex и две задачи анализа. Backend читает через отдельный пул из двух read-only соединений с SQL timeout 2 секунды. Страницы содержат максимум 32 сообщения и 64 KiB на сообщение. В MCP используется 16 сообщений на запрос, между страницами есть пауза. При занятых слотах возвращается BUSY. Бюджет задачи по умолчанию 30 секунд / 32 MiB прочитанного payload с оценкой метаданных. Диск и PostgreSQL общие с захватом, поэтому физическая изоляция нагрузки не абсолютная.

Новые MCP regex-паттерны используют RE2J при обработке трафика и RE2 при разовом поиске. Backreferences/lookaround не поддерживаются, неподдерживаемый синтаксис отклоняется. validate_pattern проверяет regex в обоих движках, включая ограничения RE2J, до сохранения. Для новых паттернов сохраняется до 256 совпадений на сообщение. Старые Java regex сохраняют прежний движок; MCP Lookback для них требует создания нового RE2J-паттерна.

Проверка

Unit checks:

docker build -t packmate-mcp:dev mcp
docker run --rm -v "$PWD/mcp:/app:ro" packmate-mcp:dev python -m unittest discover -s tests -p 'test_*.py' -v
./gradlew test --tests '*SafePatternMatcherTest' --tests '*PatternMatcherConcurrencyTest'

Интеграционный тест создаёт отдельную сеть и отдельную БД. Команды из корня репозитория:

./gradlew bootJar
docker build -t registry.gitlab.com/packmate/packmate:latest -f docker/Dockerfile_app .
docker build -t packmate-mcp:dev mcp
docker compose -p packmate-mcp-test -f stress/network/docker-compose.yml -f mcp/tests/compose.yml build target
docker compose -p packmate-mcp-test -f stress/network/docker-compose.yml -f mcp/tests/compose.yml up --no-build -d db target packmate mcp
docker compose -p packmate-mcp-test -f stress/network/docker-compose.yml -f mcp/tests/compose.yml run --rm --no-deps tester
docker compose -p packmate-mcp-test -f stress/network/docker-compose.yml -f mcp/tests/compose.yml down -v

Тест вызывает настоящий MCP Streamable HTTP, проверяет уведомления браузера, живые совпадения, IP regex, Lookback и повторное применение. Затем выполняет 3000 TCP-соединений одновременно с regex-задачами и удалением старой выборки из 200 стримов. Проверяет сохранность новых стримов, избранного, отсутствие drops и orphan packets, REST p99 < 500 мс. Отчёт: build/reports/mcp/integration.json. Это целевой тест MCP; большой профиль на 250000 соединений из docs/CLEANUP.md он не заменяет.

Увеличенный профиль (PowerShell, из корня, после сборки образов и bootJar выше):

docker compose -p packmate-mcp-capacity -f stress/network/docker-compose.yml -f mcp/tests/compose.yml -f mcp/tests/capacity.yml build target
./mcp/tests/run-capacity.ps1

Профиль проверяет 2000 исходных и 50000 новых TCP-соединений с минимальной длительностью передачи 120 секунд, по 8 сообщений по 1024 байта в каждом направлении. Сверяются хеши полного содержимого каждого соединения, IP, метаданные, live-паттерны и избранное. Одновременно работают cleaner и MCP, а MCP-контейнер перезапускается во время нагрузки. Дополнительно проверяются BUSY, отмена, бюджеты, курсор, 96 KiB binary payload и повторный Lookback старого literal-паттерна с лимитом подсветок. Тест намеренно использует бюджеты MCP 10 секунд / 2 MiB, чтобы проверить оба ограничения. Захват использует 8 workers; это параметр теста, а не обещание такой скорости с любыми настройками. MCP_STRESS_STREAMS и MCP_STRESS_SECONDS меняют нагрузку. Отчёт: build/reports/mcp/capacity.json. Скрипт удаляет только свой disposable Compose-проект; -KeepContainers оставляет его для диагностики.

Длительный прогон на 35 минут, с обычным retention 15 минут и запуском cleaner раз в 10 секунд:

docker compose -p packmate-mcp-soak -f stress/network/docker-compose.yml -f mcp/tests/compose.yml -f mcp/tests/soak.yml build target
docker compose -p packmate-mcp-soak -f stress/network/docker-compose.yml -f mcp/tests/compose.yml -f mcp/tests/soak.yml up --no-build -d db target packmate mcp
docker compose -p packmate-mcp-soak -f stress/network/docker-compose.yml -f mcp/tests/compose.yml -f mcp/tests/soak.yml run --rm --no-deps tester
docker compose -p packmate-mcp-soak -f stress/network/docker-compose.yml -f mcp/tests/compose.yml -f mcp/tests/soak.yml down -v

Не запускайте эти сетевые профили одновременно: они используют один тестовый subnet. Soak создаёт пачки по 500 соединений за 10 секунд, сверяет все payload до истечения retention, сохраняет один стрим каждой пачки в избранное и непрерывно выполняет MCP regex-поиск. Время записей в БД не подменяется: проверяется естественное удаление старого трафика. Отчёты: soak.json, soak-samples.json, soak-loads.json; текущий прогресс — soak-progress.json в build/reports/mcp. MCP_SOAK_SECONDS позволяет увеличить длительность.

Фактические параметры и результаты прогона: MCP_TEST_RESULTS.md. mcp/tests/deployment.py дополнительно проверяет настоящий SDK, валидацию обоих regex-движков и изменения общих сервисов/паттернов внутри отдельного production Compose в режиме VIEW.