20 KiB
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.