# MCP для Packmate MCP работает отдельным контейнером и предоставляет **22 инструмента с единым полным доступом**. Любой действительный токен может использовать каждый из них, включая создание и удаление сервисов, паттерны IGNORE, избранное и Lookback. Ролей analyst/operator/admin нет. ## Запуск В `.env` включите MCP и задайте случайный токен длиной не менее 32 ASCII-символов без пробелов: ```dotenv 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))'`. Затем выполните обычную команду: ```bash docker compose up --build -d ``` Endpoint: `http://127.0.0.1:65002/mcp`, транспорт **Streamable HTTP**. Клиент должен передавать `Authorization: Bearer <токен>` в каждом запросе. Токен задаётся в настройках MCP-клиента, а не в сообщениях агенту. Поле headers/переменная окружения для него зависит от конкретного клиента. Клиент без возможности передавать Bearer header не поддерживается. Встроенного OAuth-сервера нет. Для подключения с другой машины можно использовать SSH-туннель: ```bash 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`: ```json { "port": 8080, "settings": { "name": "Shop", "http": true, "urldecode_http_requests": true, "merge_adjacent_packets": true, "parse_web_sockets": false, "decrypt_tls": false } } ``` Пример аргументов `create_pattern`: ```json { "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; ограничений по ролям на существующие инструменты нет. ## Поиск и задачи ```json { "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: ```bash 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' ``` Интеграционный тест создаёт отдельную сеть и отдельную БД. Команды из корня репозитория: ```bash ./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` выше): ```powershell 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 секунд: ```bash 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_TEST_RESULTS.md). `mcp/tests/deployment.py` дополнительно проверяет настоящий SDK, валидацию обоих regex-движков и изменения общих сервисов/паттернов внутри отдельного production Compose в режиме VIEW.