ИИ-агенты для безопасности
Зачем автоматизировать recon и тесты на API NotHoly
Модель, которая не отказывает, плюс CVE, advisory и чтение публичных страниц без оплаты токенами. Активную работу делают ваши инструменты.
MCP — открытый протокол, который связывает ИИ-приложения с инструментами и данными. Роли, примитивы, транспорты и модель безопасности с лабораторной работой в песочнице.
Model Context Protocol (MCP) — открытый протокол, по которому ИИ-приложение единым способом общается с внешними инструментами и данными. До MCP каждому ИИ-приложению, которое хотело читать файлы, обращаться к базе данных или вызывать тикет-систему, требовалась своя интеграция. MCP ставит один контракт между приложением и тем, к чему оно подключается. Приложение, говорящее на MCP, может работать с любым MCP-сервером, а сервер, написанный один раз, работает с каждым клиентом, который реализует протокол.
Если вы уже знаете, как устроен tool use, основной цикл вам знаком. Модель видит список функций, просит вызвать одну из них с аргументами и получает результат. MCP этот цикл не заменяет. Он стандартизирует, откуда берётся список функций, как передаётся вызов и что ещё, кроме функций, может предложить сервер.
Протокол описан в ревизии 2026-07-28: на неё указывала страница спецификации, когда писалась эта статья. Имена полей и правила определяет спецификация. Здесь объясняется модель, которая за ней стоит, чтобы спецификацию и код серверов вы читали уже с ясной картиной в голове.
MCP стоит изучить по трём причинам.
Первая причина: повторное использование. Файловый сервер, сервер GitHub или сервер базы данных можно установить в любой совместимый хост. Больше не нужно писать один и тот же связующий код для каждого приложения.
Вторая причина: обнаружение возможностей. Клиент спрашивает сервер, что тот предлагает, и сервер отвечает именами, описаниями и схемами входных данных. Модель может выбирать из возможностей, которые никто не прописывал в приложении заранее.
Третья причина: риск. Как только модель получает доступ к вашим файлам, репозиториям или аккаунтам, слой инструментов становится поверхностью атаки. Многие проблемы безопасности ИИ возникают из-за сервера, который делает больше, чем сказано в его описании, или из-за хоста, который вызывает инструменты, никого не спрашивая. MCP делает эти вопросы видимыми, а отвечать на них придётся вам.
В архитектуре три участника. Спецификация и обзор архитектуры называют их одинаково.
Хост — ИИ-приложение, в котором работает пользователь. Claude Desktop, Claude Code и IDE с ассистентом — всё это хосты. Хост решает, к каким серверам подключаться и какие инструменты разрешить модели.
Клиент — компонент внутри хоста. Хост создаёт по одному клиенту на сервер, и каждый клиент держит выделенное соединение ровно с одним сервером. Если хост подключён к трём серверам, в нём работают три клиента.
Сервер — программа, которая предоставляет возможности. Он может работать на вашем ноутбуке как дочерний процесс или на удалённой машине по URL. Локальные серверы обычно обслуживают одного клиента, удалённые часто обслуживают многих.
Простая схема:
Host (your AI app)
├── Client A ── stdio ──> filesystem server (local process)
├── Client B ── stdio ──> database server (local process)
└── Client C ── HTTPS ──> ticket system server (remote)Каждая стрелка несёт сообщения JSON-RPC 2.0. В протоколе два слоя. Слой данных определяет сообщения и их смысл. Транспортный слой определяет, как сообщения передаются.
Примитивы определяют, что может предложить сервер. Спецификация называет три серверные возможности.
Инструменты — функции, которые может вызвать модель. У инструмента есть имя, описание, схема входных данных на JSON Schema и обработчик на стороне сервера. Список инструментов получают через tools/list, запускают инструмент через tools/call. Именно в инструментах происходят действия: запись файла, отправка запроса, выполнение запроса к базе.
Ресурсы — данные, которые приложение может прочитать по URI. Ресурсом может быть файл, строка базы данных или ответ API. Ресурсы дают контекст. Чтение ресурса не запускает никакого действия, а как показать содержимое модели, решает хост.
Промпты — многоразовые шаблоны сообщений, которые публикует сервер, часто с аргументами. Пользователь выбирает промпт так же, как команду, а хост заполняет его и отправляет модели.
У клиентов свои возможности. Elicitation позволяет серверу по ходу операции запросить у пользователя дополнительный ввод, например подтверждение или недостающее значение. Две старые клиентские возможности, sampling и logging, в ревизии 2026-07-28 объявлены устаревшими. Через sampling сервер мог запросить генерацию у модели хоста. Обзор архитектуры рекомендует новым реализациям интегрироваться с API провайдеров моделей напрямую, а логи писать в stderr на stdio или через OpenTelemetry.
Все примитивы устроены по одному образцу: метод */list для обнаружения, метод */get или */read для получения и метод вызова, если примитив выполняет действие. Списки могут меняться во время работы. Клиент, открывший подписку, может получать уведомления об изменениях и обновлять данные без опроса.
Транспорт определяет, как передаются сообщения. Обзор архитектуры называет два.
stdio запускает сервер как дочерний процесс. Хост пишет сообщения JSON-RPC в стандартный ввод сервера и читает ответы из его стандартного вывода. Сетевого порта нет. Это обычный транспорт для локальных серверов, он же используется в лабораторной работе. Главное правило: на stdio стандартный вывод принадлежит протоколу. Случайный print в stdout портит поток. Диагностика идёт в stderr.
Streamable HTTP запускает сервер за HTTP-эндпоинтом. Клиент отправляет сообщения через HTTP POST, а сервер может стримить ответы или уведомления обратно через Server-Sent Events. Это транспорт для удалённых серверов. Он смотрит в сеть, поэтому приносит обычные проблемы HTTP: аутентификацию, TLS, проверку origin и лимиты запросов. Для получения токенов обзор архитектуры рекомендует OAuth.
Слой данных в обоих случаях один и тот же. Вызов инструмента выглядит одинаково, прошёл он через пайп или через сокет.
Вот последовательность для хоста, который подключается к одному локальному серверу. Точные сообщения зависят от ревизии протокола, поэтому сверяйтесь со спецификацией, прежде чем писать под неё код.
server/discover, который обязан реализовать каждый сервер. Вызывать его необязательно, потому что каждый запрос несёт всё нужное серверу. Сервер отвечает списком поддерживаемых версий протокола, своими возможностями и данными о себе. В ревизии 2026-07-28 каждый запрос передаёт версию протокола и возможности клиента в поле _meta. Протокол не хранит состояние: каждый запрос несёт то, что нужно серверу для его обработки, и сервер не опирается на то, что было раньше в этом соединении.tools/list, resources/list и prompts/list для возможностей, которые объявил сервер.tools/call. Сервер запускает обработчик и возвращает результат с массивом content, где могут лежать текст, изображения или встроенные ресурсы. Неудачный вызов возвращает результат с ошибкой, который модель может прочитать.subscriptions/listen, получает сообщение notifications/tools/list_changed и может запросить список заново.Между шагами 4 и 5 стоит хост. Это он спрашивает у вас разрешение, если вообще спрашивает. К этому моменту мы вернёмся в разделе о безопасности.
Сам MCP безопасность не обеспечивает. Спецификация говорит об этом в разделе о доверии и безопасности и перечисляет принципы, которые должны заложить разработчики реализаций. Читайте этот список как чек-лист для собственной конфигурации.
Пользователь должен явно согласиться на доступ к данным и на операции, которые выполняет сервер, и понимать их. Хост обязан получить явное согласие, прежде чем передать данные пользователя серверу и прежде чем вызвать любой инструмент. Спецификация также говорит, что описания инструментов, включая аннотации, считаются недоверенными, если только они не получены от сервера, которому вы доверяете. Сервер может заявить, что инструмент только читает. Это утверждение в строке, и у сервера с багом или у вредоносного сервера оно может оказаться ложным.
На практике из этого следуют четыре привычки.
Относитесь к серверу как к коду, который вы запускаете. Сервер stdio — программа на вашей машине с правами вашей учётной записи. Установка сервера ничем не отличается от установки любого пакета. Прочитайте его исходники или хотя бы README, проверьте, кто его публикует, и закрепите версию, которую запускаете. Референсные серверы из официального репозитория подойдут для старта, но прочитайте, что делает каждый из них, прежде чем включать.
Ограничивайте доступ. Выдавайте серверу только те папки, аккаунты и права, которые ему нужны. Файловый сервер из лабораторной работы принимает разрешённый каталог аргументом и отказывает во всём, что за его пределами. Удалённым серверам выдавайте самые узкие из доступных OAuth-скоупов и токены, которые можно отозвать.
Требуйте подтверждения для действий. Инструменты только для чтения и инструменты, которые пишут, удаляют, отправляют или тратят деньги, относятся к разным категориям. Настройте хост так, чтобы он спрашивал перед запуском любого инструмента, меняющего состояние, и читайте аргументы, прежде чем подтвердить.
Следите за тем, что возвращается. Результаты инструментов и содержимое ресурсов — это данные. В них может оказаться текст, похожий на инструкции для модели, скопированный с веб-страницы или из файла. Хост не должен считать такой текст приказом, и вы тоже не должны. Отсюда растёт prompt injection через инструменты, которому посвящена отдельная статья.
В этой лабораторной работе используются официальный референсный файловый сервер из репозитория modelcontextprotocol/servers и официальный MCP Inspector. Модель, API-ключ и платный аккаунт не понадобятся. Нужен только Node.js. Inspector требует Node 22.19.0 или новее, поэтому берите актуальный LTS-релиз. Вы создадите папку, запустите сервер с этой папкой в качестве единственного разрешённого каталога и проверите, что сервер позволяет делать.
Выполните эти команды в терминале там, где хотите разместить лабораторную работу. В Git Bash, Linux или macOS:
mkdir mcp-sandbox && echo 'hello from the sandbox' > mcp-sandbox/note.txtВ PowerShell тот же результат дают команды:
New-Item -ItemType Directory mcp-sandbox | Out-Null
Set-Content -Path mcp-sandbox\note.txt -Value 'hello from the sandbox'Запустите Inspector, указав сервер как цель:
npx @modelcontextprotocol/inspector npx -y @modelcontextprotocol/server-filesystem ./mcp-sandboxInspector выводит локальный URL с токеном для этого запуска и открывает его в браузере. Не закрывайте терминал: сервер работает как дочерний процесс Inspector всё время, пока вы им пользуетесь. Первый запуск может занять время, потому что npx скачивает пакеты. Если подключиться не удаётся, пока пакеты ещё загружаются, подождите минуту и попробуйте снова. В режиме CLI лимит увеличивает --connect-timeout, и команды ниже его используют.
На веб-странице нажмите Connect. Затем откройте вкладку со списком инструментов сервера и запустите получение списка. Подписи меняются от версии к версии, поэтому ищите вкладку и кнопку, которые показывают инструменты. Вы должны увидеть инструменты файлового сервера. В проверенном мной релизе референсный сервер предоставлял шестнадцать инструментов, включая list_directory, read_text_file, write_file и list_allowed_directories. read_file всё ещё на месте и помечен как устаревший в пользу read_text_file.
Сначала запустите list_allowed_directories. Он показывает, что сервер примет. В результате будет один путь, абсолютное расположение mcp-sandbox. Больше ничего не доступно.
Выберите list_directory и передайте . как путь, то есть сам разрешённый каталог. В результате должна быть одна запись: [FILE] note.txt.
Выберите read_text_file и передайте note.txt как путь. В результате должен быть записанный вами текст, hello from the sandbox.
Обратите внимание на путь. Это note.txt, а не ./mcp-sandbox/note.txt. Сервер отсчитывает относительные пути от своего разрешённого каталога и не смотрит на папку, откуда вы запустили Inspector. Я ошибся в этом с первой попытки. Сервер вернул ошибку «no such file» для пути, который он превратил в mcp-sandbox\mcp-sandbox\note.txt. Из сообщения об ошибке я увидел, какой путь сервер использовал на самом деле, поэтому текст ошибок стоит читать внимательно.
Создайте файл в родительской папке, на уровень выше mcp-sandbox:
echo 'this file is outside the sandbox' > outside.txtВернитесь в Inspector и вызовите read_text_file с путём ../outside.txt. Ожидайте результат с ошибкой вместо содержимого файла. На моей машине сервер вернул такой текст (путь сокращён):
Access denied - path outside allowed directories: ...\mcplab\outside.txt not in ...\mcplab\mcp-sandboxЗатем попробуйте абсолютный путь к тому же файлу. Результат должен быть тем же отказом. Проверка выполняется на сервере по итоговому пути, поэтому запрос не пройдёт, как бы вы его ни записали.
Так выглядит ограничение доступа. Сервер — код, который работает на вашей машине с правами вашего пользователя, и всё же он не может прочитать родительскую папку, потому что запущен с одним разрешённым каталогом и соблюдает этот список. При желании попробуйте ещё несколько путей, например просто .. или несуществующую папку, и сравните текст ошибок.
Я выполнил те же вызовы в режиме CLI инструмента Inspector, который отправляет те же сообщения JSON-RPC, что и веб-клиент:
npx @modelcontextprotocol/inspector --cli --connect-timeout 120000 npx -y @modelcontextprotocol/server-filesystem ./mcp-sandbox --method tools/call --tool-name read_text_file --tool-arg path=note.txtОтвет пришёл в JSON, а текстовое содержимое было hello from the sandbox с переводом строки в конце. Та же команда с --tool-name list_allowed_directories показала единственный разрешённый путь. Вызов с ../outside.txt вернул отказ, показанный выше. Версии пакетов в день запуска: @modelcontextprotocol/inspector 2.14.0 и @modelcontextprotocol/server-filesystem 2.2.0. Сервер напечатал Secure MCP Filesystem Server running on stdio в stderr: так правило stdio выглядит на деле. Его stdout оставался зарезервированным для сообщений протокола.
Я запускал это на Windows 11 с Git Bash и Node 24 и для этих запусков веб-страницу не использовал. Ваши версии и пути будут другими, а список инструментов может меняться от релиза к релизу.
Считать MCP возможностью модели. MCP — протокол между хостом и сервером. Модель видит только то, что передаёт ей хост. Один и тот же сервер может вести себя по-разному в двух хостах, если один понятнее показывает описания инструментов или спрашивает подтверждение в другом месте.
Путать опубликованный сервер с проверенным. Установка сервера запускает его код. Пакет в публичном реестре ничего не говорит о своей безопасности.
Выдавать доступ на запись по умолчанию. Начинайте с доступа только на чтение. Добавляйте права на запись, только когда этого требует задача.
Печатать в stdout в сервере stdio. Логи и отладочный вывод в stdout ломают протокол. Используйте stderr.
Доверять аннотациям инструментов. Инструмент с пометкой read-only всё равно выполняет любой код, который есть на сервере.
Писать код по пересказу спецификации. Ревизии меняют имена методов и список устаревшего. Проверьте, какую ревизию реализует ваш SDK, и прочитайте в спецификации точные имена полей, прежде чем писать код.
Ждать от Inspector аудита. Inspector показывает, что сервер возвращает клиенту. Это отладочный вид, и проверки безопасности он не заменяет.
Сначала прочитайте обзор архитектуры, затем страницы о концепциях сервера и клиента. Там примитивы объяснены на большем числе примеров. После этого прочитайте разделы спецификации о базовом протоколе и безопасности: они задают правила, которым обязан следовать каждый сервер и хост.
Откройте исходники референсного файлового сервера. Они короткие, и по ним видно, как обработчик проверяет пути и возвращает ошибки. Затем напишите на официальном SDK небольшой собственный сервер с одним инструментом, который возвращает фиксированную строку, и изучите его в Inspector, прежде чем добавлять то, что касается ваших файлов.
Держите папку лабораторной работы маленькой и одноразовой и удалите её, когда закончите. Следующая статья этого цикла, что такое prompt injection в LLM-приложениях, разбирает атаку, которую делают возможной результаты инструментов. Основы, на которые опирается эта статья, изложены в материале что такое ИИ-агенты и tool use.
ИИ-агенты для безопасности
Модель, которая не отказывает, плюс CVE, advisory и чтение публичных страниц без оплаты токенами. Активную работу делают ваши инструменты.
ИИ-агенты для безопасности
Устройство агента для bug bounty: модель, инструменты, память и ограничители в цикле на вашей машине под вашим подтверждением.
ИИ-агенты для безопасности
Небольшой агент bug bounty на Python с вызовом инструментов на API NotHoly: предлагает команды recon, ждёт подтверждения, читает вывод и ведёт заметки.