Skip to main content
Glama
vpm238
by vpm238

mcp-a2ui-vega

MCP-приложение с интерфейсом A2UI и графиками Vega-Lite.

Попросите Claude показать дашборд продаж билетов — и он появится в разговоре: метрики, графики, таблица последних заказов, место для загрузки CSV. Затем попросите изменить что-то — превратите график продаж в линейный и покажите сегодняшние продажи зелёным, добавьте тепловую карту, когда люди покупают — и дашборд будет отредактирован на месте, а не перерисован с нуля. Перетащите в него CSV или добавьте строки из скрипта — и каждый график обновится сам по себе.

Дашборд — это не картинка, созданная моделью. Это дерево компонентов, которое агент собрал из типизированного каталога, отрисованное собственным рендерером A2UI от Google (@a2ui/react), привязанное к набору данных, который отправляет ему изменения.

Из чего он состоит

Компонент

Что делает

packages/catalog

Каталог A2UI — API компонентов, функции и JSON-Schema-документ, сгенерированный из них. Контракт между агентом и рендерером.

packages/renderer

Представление MCP-приложения: React + @a2ui/react, реализация каталога на Vega-Lite и мост MCP Apps.

packages/server

Cloudflare Worker: MCP-сервер, хранилище наборов данных, библиотека сохранённых виджетов и ресурс ui://.

data

Набор данных, основанный на реальных еженедельных сборах Бродвея.

skills/a2ui-dashboards

Навык, который учит агента хорошо собирать и пересобирать такие дашборды.

tools

Сборщик набора данных, канал живого добавления, тестовый хост, сквозной тест.

Никаких API-ключей. В этом репозитории нет модели. Агент — это любой MCP-хост, который подключается; сервер хранит строки и собирает JSON; рендерер детерминирован. Единственные учётные данные — это Cloudflare-ключи, которые нужны для развёртывания Worker.

Related MCP server: vegalite-viewer

Что это такое в терминах самого A2UI

В статье Google A2UI and MCP Apps названы три способа совместной работы двух протоколов. Этот репозиторий — Паттерн 3: A2UI внутри MCP Apps — пакет MCP-приложения несёт собственный рендерер A2UI, что позволяет хосту, который никогда не слышал об A2UI (сегодня это Claude), показывать UI, собранный агентом.

Это настоящий A2UI, а не его имитация. Рендерер — это @a2ui/react, управляющий MessageProcessor из @a2ui/web_core — пакеты Google, без изменений. Формат передачи — сообщения A2UI v0.9: createSurface, updateComponents, updateDataModel. Каталог расширяет собственный базовый каталог A2UI, а не заменяет его, поэтому Column, Card и ChoicePicker — их, а VegaChart — наш, под одним идентификатором каталога.

Здесь также реализован Паттерн 1: A2UI поверх MCP как второй путь — тот же дашборд отдаётся как application/a2ui+json по адресу a2ui://dashboard/ticket_sales, так что хост с собственным рендерером A2UI (Flutter, Angular, нативный клиент) может отрисовать его вообще без iframe. Этот payload — переносимый артефакт; MCP-приложение — способ увидеть его всем остальным.

Как дашборд остаётся живым

agent ──render_dashboard──▶ server ──A2UI messages in _meta──▶ view

                     ┌──────── change stream (SSE) ────────┐
server ──────────────┘  "ticket_sales moved"               ▼
   ▲                                                      view
   └── get_dataset_rows, through the host's tool proxy ──── │
                                                            │
                                          updateDataModel ──┘  every chart,
                                                               tile and table
                                                               re-renders

Основную работу делают четыре решения:

Строки никогда не проходят через модель. render_dashboard возвращает раскладку и количество строк. Представление само получает строки через get_dataset_rows — инструмент, у которого _meta.ui.visibility равно ["app"], поэтому он никогда не появляется в списке инструментов агента. Двенадцать тысяч заказов должны быть в графике, а не в контекстном окне.

Дашборд — это компоненты, а не изображение. Изменение одного графика — это один вызов update_dashboard с указанием одного id. Фильтры пользователя, порядок сортировки и позиция прокрутки сохраняются, потому что больше ничего не затрагивается.

Обновление должно отображаться в представлении, которое никогда не видело дашборд. Хост может открывать новое представление для каждого результата инструмента, а не направлять его в текущее, и payload из чистых updateComponents нечего обновлять там — A2UI отклоняет его с ошибкой surface not found, и пользователь получает пустую панель там, где просил изменение. Поэтому сервер запоминает собранное дерево, и каждое обновление передаётся в двух формах: _meta['a2ui/messages'] пересобирает всю поверхность с нуля, _meta['a2ui/patch'] несёт только дельту. Представление применяет ту, которая подходит к тому, что у него уже есть, так что серверу не нужно угадывать, с каким представлением он разговаривает.

Сервер говорит когда, хост по-прежнему несёт что. В MCP нет канала сервер→представление, поэтому представление держит открытым поток изменений напрямую к Worker — единственное, что ресурс приложения разрешает в csp.connectDomains. По нему приходит уведомление, а не данные: строки по-прежнему загружаются через прокси инструментов хоста, так что каждый байт данных остаётся проверяемым. Простаивающий дашборд не делает никаких запросов, а изменение доходит до него примерно за секунду.

Любой график, включая те, которых нет в каталоге

VegaChart принимает целую спецификацию Vega-Lite как свойство. Тепловая карта, ящик с усами, фасетные малые множества — ни одного из них нет в каталоге, и все они работают, потому что граница каталога — это типы компонентов, а не типы графиков.

Когда пользователю нравится какой-то график, save_widget сохраняет его по имени, а render_dashboard({widgets: ["sales_by_hour_heatmap"]}) возвращает его в более позднем разговоре — всё ещё привязанным к живому набору данных, так что он обновляется, как и всё остальное.

Данные

data/ticket_sales.csv — это по одной строке на каждый заказ билетов по двенадцати бродвейским шоу. Шоу, их театры, размеры залов, недельная заполняемость и уровни цен — реальные, из набора данных Broadway weekly grosses dataset (Playbill, через TidyTuesday). Отдельные заказы смоделированы на основе этих цифр, потому что источник — недельный и агрегированный. В data/README.md точно сказано, какие части какие.

npm run data:build                    # rebuild, 90 days ending now
npm run data:append -- --watch 10     # a live feed: new orders every 10s

Укажите это для развёртывания с --url https://your-worker.workers.dev и наблюдайте, как дашборд движется, пока вы на него смотрите — в течение секунды после каждого добавления, потому что сервер сообщает ему об этом.

Запуск

npm install
npm run data:build          # build the dataset (downloads the source CSV once)
npm run build               # catalog → renderer → single-file app → worker
npm run dev -w @mcp-a2ui-vega/server

Затем откройте http://localhost:8788/app.html для дашборда отдельно или http://localhost:8788/ для инструкций по подключению.

Установка в Claude

Сначала разверните (ниже) — до пользовательского коннектора обращаются из облака Anthropic, а не с вашей машины, так что localhost не подойдёт.

Claude Code, прямо из этого репозитория:

/plugin marketplace add vpm238/mcp-a2ui-vega
/plugin install a2ui-vega-dashboards@mcp-a2ui-vega

Это устанавливает MCP-сервер и навык вместе. URL сервера указан в .claude-plugin/plugin.json — если вы развернёте собственный Worker, измените эту одну строку и выполните /plugin marketplace update mcp-a2ui-vega.

Claude web или desktop: Настройки → Коннекторы → Добавить пользовательский коннектор и вставьте https://your-worker.workers.dev/mcp. Никакого OAuth и ключей нет. Затем добавьте навык: заархивируйте папку skills/a2ui-dashboards — сама папка должна быть в корне архива — и загрузите её в Настройки → Возможности → Навыки.

Навык в любом случае необязателен: сервер отправляет инструкции по использованию в своём MCP-рукопожатии. Именно он делает последующие запросы хорошими — редактирование одного компонента вместо перерисовки всего и запоминание понравившихся графиков.

Затем попросите дашборд продаж билетов.

Развёртывание

Worker — единственное, что нужно хостить. GitHub Pages получает автономное демо.

npx wrangler login
npm run deploy -w @mcp-a2ui-vega/server

Это создаёт пространство имён KV, если его ещё нет, записывает его id в wrangler.toml, собирает приложение и начальные данные и развёртывает.

Или добавьте два секрета репозитория и отправьте в mainрабочий процесс делает всё это, включая создание пространства имён, и пропускает развёртывание с предупреждением, а не с ошибкой, пока секреты отсутствуют:

Секрет

Что это такое

CLOUDFLARE_API_TOKEN

Токен из шаблона Edit Cloudflare Workers

CLOUDFLARE_ACCOUNT_ID

Ваш id аккаунта, из панели Workers

Тот же рабочий процесс публикует автономное демо на GitHub Pages, как только Pages включён в Настройки → Pages с источником GitHub Actions. Пока этого не произошло, рабочий процесс сообщает об этом в предупреждении и остаётся зелёным.

Тестирование

npm test                                       # dataset and catalog checks
npm run dev -w @mcp-a2ui-vega/server           # terminal 1
python3 -m http.server 8479                    # terminal 2, at the repo root
node tools/e2e.mjs                             # a real browser, the real protocol

Чтобы запустить тот же набор тестов против развёртывания, а не локального worker:

node tools/relay.mjs https://your-worker.workers.dev     # terminal 3
SERVER_URL=http://localhost:8790 node tools/e2e.mjs

Ретранслятор существует потому, что браузер за строгим прокси может не достать до Cloudflare, в то время как Node может; каждый байт по-прежнему приходит из реального развёртывания. Он буферизует ответы, поэтому не переносит поток изменений — представление за ним переходит на опрос, что тоже стоит проверить.

tools/e2e.mjs управляет tools/harness.html — самодельным MCP Apps-хостом, ~120 строк, намеренно не разделяющим код с приложением, чтобы ошибка протокола не могла незаметно пройти в обоих. Он проверяет то, что проверка типов не может: что дашборд рисуется, что пересборка перекрашивает одну плитку, не затрагивая остальные, что добавленные строки приходят без запроса, что фильтр двигает метрики и таблицу вместе, и что сохранённый виджет возвращается.

tools/push-latency.mjs измеряет то, что заявляет архитектура: простаивающий дашборд делает ноль запросов, а изменение доходит до него примерно за полсекунды ровно с одним fetch.

node tools/push-latency.mjs https://your-worker.workers.dev

Лицензия

MIT.

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    A
    quality
    B
    maintenance
    MCP server that lets agents create, display, and export rich UI widgets (cards, dashboards, charts, forms) inline in conversations, with interactive iframe support in MCP Apps hosts and PNG image fallback for other clients.
    3

View all related MCP servers

Related MCP Connectors

  • Create, browse, remix, collaborate on, and run durable AI workflow nodes from MCP hosts.

  • Build, deploy, and operate hosted web apps on VibeKit (vibekit.bot) from any MCP client.

  • MCP Hub: AI service discovery, per-user OAuth, and multi-service workflow orchestration

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vpm238/mcp-a2ui-vega'

If you have feedback or need assistance with the MCP directory API, please join our Discord server