Подтверждение инструментов

Подтверждение инструментов

Инструменты MCP — это возможности агента. Часть из них безопасна по построению и выполняется без запроса; остальные требуют явного согласия пользователя, по каждому серверу инструментов. На этой странице — политика, диалог согласия и где хранятся разрешения (гранты).

Политика

Поле requires_approval записывается для каждого сервера в ~/.levpro-ai/mcp.json:

Сервер requires_approval Почему
filesystem (всегда включён, управляемый) false Ограничен активной рабочей папкой и явным allowlist-ом allowed_tools.
code-sandbox (каталог) true Выполняет код и устанавливает библиотеки.
context7 (каталог) false Манифест помечает его readonly.

Правила, применяемые при включении записи каталога:

  • allowed_tools обязателен и не может содержать *; сервер каталога без явного списка отклоняется.
  • requires_approval = !manifest.readonly. Только записи, чей манифест задаёт readonly: true, пропускают согласие.

Режим планирования полностью убирает code-sandbox, поэтому на ходе планирования нет ничего, что требовало бы подтверждения (см. Режим планирования).

Что видит пользователь

Когда ядро отклоняет вызов инструмента, рендер показывает модальное окно:

  • Заголовок: Разрешить выполнение инструмента?
  • Показывает Сервер, Инструмент и Аргументы вызова (с превью, если ядро его предоставляет).
  • Кнопки: Запретить, Разрешить один раз, Разрешить всегда.

Пока окно открыто, статус показывает Ожидание подтверждения: …. Если на окно так и не ответили, по умолчанию через 120 секунд применяется Запретить — ход не может зависнуть навсегда.

Поток решения

lc.sendChat({ approveExecution: autoApproveExecution() })
  └─ Core отклонил вызов инструмента ─► res.approvalDenied {tool, args, preview}
        ├─ serverId = serverIdFromTool(tool, активные id mcp.json)   // mcp_<server>_<tool>
        ├─ promptToolApproval() ── broadcast ai:approvalRequired ─► модальное окно
        │     └─ ответ: deny | once | always          (по умолчанию deny после 120 с)
        ├─ always + serverId ─► config.grantServerApproval(serverId)   // сохраняется
        ├─ deny ─► стоп; ход завершается отказом
        └─ once/always ─► syncCoreSessionHistory() затем повтор с approveExecution=true
  • Отклонённая попытка усекается из зеркала сессии ядра перед повтором, чтобы модель не видела наполовину продублированный ход.
  • autoApproveExecution() возвращает true, когда ни один активный сервер не требует подтверждения, или когда у каждого требующего сервера уже есть грант. Иначе ход начинается неподтверждённым, и цикл подтверждения обрабатывает первый заблокированный инструмент.

Гранты

Гранты хранятся в ~/.levpro-ai/app-settings.json:

{ "approvalGrants": { "code-sandbox": true } }
  • Записью управляет electron/config.js: getApprovalGrants(), grantServerApproval(serverId), revokeServerApproval(serverId).
  • ai:getApprovalGrants отдаёт текущую карту рендеру; ai:approveTool разрешает ожидающий диалог.
  • «Разрешить всегда» действует на сервер, а не на инструмент — одного разрешения для сервера достаточно, чтобы покрыть все его инструменты на последующих ходах. Отозвать можно, очистив запись в app-settings.json (встроенного интерфейса отзыва пока нет).

Связанные страницы