Перейти к содержимому

Кейс: Codex 0.151 — перехват MCP tool results и настраиваемая grace period

MCP-серверы — это основа расширяемости Codex CLI: каждый сервер добавляет агенту новые тулзы (поиск в интернете, работа с базой данных, обращение к API). Но до версии 0.151.0 результат MCP-тулзы попадал в модель как есть — без валидации, без фильтрации, без возможности исправить ошибку. Релиз 29 августа 2026 года (GitHub) добавил два механизма, которые меняют эту картину: расширения (extensions) теперь перехватывают результаты MCP-тулзов до попадания в модель, а задержка старта для optional-серверов стала настраиваемой. Ниже — как использовать оба на практике.

Релиз Codex 0.151.0 на GitHub (29.08.2026)
Запись релиза Codex 0.151.0: перехват MCP tool results и grace period. Источник: github.com/openai/codex/releases.

Что изменилось в 0.151.0

Три ключевых фичи релиза (changelog):

Фича Что делает Пул-реквест
Extension MCP result interception Расширения могут инспектировать и заменять результаты MCP-тулзов до отправки в модель #41202
Configurable grace period Настраиваемая задержка ожидания optional MCP-серверов при старте #41199
Per-repo plugin catalog Каталог плагинов учитывает конфигурацию конкретного репозитория #41208

Обновление — стандартное:

codex --version   # проверить текущую версию
# для standalone:
curl -fsSL https://chatgpt.com/codex/install.sh | sh
# для npm:
npm update -g @openai/codex

На момент публикации актуальная версия — 0.151.0 (стабильная). Если у вас стоит 0.149.0 или 0.150.0 — обновление обязательно: оба ключевых механизма отсутствуют в старых версиях.

Зачем перехватывать результаты MCP-тулзов

Стандартный пайплайн MCP в Codex выглядит так: агент вызывает тулзу → MCP-сервер обрабатывает запрос → JSON-результат попадает в модель как часть контекста. Проблема в том, что модель получает сырые данные без какой-либо обработки.

На практике это приводит к трём категориям situations (по данным PR #41202):

  1. Секреты в ответах. MCP-сервер может вернуть API-токены, пароли или внутренние идентификаторы в теле ответа. Модель видит их и может воспроизвести в генерируемом коде или командах.

  2. Неформатированные ошибки. Когда MCP-сервер возвращает ошибку (isError: true), модель получает сырой JSON сtechnical details — stack trace, HTTP-коды, внутренние пути сервера. Вместо этого агенту полезнее видеть человекочитаемое описание проблемы.

  3. Раздутые контексты. Некоторые MCP-тулзы возвращают многостраничные JSON-ответы (каталоги, списки, дампы). Без фильтрации они съедают контекстное окно модели.

До 0.151.0 исправить это можно было только через промпт — просить модель «игнорировать секреты» или «кратко описывать ошибки». Это ненадёжно: модель не всегда следует таким инструкциям, особенно при длинных сессиях.

Схема: поток MCP tool result без расширения и с расширением
Сравнение потоков: без расширения (слева) результат MCP-тулзы попадает в модель напрямую; с расширением (справа) проходит через on_mcp_tool_result() для валидации и фильтрации.

Extension MCP result interception: как работает

С 0.151.0 расширения (extensions) могут подписаться на событие on_mcp_tool_result (PR #41202). Колбэк вызывается после завершения MCP-вызова, но до отправки результата в модель и до публикации completion-события.

Техническая реализация

Новый интерфейс ToolLifecycleContributor добавляет метод:

fn on_mcp_tool_result<'a>(&'a self, _input: McpToolResultInput<'a>) -> ToolLifecycleFuture<'a> {
    Box::pin(std::future::ready(()))
}

McpToolResultInput содержит (исходный код):

Поле Тип Что содержит
session_store &SessionExtensionData Данные расширения на уровне сессии
thread_store &ThreadExtensionData Данные расширения на уровне треда
turn_store &TurnExtensionData Данные расширения на уровне хода
turn_id &str Идентификатор текущего хода
call_id &str Идентификатор MCP-вызова
mcp_tool &McpToolContext Контекст тулзы: имя, сервер, источник (Connector / CodeMode)
arguments &Value Аргументы, с которыми вызвана тулза
result &mut CallToolResult Мутируемый результат — можно заменить или модифицировать

Ключевой момент — result передаётся как &mut: расширение не просто видит результат, а может его изменить. Модификация применяется к обоим направлениям — и в completion-события (для UI), и в контексте модели.

Порядок выполнения

Код из lifecycle.rs показывает цепочку:

MCP-сервер → result → on_mcp_tool_result() → sanitize → модель

Расширения выполняются последовательно — каждое видит результат предыдущего. Это позволяет выстраивать цепочки: первое расширение удаляет секреты, второе логирует результат, третье форматирует ошибки.

Что можно делать в on_mcp_tool_result

На основании тестов в tool_lifecycle.rs, поддерживается три сценария:

Сценарий Что делает расширение Пример
Unchanged Оставляет результат как есть Логирование MCP-вызова
Replace Заменяет результат целиком Удаление секретов из ответа
Error Помечает результат как ошибку Валидация формата ответа

Тесты проверяют оба режима вызова MCP-тулз — прямой вызов (Direct) и вызов через Code Mode (tools.mcp__* в exec-режиме). В обоих случаях расширение корректно перехватывает результат (тесты).

Практический пример: фильтрация секретов

Допустим, у вас MCP-сервер, подключающийся к корпоративному API. Он возвращает ответы, содержащие временные токены доступа:

{
  "content": [{"type": "text", "text": "Results for query..."}],
  "_meta": {
    "access_token": "eyJhbGciOi...",
    "refresh_token": "dGhpcyBpcyBh..."
  }
}

Расширение для Codex может очищать такие данные:

impl ToolLifecycleContributor for SecretSanitizer {
    fn on_mcp_tool_result<'a>(&'a self, input: McpToolResultInput<'a>) -> ToolLifecycleFuture<'a> {
        Box::pin(async move {
            // Удаляем чувствительные поля из _meta
            if let Some(meta) = input.result.get_mut("_meta") {
                if let Value::Object(map) = meta {
                    map.remove("access_token");
                    map.remove("refresh_token");
                }
            }
        })
    }
}

Модель видит только результат запроса — без токенов, которые могли бы просочиться в генерируемый код.

Практический пример: валидация формата

Другой сценарий: MCP-сервер иногда возвращает ошибки в неожиданном формате. Вместо стандартного { "isError": true, "content": [...] } он отдаёт plain-text описание или HTML:

Error: Connection refused to postgres://...

Расширение нормализует такие ответы:

impl ToolLifecycleContributor for ErrorNormalizer {
    fn on_mcp_tool_result<'a>(&'a self, input: McpToolResultInput<'a>) -> ToolLifecycleFuture<'a> {
        Box::pin(async move {
            if input.result.is_error {
                // Форматируем ошибку в человекочитаемый вид
                let text = input.result.content.iter()
                    .filter_map(|c| match c {
                        ContentItem::Text { text, .. } => Some(text.as_str()),
                        _ => None,
                    })
                    .collect::<Vec<_>>()
                    .join(" ");

                // Убираем технические детали: пути, токены, стек-трейсы
                let clean = sanitize_error_message(&text);

                input.result.content = vec![ContentItem::Text {
                    text: format!("MCP-сервер вернул ошибку: {clean}"),
                    annotations: None,
                }];
            }
        })
    }
}

Агент получает чистое описание проблемы, модель не тратит контекст на технический мусор.

Grace period для optional MCP-серверов

Второй ключевой механизм — PR #41199. До 0.151.0 Codex ждал определённое время подключения каждого optional MCP-сервера, и эта задержка была фиксированной. Теперь параметр mcp_optional_startup_grace_ms доступен в конфигурации.

Как это работает

При старте Codex подключается к MCP-серверам параллельно. Required-серверы блокируют запуск — если они не подключились, Codex не начнёт работу. Optional-серверы — нет: агент стартует без них, но только если за отведённое время (grace period) они не появились.

По умолчанию grace period = 1000 мс (PR description):

Add mcp_optional_startup_grace_ms with a default of 1,000 ms to control how long tool catalog capture waits for optional MCP servers.

Когда менять grace period

Сценарий Значение Почему
Быстрые MCP-серверы (локальные) 1000 (по умолчанию) Хватает для подключения
Тяжёлые серверы (БД, удалённые API) 3000–5000 Даём время на старт
Отключение общей задержки 0 Каждый сервер использует свой startup_timeout_sec

Конфигурация

В config.toml или ~/.codex/config.toml:

# Глобальная задержка для optional-серверов (мс)
mcp_optional_startup_grace_ms = 3000

[mcp_servers.postgres]
command = "mcp-postgres"
args = ["postgresql://localhost/mydb"]
optional = true
startup_timeout_sec = 5

[mcp_servers.github]
command = "mcp-github"
optional = false  # required — не зависит от grace period

При mcp_optional_startup_grace_ms = 0 общая задержка отключается — optional-серверы используют индивидуальные значения startup_timeout_sec. Это полезно, если у вас смешанный стек: часть серверов быстрые (мгновенно), часть — тяжёлые (запускаются по 5–10 секунд).

Схема: конфигурация grace period для optional MCP-серверов
Настройка grace period: до 0.151.0 задержка была фиксированной (слева), теперь настраивается через mcp_optional_startup_grace_ms (справа).

Настройка во время работы

Параметр применяется не только при старте, но и при обновлении MCP-конфигурации:

Apply updated grace values during runtime and MCP configuration refreshes, and reset cached startup deadlines when the configured duration changes.

Это значит, что можно менять grace period через /cd (смена рабочей папки перезагружает конфиг) или при обновлении конфига — не требуя перезапуска сессии.

Сценарии использования

1. Централизованная валидация MCP-ответов

Если вы работаете с несколькими MCP-серверами и хотите гарантировать формат ответов — расширение проверяет result.content на соответствие ожидаемой структуре. Невалидные ответы заменяются на стандартизированную ошибку.

2. Аудит MCP-вызовов

Расширение логирует каждый MCP-вызов: имя тулзы, аргументы, время выполнения, размер ответа. Полезно для отладки долгих серверов или поиска тулз, которые раздувают контекст.

3. Кэширование результатов

Если MCP-тулза вызывается повторно с теми же аргументами — расширение может вернуть кэшированный результат, не обращаясь к серверу. Это ускоряет работу агента при повторяющихся запросах.

4. Комбинирование с grace period

Для production-окружений с несколькими optional-серверами:

  1. Увеличьте grace period до 3–5 секунд, чтобы дать время тяжёлым серверам
  2. Добавьте расширение, которое помечает результаты от отсутствующих серверов как «сервер недоступен, результат неполный»
  3. Модель получает осмысленную информацию о доступности инструментов

Российские реалии

  • Установка и обновление Codex CLI — штатные: GitHub и npm доступны из РФ без VPN. Обновление через curl | sh или npm update -g @openai/codex работает без ограничений.
  • Вход — через ChatGPT (OAuth) требует VPN из-за ограничений OpenAI по российским IP; через API-ключ (OPENAI_API_KEY) работает стабильнее.
  • Оплата — российские Visa/Mastercard не принимаются. Рабочие варианты: виртуальные зарубежные карты (пополнение по СБП или USDT), карты банков Казахстана/Грузии/Армении. Подробности — в статье «Как оплатить подписку ChatGPT из России в 2026 году».
  • Russian providers — Codex CLI можно подключить к другим провайдерам. Разработчик на практике собрал Codex CLI с инференсом Яндекса через AI Studio API — «Агентность на практике: Codex CLI и российский AI-ландшафт».
  • Русскоязычные материалы: полный гид по Codex CLI — «Ультимативный гид по Codex CLI», сравнение CLI-агентов — Habr, 4 августа 2026.

Ограничения

  • Extensions —perimental API. Интерфейс ToolLifecycleContributor появился в 0.151.0; структура McpToolResultInput и набор полей могут измениться в следующих релизах. Проверяйте changelog при обновлении Codex.
  • Расширения не заменяют валидацию на стороне MCP-сервера. Перехват в расширении — это последний рубеж перед моделью. Если MCP-сервер генерирует некорректные данные, лучше исправить его, а не обрабатывать симптомы в расширении.
  • Grace period не влияет на required-серверы. Если required MCP-сервер не подключился за startup_timeout_sec, Codex завершится с ошибкой — обойти это нельзя и не нужно.
  • Нет встроенных расширений для фильтрации. Codex 0.151.0 добавляет API, но не поставляет расширения из коробки. Фильтрацию секретов, валидацию формата и другие сценарии нужно реализовать самостоятельно или ждать появления готовых решений в каталоге плагинов.
  • Контекстное окно не расширяется. Grace period ускоряет старт за счёт включения optional-серверов, но не увеличивает объём контекста. Декомпозиция задач и /new между батчами по-прежнему рекомендуются — об этом подробнее в статье «Как установить Codex CLI».
  • Из РФ — все ограничения OpenAI по входу и оплате сохраняются; extensions и grace period не зависят от региона.

Связанные статьи

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка / 5. Количество оценок:

Оценок пока нет. Поставьте оценку первым.

Добавить комментарий

Adblock
detector