До появления MCP Apps каждый ответ MCP-сервера был «стеной текста». Агент вызывал инструмент, получал JSON или Markdown, и вся «красота» диалога жила в силах модели. Это не проблема для справки или генерации кода, но это тупик там, где нужны кликабельные элементы: выбор товара, чекаут, фильтры в каталоге, формы, интерактивные дашборды.

В январе 2026-го команды MCP, OpenAI и MCP-UI зафиксировали первое официальное расширение протокола — MCP Apps. Теперь инструмент может вернуть не только текст, но и интерактивный UI-блок, который рендерится прямо в чате, в изолированном iframe, с безопасным обменом сообщениями между UI и моделью.

MCP Apps — это «App Bridge + sandboxed iframe + postMessage-протокол поверх JSON-RPC», а не новый фреймворк и не отдельная экосистема. Тот же MCP-сервер, тот же набор tools, та же модель безопасности — плюс опциональный UI-ресурс, который клиент-хост умеет рендерить, если объявил поддержку Apps Extension в своих capabilities.

MCP Apps — официальное расширение Model Context Protocol. Группа работ SEP-1865 введена 21 ноября 2025 года, официальный релиз — 26 января 2026-го (спецификация 2026-01-26). Под капотом — sandboxed iframe, App Bridge и message passing между UI и моделью.

Что это

MCP — открытый «USB-C для ИИ» (формулировка modelcontextprotocol.io). До MCP Apps сервер мог выдавать в ответ на tool call только текст или structured data. MCP Apps добавляет в этот ответ «UI-ресурс» — HTML/JS-блок, который клиент (ChatGPT, Claude Desktop, VS Code, любой хост на App Bridge) встраивает в диалог.

Где расширение работает сегодня:

  • Клиенты, поддерживающие Apps Extension: Claude, Claude Desktop, VS Code GitHub Copilot, Microsoft 365 Copilot, Goose, Postman, MCPJam, Archestra.AI. Полный список — в client matrix.
  • Хосты на @mcp-ui/client — React-компоненты для рендера MCP Apps Views.
  • Собственные хосты поверх App Bridge из ext-apps — официального репозитория спецификации и SDK.

Зачем нужно

MCP Apps закрывают пять типов задач, в которых чистый текст или Markdown хуже UI.

  • Исследование сложных данных. «Покажи продажи по регионам» в виде списка — слабо. Виджет с интерактивной картой, кликами по регионам и переключателями метрик — сильно.
  • Конфигурация с большим числом опций. Деплой с десятками связанных параметров превращается из переписки в форму с дефолтами и валидацией.
  • Просмотр мультимедиа. PDF, 3D-модели, сгенерированные изображения — встраиваются прямо в чат с pan/zoom/rotate, без ссылки на отдельный просмотрщик.
  • Мониторинг в реальном времени. Дашборды метрик и логов, которые обновляются без нового вызова LLM.
  • Многошаговые сценарии. Аппрув отчётов, ревью изменений, тикеты — навигация, кнопки действий, состояние между шагами.

Ключевое преимущество перед «просто отдайте ссылку на ваш сайт» — контекст сохраняется: UI живёт внутри разговора, не в новой вкладке, и продолжает использовать уже подключённые к хосту инструменты и авторизации. Источник — обзор MCP Apps в modelcontextprotocol.io.

Как устроено

MCP-сервер возвращает в ответе три вещи:

  • Текст для модели — как раньше, чтобы LLM поняла результат и рассуждала дальше.
  • UI-ресурс — HTML/JS-блок с интерактивом, рендерящийся в изолированном iframe на стороне клиента.
  • Метаданные — высота, режим отображения, разрешённые capabilities (permissions и csp в _meta.ui), домены внешних ресурсов.

App Bridge — ядро расширения на стороне клиента. Он делает четыре вещи.

  • Рендерит приложение в sandboxed iframe (UI не имеет доступа к странице хоста, cookies, localStorage родителя).
  • Передаёт сообщения между UI и хостом через postMessage (транспорт MCP Apps).
  • Проксирует tool calls: UI может запросить «обновить данные» или «закрыть блок» без отдельного раунда LLM.
  • Применяет security policy: хост выбирает, какие capabilities разрешить (открыть ссылку, вызвать tool, отправить контекст в модель).

Схема взаимодействия — от запроса пользователя до обновления интерфейса (по официальной документации modelcontextprotocol.io):

sequenceDiagram
    participant User
    participant Agent
    participant App as MCP App iframe
    participant Server as MCP Server

    User->>Agent: "show me analytics"
    Note over User,App: Interactive app rendered in chat
    Agent->>Server: tools/call
    Server-->>Agent: tool input/result
    Agent-->>App: tool result pushed to app
    User->>App: user interacts
    App->>Agent: tools/call request
    Agent->>Server: tools/call (forwarded)
    Server-->>Agent: fresh data
    Agent-->>App: fresh data
    Note over User,App: App updates with new data
    App-->>Agent: context update

Когда использовать

MCP Apps — это расширение, а не замена обычному MCP-инструменту. Оно оправдано там, где текстовый ответ хуже интерактивного интерфейса, и не оправдано там, где текста достаточно.

  • E-commerce. Витрина внутри чата: карточки товаров, выбор размера, корзина, чекаут. Агент ведёт диалог, UI берёт визуальные решения на себя. Shopify собрал такой сценарий первым и описал опыт в «MCP UI — breaking the text wall».
  • Дашборды и аналитика. Tool «покажи метрики» возвращает график, где пользователь переключает даты и сегменты без нового LLM-вызова.
  • Формы и визарды. Онбординг, заявки, опросы. Агент объясняет и подбирает дефолты, UI собирает структурированные данные.
  • Продуктовые карточки. Карты, расписания рейсов, бронирование отелей — всё, что плохо живёт в виде Markdown-списка.
  • Многошаговые сценарии. Debug-панель для внутреннего инструмента: логи, фильтры, кнопки retry, переключение окружений.

UI в MCP — это удобно для пользователя, но расхождение с «чистым текстовым» агентом. Чем больше бизнес-логики вы переносите в UI, тем сложнее потом использовать тот же MCP-сервер в voice-интерфейсе или в фоновых агентах. Разумно строить MCP в два слоя: вся логика — в tool, UI — только рендер результата.

Пример

Минимальный ответ MCP-сервера с UI-ресурсом — формат, который объявлен в официальной спецификации Apps Extension:

// Сервер возвращает инструмент с UI
const result = {
  content: [
    { type: "text", text: "Для вас подобралось 12 рейсов." },
    {
      type: "resource",
      resource: {
        uri: "ui://flights/list?date=2026-06-01",
        mimeType: "text/html",
        text: `<flight-picker data-route="..."></flight-picker>`,
      },
    },
  ],
};

В официальном репозитории ext-apps уже есть набор стартовых шаблонов на разных фреймворках (React, Vue, Svelte, Preact, Solid, vanilla JavaScript) и готовые демо под конкретные задачи.

Запустить всё локально можно через basic-host — референсную реализацию хоста из того же репозитория:

git clone https://github.com/modelcontextprotocol/ext-apps.git
cd ext-apps
npm install
npm start
# открыть http://localhost:8080/

Ограничения

Ограничения

Поддержка клиентов ограничена — на июль 2026 Apps Extension понимают Claude, Claude Desktop, VS Code GitHub Copilot, Microsoft 365 Copilot, Goose, Postman, MCPJam, Archestra.AI.

Сервер обязан грациозно деградировать: в client capabilities проверять поддержку расширения и при отсутствии отдавать чистый текст или Markdown.

Sandbox iframe — не панацея — iframe изолирует UI от хоста, но не от вашего backend.

Все user-supplied данные, попадающие в HTML, нужно экранировать; CSP и домены внешних ресурсов ограничиваются в _meta.ui.csp.

Состояние — только на сервере — UI — это «вид», а не «источник правды».

Если состояние живёт только в iframe, пользователь закроет чат — и всё потеряется. Долгие сценарии требуют серверной персистентности и реактивной подгрузки.

Узкие колонки чата — UI рендерится в узкой левой панели ChatGPT или в панели IDE.

Mobile-first, минимальная ширина, ничего не выезжает за границы, адаптивная высота обязательна.

Accessibility — не опция — Tab-навигация, focus rings, осмысленные ARIA-роли.

Без этого ломаются скринридеры и голосовое управление в чате.

Trade-off с текстовым агентом — чем больше логики вы уносите в UI, тем меньше ваш сервер пригоден для voice-агентов, фоновых скриптов и batch-задач.

Стройте логику в tool, UI — только рендер.

Антипаттерны

Антипаттерны

Отдавать UI без проверки capabilities — клиент без Apps Extension покажет пустоту или ошибку.

Всегда проверяйте capabilities и имейте текстовый fallback.

Хранить состояние в iframe — закроется чат — потеряются данные.

Сессия — на сервере, UI получает данные через notifications и tool calls.

Инжектировать input в HTML без escape — iframe изолирует UI от родителя, но не защищает ваш компонент от XSS.

Любой текст от пользователя или модели в markup должен проходить экранирование.

Тащить всю логику в UI — тот же сервер перестанет работать в фоне, в CLI-агенте и в голосовом интерфейсе.

Логика — в tool, UI — только рендер.

Делать desktop-only интерфейс — чат-панели узкие, IDE-встраивания ограничены по высоте.

Mobile-first и адаптивная высота обязательны.

Подменять модель UI-вызовами — UI может вызывать tool напрямую, но это не отменяет LLM.

Если UI целиком обходит модель, теряются reasoning и контекст разговора.

Чеклист

Чеклист

Capabilities клиента проверены

— если хост не объявил поддержку Apps, сервер возвращает чистый текст или Markdown без UI-ресурса.

Текст для модели остаётся в ответе

— даже когда UI рендерит интерфейс, content[0] — это text, который LLM прочитает и использует в следующих рассуждениях.

HTML экранирован

— никакого user-supplied input в markup без escape; CSP и домены внешних ресурсов ограничены _meta.ui.csp.

Permissions в _meta.ui минимальны — запрашивайте только то, что UI реально использует.

Лишний microphone или sendOpenLink повышают поверхность атаки и настораживают пользователя.

Состояние

— на сервере — UI получает данные через notifications и tool calls, не хранит их между сессиями.

Логика

— в tool — UI вызывает существующие MCP-tools, не дублирует бизнес-правила в JavaScript.

Mobile-first вёрстка

— ширина 320–400 px, нет горизонтального скролла, высота адаптивна, нет hover-only сценариев.

Accessibility пройдена

— Tab-навигация по интерактивным элементам, видимый focus ring, ARIA-роли, текстовые альтернативы для графиков.

Есть текстовый fallback

— пользователь в клиенте без Apps получает тот же ответ в виде структурированного текста — без потери смысла.

Версия спецификации зафиксирована — сейчас 2026-01-26 в ext-apps.

Обновления отслеживаются через draft/apps.mdx в репозитории.

Ссылки

Ссылки