
Технологии ушли вперёд, и теперь мы живём в эру больших языковых моделей и автономных AI-агентов. В настоящее время существует несколько агентных систем, работающие с компьютерным зрением и камерами. Интеллектуальные видеоагенты обрабатывают видеопотоки в реальном времени, распознают объекты, анализируют поведение людей, фиксируют нарушения и действуют автономно. В основном – это готовые коммерческие ИИ-платформы для видеонаблюдения (например, Lumana, VisionPlatform.ai, Spot AI).
Для создания собственных решений можно настроить захват кадров (через Frame Forwarder) и передать их в визуальные модели обработки. Можно создавать логику на базе Amazon Bedrock Agents или фреймворков для ИИ-агентов (LangChain, CrewAI, AutoGen), где камера выступает как «инструмент» (take_snapshot()) восприятия.
Есть еще более специализированные решения – VisionAgent (от Landing AI), Microsoft AutoGen, LlamaIndex (Multimodal Agents).
А можно как-то по проще? Да еще из подручных средств? Да еще в «бытовые» агентные системы?
А давайте попробуем…
Дисклеймер:
Платформа: Windows, WSL
Язык: Object Pascal (Delphi)
Еще один дисклеймер:
Стиль, грамматика и пунктуация этой статьи причёсаны искусственным интеллектом. Автор честно пытался писать сам, но засомневался в своих деепричастных оборотах. Архитектурные UML-диаграммы рождены из множества попыток сформулировать для ИИ разумное техническое описание процессов. Ни один разработчик и ИИ не пострадали.
Если вы видите следы генерации – я их тоже вижу.
«Бытовые» мультиагентные системы в целом остаются «слепыми» – они заперты в текстовом контексте и локальных песочницах. Они не умеют напрямую работать с веб-камерами, сканировать локальную сеть на наличие IP-камер, быстро нарезать видео или распознавать лица в кадре без Node.js- или Python-окружения.
Ставить Python-окружение весом в гигабайт с кучей зависимостей ради того, чтобы ИИ-агент просто сделал скриншот с веб-камеры – это грех против нативной разработки.
В статье Delphi+OpenCV (сейчас Delphi-OpenCV-Class перенесен в private) был описан проект, который связал Object Pascal с миром компьютерного зрения. Импорт C++ классов напрямую из OpenCV 4.xx DLL по декорированным именам, использование соглашений о вызовах Windows x64 и Custom Managed Records в Delphi – позволили автоматически управлять жизненным циклом структур TMat (обёток для cv::Mat) и избавиться от утечек памяти. Всё это не пропало даром и сейчас перенесено в Delphi-OpenCV5 для версии 5.0. Кроме этого под рукой оказались – Delphi-FFmpeg и Delphi-ONVIF
Попробуем объединить это все и превратить в Delphi-движок media-mcp-server – быстрый и «родной» сервер протокола MCP (Model Context Protocol), в единую экосистему инструментов для AI-ассистента.
На всякий случай.
Model Context Protocol (MCP) – открытый стандарт взаимодействия между ИИ-клиентами (например, локальными ИИ-ассистентами или средами разработки) и внешними локальными инструментами (серверами), разработанный компанией Anthropic. Вся коммуникация идет по стандарту JSON-RPC. Клиент запрашивает список доступных функций (tools/list), а затем вызывает нужную команду с параметрами в формате JSON (tools/call), ожидая ответ от сервера.
Большинство готовых MCP-серверов написано на TypeScript (Node.js) или Python. Но если цель – быстрый медиа-процессинг на Windows-машине с поддержкой веб-камер и RTSP-потоков, нативный код даёт максимум:
-
Получаем один скомпилированный
MediaMCPServer.exeи несколько DLL рядом, то есть решение практически с нулевыми зависимостями. Никаких гигабайтныхnode_modules, вызововpip installи виртуальных окружений. -
Сервер запускается мгновенно, потребляет минимальный объём RAM и выдаёт чистую нативную скорость при работе с видеопотоками. Потребление RAM в режиме ожидания составляет всего 12–15 МБ. При активной работе с DNN-моделями память расходуется только под структуры кадров в C++ DLL.
-
Работаем с кадрами OpenCV и потоками FFmpeg прямо в общей памяти процесса, не тратя ресурсы на межпроцессную сериализацию мегабайтных массивов пикселей.
Транспортных протоколов два:
-
Классика stdio (стандартные потоки ввода-вывода) – клиент запускает исполняемый файл сервера как дочерний процесс и общается с ним через перенаправление потоков
stdinиstdout. На первый взгляд, Pascal отлично подходит для работы с консолью, однако на практике выяснилось следующее:-
Сторонние динамические библиотеки (в частности, библиотеки FFmpeg и OpenCV) при возникновении внутренних предупреждений пишут отладочные сообщения напрямую в стандартный вывод
stdout. Этот мусор ломал парсер JSON-RPC на стороне ИИ-клиента, из-за чего сессия аварийно завершалась. -
Использование
Readlnв Delphi по умолчанию буферизует ввод, что приводило к зависанию на некоторых типах сообщений, когда разделитель строк не совпадал с ожидаемым средой выполнения. Другие решения не искал, но наверное они есть. -
stdio-транспорт не может работать через границу виртуализации (например, когда ИИ-клиент запущен в WSL Linux, а сам медиа-сервер с физическими USB-камерами и видеокартами с поддержкой CUDA должен работать на хост-системе Windows). По этой причине поддержка транспорта stdio в проекте была признана устаревшей и оставлена только для совместимости с простейшими локальными сценариями.
-
-
Streamable HTTP – сейчас основной транспорт. Сервер запускается как самостоятельный процесс и слушает порт, а клиент подключается к нему по HTTP, получая ответы на запросы в реальном времени. Это гарантирует изоляцию и стабильность сессий.
Архитектура проекта построена на легковесном HTTP-сервере, написанном на WinSock API (uMCPHttpServer.pas). Он слушает входящие POST-запросы и распределяет их на уровне HTTP-сессий.
Также далее для информации – показан сценарий обработки сообщений внутри самого Windows-хоста Media-MCP-Server (от приёма HTTP-запроса до вызова OpenCV/FFmpeg и отправки HTTP-ответа)

Сервер поддерживает сессии клиентов с помощью HTTP-заголовка Mcp-Session-Id. Жизненный цикл сессии и обработка запросов реализованы в методе ProcessHttpRequest (uMCPHttpServer.pas):
procedure TMCPHttpServer.ProcessHttpRequest(ASocket: NativeUInt; const Method, Path, Body: string; const Headers: TDictionary<string, string>);var SessionId, ResponseJson, MethodName: string; StatusCode: Integer; StatusText, ContentType, ExtraHeaders, ResponseBody: string; JsonVal: TJSONValue; JsonReq: TJSONObject;begin StatusCode := 200; StatusText := 'OK'; ContentType := 'application/json'; ExtraHeaders := ''; ResponseBody := ''; if not SameText(NormalizePath(Path), FConfig.HttpPath) then begin StatusCode := 404; StatusText := 'Not Found'; Exit; end; SessionId := HeaderValue(Headers, 'Mcp-Session-Id'); if SameText(Method, 'DELETE') then begin RemoveSession(SessionId); StatusCode := 200; ResponseBody := '{"status":"session_closed"}'; end else if SameText(Method, 'POST') then begin JsonVal := TJSONObject.ParseJSONValue(Body); if JsonVal is TJSONObject then try JsonReq := JsonVal as TJSONObject; JsonReq.TryGetValue<string>('method', MethodName); // При initialize создаем новую сессию if SameText(MethodName, 'initialize') then begin SessionId := CreateSessionId; AddSession(SessionId); ResponseJson := FHandler.ProcessMessage(Body); ResponseBody := ResponseJson; ExtraHeaders := ExtraHeaders + 'Mcp-Session-Id: ' + SessionId + #13#10; end else begin // Для обычных вызовов проверяем существование сессии if not SessionExists(SessionId) then begin StatusCode := 401; ResponseBody := '{"error":"Unauthorized session"}'; end else begin ResponseJson := FHandler.ProcessMessage(Body); ResponseBody := ResponseJson; ExtraHeaders := ExtraHeaders + 'Mcp-Session-Id: ' + SessionId + #13#10; end; end; finally JsonVal.Free; end; end; SendHttpResponse(ASocket, StatusCode, StatusText, ContentType, ExtraHeaders, ResponseBody);end;
Внутри uMCPHandler.pas JSON-запрос от ИИ-агента разбирается с помощью базовой диспетчеризации методов:
function TMCPHandler.ProcessMessage(const JsonText: string): string;...begin // Парсим JSON и извлекаем jsonrpc, method, id и params ... if Method = 'initialize' then Exit(BuildInitializeResponse(Id, Params)) else if Method = 'tools/list' then Exit(BuildToolsListResponse(Id)) else if Method = 'tools/call' then Exit(BuildToolsCallResponse(Id, Params)) else if Id <> nil then Exit(BuildErrorResponse(Id, -32601, 'Method not found: ' + Method));end;
Когда ИИ-агент запрашивает tools/list, возвращаем ему массив JSON-объектов, описывающих наши возможности. Например, инструмент для захвата кадра с веб-камеры регистрируется так:
// Описание свойства в uMediaEngine.pasTool := TJSONObject.Create;Tool.AddPair('name', 'webcam_grab_frame');Tool.AddPair('description', 'Grab a frame from a local webcam by its index and save it as a JPEG image.');Schema := TJSONObject.Create;Schema.AddPair('type', 'object');// Описание свойств: cameraIndex (integer), outputPath (string, required), etc....Tool.AddPair('inputSchema', Schema);Result.Add(Tool);
Вся функциональность сервера разделена на логические модули на Object Pascal. Каждый модуль отвечает за определенный круг задач и регистрирует соответствующие JSON-RPC инструменты, с которыми может взаимодействовать ИИ-ассистент.
Для реализации функциональности потребовалось не так уж и много модулей. Модули обеспечивают инфраструктуру сервера, парсинг JSON-RPC и коммуникацию с клиентом:
-
MediaMCPServer.dpr – точка входа консольного приложения. Обрабатывает аргументы командной строки и инициализирует stdio или HTTP транспорт.
-
uMCPServer.pas – стандартный stdio-транспорт. Читает
stdin, передает запросы обработчику и отправляет ответы вstdout. -
uMCPHttpServer.pas – встроенный HTTP-сервер для кросс-окружения (WSL/Windows). Поддерживает REST API и SSE (Server-Sent Events) для уведомлений.
-
uMCPHandler.pas – логический диспетчер JSON-RPC. Проверяет структуру пакетов, обрабатывает запросы инициализации и перенаправляет вызовы инструментов.
-
uMCPConfig.pas – управление конфигурациями, путями к DLL и рабочими каталогами.
-
uMediaEngine.pas – оркестратор, содержит метаданные и схемы параметров для всех 47 инструментов (их список с пояснениями — ниже), а также распределяет вызовы методов к соответствующим модулям.
Модуль uONVIFTools.pas, реализованный на базе Delphi-ONVIF, отвечает за интеграцию с IP-камерами по протоколу ONVIF (и содержит 6 инструментов):
-
camera_discover– автоматический поиск ONVIF IP-камер в локальной подсети по WS-Discovery (UDP Multicast). -
camera_get_stream_uri– запрос RTSP-ссылки на медиапоток с камеры (с возможностью выбора профиля качества). -
camera_ptz_move– управление движением поворотной камеры (Pan, Tilt, Zoom) с заданной скоростью и длительностью. -
camera_ptz_stop– мгновенная остановка любого PTZ-движения камеры. -
camera_get_imaging_settings– получение параметров сенсора камеры (яркость, контрастность, резкость, насыщенность). -
camera_set_imaging_settings– изменение настроек изображения на физической камере.
Модули uOpenCVTools.pas и uOpenCVHelpers.pas (на базе Delphi-OpenCV5) выполняют базовый захват медиаданных и простейший анализ (содержат 4 инструмента):
-
webcam_list– сканирование DirectShow/MSMF системных устройств для вывода списка подключенных USB-камер. -
webcam_grab_frame– захват кадра с локальной USB-камеры (или RTSP-потока) с сохранением на диск в JPEG. -
image_detect_objects– базовая детекция объектов на изображении с возвратом координат. -
image_detect_faces– быстрая детекция человеческих лиц с помощью детектора YuNet.
Блок FFmpeg Tools (использует Delphi-FFmpeg) – инструменты этого модуля вызывают функции FFmpeg DLL напрямую для работы с медиаконтейнерами без перекодирования (или с минимальным декодированием). Он объединяет файлы uFFmpegTools.pas, uFFmpegProbe.pas и uFFmpegHelpers.pas и содержит 15 инструментов:
-
video_probe– технический анализ видеофайла (длительность, FPS, кодеки, параметры аудио). -
stream_test– проверка доступности сетевого потока или файла с замером пинга и чтением метаданных. -
video_grab_frame– вырезание одиночного кадра в JPEG на определенной секунде видеофайла. -
video_grab_frames– серийная нарезка кадров из видеофайла через заданные интервалы времени. -
video_thumbnail– быстрое создание миниатюры (превью) заданного размера из видео. -
video_remux– смена контейнера видеофайла (например,.mkvв.mp4) без перекодирования потоков. -
video_trim– быстрая обрезка видео по таймкодам начала и конца (без транскодирования). -
video_concat– склейка нескольких видеофайлов одного формата в один файл. -
audio_extract– извлечение аудиодорожки из видео в формате сырого PCM S16LE. -
video_record_segment– запись отрезка живого RTSP-вещания заданной длительности в файл. -
video_scale– изменение разрешения видео с перекодированием. -
video_filter– применение цепочки фильтров FFmpeg (например, кадрирование, водяные знаки, цветокоррекция). -
video_detect_silence– анализ аудиодорожки на предмет обнаружения периодов тишины ниже заданного уровня дБ. -
video_scene_detect– обнаружение монтажных склеек (смен сцен) на основе разности кадров. -
video_metadata_read– чтение тегов и метаданных из медиафайла.
Раздел OpenCV DNN Tools (на базе Delphi-OpenCV5) представлен модулем uOpenCVDnnTools.pas. Он использует модуль cv::dnn из OpenCV для работы с ONNX- и TensorFlow-моделями и предоставляет 8 инструментов:
-
image_classify– классификация изображения по 1000 классам с помощью свёрточной сети MobileNetV2. -
image_segment_person– сегментация силуэта человека в кадре (PP-HumanSeg) с сохранением маски в PNG. -
image_detect_text– обнаружение текстовых блоков и полигонов их границ с помощью OCR-модели PP-OCR. -
image_detect_text_east– детектор текста EAST для быстрого поиска повёрнутых областей текста. -
face_compare– сравнение двух лиц по геометрии (SFace) с вычислением косинусного сходства. -
face_enroll– регистрация нового лица в локальную базу данных (сохранение вектора признаков). -
face_identify– распознавание лица путём поиска по зарегистрированной локальной базе векторов лиц. -
face_list– вывод списка имён всех зарегистрированных лиц.
В OpenCV 5.0 модуль cv::dnn позволяет запускать глубокие нейросети «из коробки» без разворачивания окружения PyTorch или TensorFlow. В проекте media-mcp-server используются преднастроенные и оптимизированные ONNX- и Protobuf-модели.
-
YuNet (
face_detection_yunet) – сверхбыстрое и легковесное обнаружение лиц. Позволяет находить в кадре лица людей (даже если они частично перекрыты, обращены в профиль или выражают удивление) и возвращает координаты описывающего прямоугольника, а также точные координаты 5 ключевых ориентиров лица (глаза, нос, уголки губ) и оценку уверенности (confidence). -
SFace (
face_recognition_sface) – распознавание и сравнение лиц. Принимает два вырезанных и выровненных по ключевым точкам лица, извлекает из них вектор признаков (эмбеддинг из 128 чисел типа float) и вычисляет косинусное сходство. Это позволяет ИИ-агенту определять степень сходства лиц. -
YOLOX (
object_detection_yolox) – универсальный детектор объектов. Находит в кадре до 80 типов распространенных объектов (люди, машины, сумки, котики) и возвращает их координаты. Подходит для сценариев вроде «проверь, есть ли машины перед воротами». -
MobileNetV2 (
image_classify) – классификация изображения. Определяет, какой объект изображён на картинке, возвращая идентификатор класса из базы ImageNet (1000 классов). -
PP-HumanSeg (
human_segmentation_pphumanseg) – сегментация силуэта человека. Выделяет людей на изображении попиксельно. Полезно для автоматической изоляции людей в кадре с целью сохранения их признаков в базу данных. -
PP-OCR / EAST (
text_detection_ppocr/frozen_east_text_detection) – обнаружение текста (OCR). Локализует области, содержащие печатный текст под любым углом. PP-OCR строит полигоны вокруг слов, а EAST строит повёрнутые ограничивающие рамки. Это первый шаг для последующего распознавания текста. -
TrackerNano (
video_track_object) – локальный трекинг объектов на видео. Трекер на базе ONNX, сопровождающий произвольный объект, однажды выделенный рамкой, на протяжении всего видеоряда. Это позволяет не запускать ресурсоёмкую детекцию на каждом кадре, а следовать за целью.
OpenCV Image Tools (Delphi-OpenCV5) – модуль uOpenCVImgTools.pas геометрические трансформации, фильтрация и классическое компьютерное зрение (11 инструментов):
-
image_read_qrcode– распознавание и декодирование QR-кодов на изображении. -
image_encode_qrcode– генерация QR-кода по текстовой строке с сохранением в JPEG. -
image_read_barcode– сканирование и декодирование штрихкодов. -
image_detect_aruco– детекция маркеров позиционирования ArUco (для робототехники). -
image_template_match– поиск эталонного фрагмента (шаблона) на большом изображении. -
image_find_contours– выделение контуров объектов и определение самого крупного из них. -
image_detect_edges– выделение границ на изображении методом Canny. -
image_detect_lines– поиск прямых линий с помощью преобразования Хафа. -
image_detect_circles– поиск окружностей с помощью преобразования Хафа. -
image_transform– трансформация кадра (поворот на произвольный угол, обрезка, изменение разрешения). -
image_annotate– графическая разметка изображения (нанесение рамок, подписей и масок детекции YOLO/YuNet).
OpenCV Video Tools (Delphi-OpenCV5) – модуль uOpenCVVideoTools.pas алгоритмы, требующие анализа последовательности кадров (3 инструмента):
-
webcam_record_video– фоновая запись видео с USB-камеры заданной длительности без создания графических окон Windows. -
video_track_object– отслеживание перемещения объекта в видеопотоке с помощью трекера TrackerNano. -
image_optical_flow– вычисление плотного оптического потока Фарнебека между парой кадров для анализа движения.
Чтобы ИИ-агент понимал, как правильно вызывать эти инструменты и связывать их с окружением используется базовый системный промпт (простой):
Вы имеете доступ к локальному медиа-серверу MediaMCPServer через протокол MCP. Правила работы с инструментами:
Для обнаружения камер в сети используйте
camera_discover.Если ИИ-клиент запущен на той же машине, всегда указывайте локальные пути (например,
C:/temp/frame.jpg) в параметрах сохранения изображений. Не запрашивайте Base64 без необходимости.При поиске людей используйте связку
image_detect_faces->face_compareдля сравнения лиц с базой данных.При отслеживании движения в реальном времени используйте
video_track_objectвместо серийного вызова детектора для экономии CPU/GPU.
Основная проблема возникла при попытке передать обработанное изображение обратно в контекст языковой модели. Первоначальный «артефакт» проектирования, первая попытка в лоб – передача сырого изображения высокого разрешения (например, кадра 4K с IP-камеры) в Base64 прямо внутри JSON-RPC ответа. Это приводило к раздуванию JSON до десятков мегабайт, из-за чего парсеры ИИ-клиентов аварийно завершали сессию по тайм-ауту. К тому же отправка больших Base64-строк быстро исчерпывала контекстное окно ИИ-моделей. Попытки сжимать изображения на лету до превью размером 120×120 пикселей решали проблему объёма данных, но делали картинку бесполезной – ИИ-модель видела пиксельную кашу и не могла разобрать текст на автомобильных номерах или мелкие объекты.
Сейчас в силу отсутствия лучшего решения — используется гибридный конвейер. Передача изображений происходит по схеме:
-
Если ИИ-клиент запущен локально на той же машине, сервер сохраняет кадр в оригинальном качестве в каталог
data/media/и возвращает только текстовый путь к файлу. Клиент сам считывает его с диска. Когда агент вызываетwebcam_grab_frame, он передает параметрoutputPath(например,...\data\media\frame.jpg). ИИ-модель оперирует строкой в несколько десятков символов. -
Если требуется прямая передача данных (или клиент работает удаленно), сервер выполняет адаптивное масштабирование кадра (downscaling с сохранением соотношения сторон) и сжатие в JPEG с качеством 80%, после чего кодирует полученный буфер в Base64. Это дает баланс между детализацией картинки и размером JSON.
Когда агент вызывает инструмент image_detect_faces, управление переходит к Delphi-коду, который загружает изображение в TMat и запускает легковесную сеть YuNet:
var Img, Faces: TMat; Detector: TFaceDetectorYN;begin Img := TMat.imread(ImagePath); if Img.empty then raise Exception.Create('Could not read image'); // YuNet требует инициализации под размер входного изображения Detector := TFaceDetectorYN.create(ModelPath, '', Img.size); Faces := TMat.Create; try Detector.detect(Img, Faces); // Извлекаем bounding box'ы лиц, координаты 5 ключевых ориентиров и confidence ResultJSON := ParseFacesToJSON(Faces); finally Faces.Free; end;end;
Отдельно – интеграция системы с мультиагентными средами. В рамках тестирования подключали media-mcp-server к мультиагентной системе, работающей под WSL. Это потребовало создания сетевого и межпроцессного моста между Windows и виртуальным окружением Linux (WSL), поскольку агенты запускались в контексте Linux и ожидали, что MCP-сервер будет работать там же.
Работа в виртуализированном окружении Linux сопряжена со сложностями. WSL не имеет прямого доступа к физическим USB-устройствам Windows-хоста. Захват картинки с локальной веб-камеры ноутбука из Linux-контейнера требует проброса USB-портов через утилиты вроде usbipd-win. На практике это решение оказалось нестабильным, требовало прав администратора и периодически отваливается. Кроме того, для быстрой работы нейросетевых моделей в OpenCV (например, детекции объектов или лиц) важен прямой доступ к GPU. Настройка проброса CUDA внутри WSL технически возможна, но сложна и снижает производительность по сравнению с работой на физическом хосте, где уже установлены родные драйверы видеокарты и библиотеки OpenCV 5.0 с поддержкой CUDA.
Рассматривались и альтернативные варианты. Например, запуск сервера внутри WSL через Wine не увенчался успехом – Wine не смог стабильно работать с драйверами захвата видео DirectShow/MSMF и падал при инициализации камеры. Идея написать отдельный Python-демон для трансляции потоков из Windows в WSL через IP-сеть также не выстрелила, поскольку это усложняло архитектуру. Использование stdio-транспорта – не подошло из-за невозможности работы через границу WSL/Windows без перенаправления пайпов через SSH.
В результате окончательно – Streamable HTTP-сервер, и это решение полностью себя оправдало.
ИИ-клиент внутри WSL Linux общается с сервером по протоколу HTTP (через сетевой мост WSL). В репозитории проекта есть готовые шаблоны конфигурационных файлов (например, config/mcp.json.template для stdio (это осталось от старых попыток, не используйте это) и config/mcp.http.json.template для HTTP).

Внутри WSL запускается скрипт, вычисляющий IP-адрес Windows-хоста (через /etc/resolv.conf) и прописывающий в конфигурационный файл ИИ-клиента ссылку на этот адрес (по аналогии с шаблоном config/mcp.wsl.http.json.template):
"media-mcp-server": { "url": "http://<windows_host_ip>:8765/mcp"}
Получилось довольно-таки неплохое разделение обязанностей — тяжёлая математика нейросетей выполняется Delphi-сервером на GPU хоста, хранение векторов берёт на себя специализированная СУБД, а LLM работает только с JSON-вызовами. Лёгкий ИИ-агент функционирует в WSL Linux, а медиа-сервер MediaMCPServer.exe выполняется на Windows-хосте, получая прямой доступ к аппаратному ускорению видеокарты и физическим веб-камерам без задержек виртуализации.
В мультиагентных ИИ-системах один специализированный агент редко решает задачу в одиночку. В рамках тестирования под media-mcp-server были созданы:
-
Агент-Наблюдатель (Сенсорный уровень) – использует
media-mcp-serverдля физического взаимодействия с миром (захват кадров, детекция лиц, объектов, считывание QR-кодов). -
Агент-Хранитель (условно — Гиппокамп) – использует векторные и семантические базы данных через специализированные MCP (например,
vector-memory-mcpилиknowledge-graph-mcp). -
Агент-Аналитик – оркестратор, сопоставляет информацию и принимает решения.
Типичный сценарий долговременного отслеживания и ведения логов событий:
-
Когда Агент-Наблюдатель вызывает
face_identifyилиimage_detect_faces, сервер (mcp) находит лицо и вычисляет его математический вектор признаков (эмбеддинг размерностью 128 (float) с помощью модели SFace). Этап сбора эмбеддингов. -
Вместо сохранения видео, Агент-Аналитик преобразует это событие в текстовое описание и вектор:
-
Метаданные:
{"event": "face_detected", "name": "Иванов И.И.", "confidence": 0.92, "timestamp": "2026-06-23T12:00:00Z", "location": "Вход в корпус А"} -
Вектор: Вектор признаков лица SFace, полученный от mcp.
-
-
Агент обращается к
vector-memory-mcpи вызывает инструментstore_memory(илиcreate_entitiesв Graph-базе данных), сохраняя этот вектор и метаданные. -
Позже, когда пользователю нужно найти информацию о перемещениях человека, Агент-Аналитик выполняет семантический поиск: «Когда в последний раз видели Иванова?». Векторная база выдает сохраненные записи с разных камер. Агент сопоставляет их по времени (
timestamp) и строит хронологическую цепочку: «Сначала Иванов зашел в корпус А в 12:00 (Камера 1), затем прошел по коридору второго этажа в 12:02 (Камера 5) и зашел в аудиторию 204 в 12:05 (Камера 12)».
Один из вопросов – «Можно ли перенести этот сервер на Linux/macOS, чтобы запускать его в Docker-контейнерах или на MacBook?»
Object Pascal позволяет сделать это — да, но есть нюанс. Здесь есть два пути развития проекта.
Данные предположения носят теоретический характер, так как практические тесты на этих платформах пока не проводились.
Если необходимо иметь полностью бесплатный и свободный кроссплатформенный стек, надо переходить на Free Pascal. В FPC есть поддержка расширенных записей (Advanced Records) и перегрузка операторов.
Но общий план адаптации выглядит следующим образом:
-
Нужна stdio-обёртка. Надо переписать чтение/запись под UNIX-потоки ввода-вывода (с использованием файловых дескрипторов
StdInputиStdOutputв FPC) и учесть специфику неблокирующего чтения в POSIX-системах. -
Заменить модули
System.JSON(специфичные для Delphi) наfpjsonиjsonparser(Lazarus). -
Использовать пакет
fphttpapp(встроенный в FPC HTTP-сервер) или библиотеку Synapse для поднятия REST API на Linux/macOS. -
Поскольку FPC не поддерживает автоматическое декорирование С++ имён классов при линковке на не-Windows системах, собрать разделяемую библиотеку (
.soпод Linux,.dylibпод macOS), которая скроет вызовы C++ классов OpenCV 5.0 за плоским C-интерфейсом. После выполнения этих шагов проект будет готов к компиляции под целевую платформу, например:fpc -Mdelphi -Tlinux -Pxd86_64 MediaMCPServer.lpr. Ха!
Ещё один путь – использование Delphi Enterprise (DCCLinux / DCCMac). Delphi компилируется под Linux x64 и macOS, поэтому вся системная логика (System.JSON, System.Net.HttpClient) перенесётся без изменений.
Но там есть свои сложности:
-
Под Windows x64 действует соглашение Microsoft x64 calling convention, под Linux и macOS x64 – System V AMD64 ABI. Из-за разницы в передаче параметров (в System V ABI структуры до 16 байт передаются непосредственно через регистры RDI, RSI, а не по ссылке) заголовки импорта OpenCV могут приводить к Access Violation. Delphi все непростые типы (например, записи) даже размером 1 байт передаёт как адрес. Чтобы избежать проблем с ABI, придётся переписать сигнатуры импортируемых методов, принимающих
TPoint,TRectилиTSize, объявив их как указатели (pTRect,constилиconst [ref]). Фактически это потребует полного переписывания биндинга OpenCV. -
Можно разработать Flat C Wrapper. Собрать C++ библиотеку-посредник
libopencv_wrapper.so(или.dylibпод macOS), которая экспортирует C-совместимые функции (где все структуры передаются только по ссылке или указателю) с соглашениемcdecl. Это избавит от привязки к ABI конкретной ОС на стороне Delphi. После выполнения этих шагов останется настроить PAServer, собрать проект под Linux или macOS, положить рядом динамические библиотеки OpenCV и FFmpeg и указать к ним пути через переменные окруженияLD_LIBRARY_PATH(илиDYLD_LIBRARY_PATHв macOS) при запуске. Ха!
В заключение – несколько примеров. Сессия взаимодействия с мультиагентной системой, когда ИИ получает в своё распоряжение media-mcp-server.
Запрос пользователя в чате к ИИ-ассистенту:
Найди IP-камеры в сети. Если найдешь камеру на парковке, забери с нее один кадр и скажи, есть ли свободные места.
Цепочка действий агента:
-
Агент видит в списке доступных инструментов
camera_discoverи вызывает его. -
Delphi-сервер сканирует сеть по ONVIF и возвращает:
[{"ip": "192.168.1.50", "name": "Parking-Gate-Camera"}] -
Агент вызывает инструмент
camera_get_stream_uriс параметромcameraIp: "192.168.1.50". Delphi-сервер отправляет камере ONVIF-запрос и возвращает RTSP-адрес потока:{"streamUri": "rtsp://admin:pass@192.168.1.50:554/live/main"} -
Агент вызывает
webcam_grab_frame, передавая полученную RTSP-ссылку вcameraUrlи путь сохранения на диске. -
Cервер инициализирует захват кадра через
cv::VideoCapture, декодирует RTSP-поток с помощью FFmpeg, забирает кадр, сохраняет его на диск как JPEG и сообщает об успехе. -
Агент считывает полученную картинку с диска, отправляет её в визуальную модель и отвечает пользователю:
На парковке обнаружено 2 свободных места в первом ряду. Одно место около въезда свободно, второе занято синей машиной, но рядом с ней есть свободный карман.
Вся цепочка выполняется автономно за 8–10 секунд. Не нужно писать сценарии интеграции – ИИ-агент сам решает, в какой последовательности вызывать предоставленные сервером инструменты.

Есть другой пример – случай (на этапе тестирования) аудита безопасности в университетской сети, где media-mcp-server выступил в роли «глаз» автономного ИИ-агента.
Задача для ИИ-агента:
Пользователь загружает фотографию студента и отправляет запрос: «Найди, в какую аудиторию зашёл этот студент за последние 15 минут. Доступ к локальной сети корпуса у тебя есть».
Ход процесса:
-
Агент вызывает инструмент
camera_discover. Delphi-сервер отправляет UDP Multicast по протоколу WS-Discovery. Так как сегмент видеонаблюдения не был изолирован от университетской беспроводной сети на уровне VLAN, агент обнаруживает в подсети корпуса 34 ONVIF-совместимые камеры. -
Агент пытается запросить RTSP-адреса потоков через
camera_get_stream_uri. Поскольку инструмент требует авторизации, агент методично пробует дефолтные пары (admin:admin,admin:12345,admin:password— это мы его научили). На 3 коридорных камерах авторизация проходит успешно, и агент получает их RTSP-ссылки. -
Чтобы не перегружать сетевой канал и CPU/GPU сервера передачей Base64, агент настраивает дискретный опрос – каждые 3 секунды он делает снимок через
webcam_grab_frameна скомпрометированных камерах, запускает быструю детекцию лицimage_detect_faces(YuNet) и сравнивает результаты с целевым фото черезface_compare. -
На камере возле лифтового холла модель распознавания лиц SFace возвращает косинусное сходство
0.47(при установленном пороге совпадения0.36). Студент обнаружен в кадре. -
Агент считывает метаданные ONVIF-камер и анализирует их имена:
ONVIF_Cam_Fl4_Lobby(где был замечен студент) иONVIF_Cam_Fl4_West(коридор). Он переключает фокус опроса кадров на камеру коридора. -
Из-за задержек дискретного опроса (интервал в 3 секунды) студент успевает скрыться в одной из дверей. Агент фиксирует, что объект прошёл мимо первой камеры коридора, но не появился на камере в конце коридора.
-
Агент выдаёт пользователю отчёт – «Целевой субъект зафиксирован в лифтовом холле в 12:47:15. Проследовал по коридору. В 12:47:30 скрылся из поля зрения. С высокой вероятностью вошёл в одну из аудиторий в начале коридора, так как на конечной камере коридора обнаружен не был»*.
После демонстрации логов расследования руководству департамента ИТ, уязвимости были оперативно устранены. На всех камерах принудительно обновили пароли, отключили протокол WS-Discovery для гостевых подсетей и настроили списки контроля доступа (ACL) на коммутаторах, изолировав трафик видеонаблюдения от общей сети.
Ну и в заключение.
Delphi продолжает замечательно чувствовать себя в современную эру искусственного интеллекта. Скорость компиляции, низкое потребление ресурсов и возможность интеграции с C/C++ кодом делают Object Pascal хорошим выбором для написания легковесных системных утилит. В этом случае – связывающих физический мир с возможностями больших языковых моделей.
-
Полный исходный код проекта, скрипты автоматической настройки MCP-клиентов и шаблоны конфигураций доступны на GitHub: MediaMCPServer.
-
Дополнительные примеры использования с описанием различных сценариев вызова инструментов ИИ-агентом собраны в файле EXAMPLES.md.
-
Буду рад вашим комментариям, замечаниям, идеям новых инструментов. Ну и ругайте, конечно…
ссылка на оригинал статьи https://habr.com/ru/articles/1051210/