Skip to main content
Glama
vpm238
by vpm238

mcp-a2ui-vega

Una MCP App cuya interfaz es A2UI y cuyos gráficos son Vega-Lite.

Pídele a Claude el panel de ventas de entradas y aparecerá en la conversación: métricas, gráficos, una tabla con los últimos pedidos y un lugar donde soltar un CSV. Luego pide cambios — convierte el de ventas en un gráfico de líneas y muestra las ventas de hoy en verde, añade un mapa de calor de cuándo compra la gente — y el panel se edita en su sitio, sin redibujarse desde cero. Suelta un CSV en él, o añade filas desde un script, y cada gráfico se mueve por su cuenta.

El panel no es una imagen que haya producido el modelo. Es un árbol de componentes que el agente compuso a partir de un catálogo tipado, dibujado por el propio renderizador A2UI de Google (@a2ui/react), vinculado a un dataset que le envía los cambios.

De qué está hecho

Pieza

Qué hace

packages/catalog

El catálogo A2UI: APIs de componentes, funciones y el documento JSON-Schema generado a partir de ellas. El contrato entre el agente y el renderizador.

packages/renderer

La vista de MCP App: React + @a2ui/react, una implementación en Vega-Lite del catálogo y el puente de MCP Apps.

packages/server

Un Cloudflare Worker: el servidor MCP, el almacén del dataset, la biblioteca de widgets guardados y el recurso ui://.

data

El dataset, anclado en las recaudaciones semanales reales de Broadway.

skills/a2ui-dashboards

El skill que enseña a un agente a componer y recomponer bien estos paneles.

tools

Constructor del dataset, fuente de append en vivo, harness de host, prueba de extremo a extremo.

Sin claves de API. En este repositorio no hay ningún modelo. El agente es el host MCP que se conecte; el servidor almacena filas y compone JSON; el renderizador es determinista. Las únicas credenciales que intervienen son las de Cloudflare que necesitas para desplegar el Worker.

Related MCP server: vegalite-viewer

Qué es esto, en los propios términos de A2UI

El artículo de Google A2UI and MCP Apps enumera tres formas en que los dos protocolos se combinan. Este repositorio es el Patrón 3: A2UI dentro de MCP Apps — el bundle de MCP App lleva su propio renderizador A2UI, que es lo que permite que un host que nunca ha oído hablar de A2UI (Claude, hoy) muestre igualmente una interfaz compuesta por el agente.

Es A2UI de verdad, no una imitación. El renderizador es @a2ui/react manejando el MessageProcessor de @a2ui/web_core — los paquetes de Google, sin modificar. El formato de transmisión son mensajes A2UI v0.9: createSurface, updateComponents, updateDataModel. El catálogo extiende el catálogo básico de A2UI en lugar de sustituirlo, así que Column, Card y ChoicePicker son suyos y VegaChart es nuestro, bajo un mismo id de catálogo.

También implementa el Patrón 1: A2UI sobre MCP como segunda vía: el mismo panel se sirve como application/a2ui+json en a2ui://dashboard/ticket_sales, de modo que un host con su propio renderizador A2UI (Flutter, Angular, un cliente nativo) puede dibujarlo sin ningún iframe. Ese payload es el artefacto portable; la MCP App es la forma que tienen todos los demás de verlo.

Cómo se mantiene vivo un panel

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

Cuatro decisiones hacen la mayor parte del trabajo:

Las filas nunca viajan a través del modelo. render_dashboard devuelve un diseño y un recuento de filas. La vista obtiene las filas por sí misma con get_dataset_rows, una herramienta cuyo _meta.ui.visibility es ["app"], de modo que nunca aparece en la lista de herramientas del agente. Doce mil pedidos pertenecen a un gráfico, no a una ventana de contexto.

Un panel son componentes, no una imagen. Cambiar un gráfico es un solo update_dashboard que nombra un id. Los filtros del usuario, el orden de clasificación y la posición de scroll se conservan, porque no se ha tocado nada más.

Una actualización debe poder renderizarse en una vista que nunca ha visto el panel. Un host es libre de abrir una vista nueva por cada resultado de herramienta en lugar de enrutarlo hacia la vista en marcha, y un payload de solo updateComponents no tiene nada que actualizar allí — A2UI lo rechaza con surface not found, y el usuario obtiene un panel en blanco donde pidió un cambio. Así que el servidor recuerda el árbol compuesto, y cada actualización viaja en dos formas: _meta['a2ui/messages'] reconstruye toda la superficie desde cero, _meta['a2ui/patch'] lleva solo el delta. La vista aplica la que encaje con lo que ya tiene, de modo que el servidor nunca tiene que adivinar con qué vista está hablando.

El servidor dice cuándo; el host sigue llevando el qué. MCP no tiene canal servidor→vista, así que la vista mantiene abierto un flujo de cambios directo al Worker — lo único que el recurso de la app permite en csp.connectDomains. Lo que baja es una notificación, nunca datos: las filas se siguen obteniendo a través del proxy de herramientas del host, así que cada byte de datos sigue siendo auditable. Un panel inactivo no hace ninguna petición, y un cambio le llega en aproximadamente un segundo.

Cualquier gráfico, incluidos los que el catálogo nunca nombró

VegaChart acepta una especificación completa de Vega-Lite como propiedad. Un mapa de calor, un diagrama de caja, un panel de pequeños múltiples — ninguno está en el catálogo, y todos funcionan, porque el límite del catálogo son los tipos de componente, no los tipos de gráfico.

Cuando al usuario le gusta uno, save_widget lo guarda por nombre, y render_dashboard({widgets: ["sales_by_hour_heatmap"]}) lo recupera en una conversación posterior — todavía vinculado al dataset en vivo, así que se actualiza como todo lo demás.

Los datos

data/ticket_sales.csv contiene una fila por pedido de entradas en doce obras de Broadway. Las obras, sus teatros, los aforos, la ocupación semana a semana y los niveles de precios son reales, del dataset Broadway weekly grosses (Playbill, vía TidyTuesday). Los pedidos individuales se han modelado a partir de esas cifras, porque la fuente es semanal y agregada. data/README.md indica exactamente qué partes son cuáles.

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

Apunta eso a un despliegue con --url https://your-worker.workers.dev y mira cómo se mueve el panel mientras lo estás mirando — menos de un segundo después de cada append, porque el servidor se lo indica.

Ejecútalo

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

Luego abre http://localhost:8788/app.html para ver el panel por separado, o http://localhost:8788/ para las instrucciones de conexión.

Instalarlo en Claude

Despliega primero (más abajo): un conector personalizado se alcanza desde la nube de Anthropic, no desde tu máquina, así que localhost no sirve.

Claude Code, directamente desde este repositorio:

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

Eso instala el servidor MCP y el skill juntos. La URL del servidor está en .claude-plugin/plugin.json — si despliegas tu propio Worker, cambia esa única línea y ejecuta /plugin marketplace update mcp-a2ui-vega.

Claude web o de escritorio: Settings → Connectors → Add custom connector, y pega https://your-worker.workers.dev/mcp. No hay OAuth ni clave. Luego añade el skill: comprime la carpeta skills/a2ui-dashboards — la carpeta en sí debe estar en la raíz del zip — y súbela en Settings → Capabilities → Skills.

El skill es opcional en cualquier caso: el servidor envía las instrucciones de uso en su handshake de MCP. Es lo que hace que los seguimientos sean buenos: editar un componente en lugar de redibujarlo todo, y recordar los gráficos que te gustaron.

Luego pide el panel de ventas de entradas.

Despliegue

El Worker es lo único que hay que alojar. GitHub Pages se lleva la demo independiente.

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

Eso crea el namespace de KV si aún no existe, escribe su id en wrangler.toml, empaqueta la app y los datos iniciales, y despliega.

O añade dos secretos del repositorio y haz push a mainel workflow lo hace todo, incluida la creación del namespace, y se salta el despliegue con un aviso en lugar de fallar mientras falten los secretos:

Secret

Qué es

CLOUDFLARE_API_TOKEN

Un token de la plantilla Edit Cloudflare Workers

CLOUDFLARE_ACCOUNT_ID

Tu id de cuenta, desde el panel de Workers

El mismo workflow publica la demo independiente en GitHub Pages en cuanto Pages esté habilitado en Settings → Pages con la fuente GitHub Actions. Hasta entonces, el workflow lo indica en un aviso y sigue en verde.

Pruebas

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

Para ejecutar la misma suite contra un despliegue en lugar de contra un worker local:

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

El relay existe porque un navegador detrás de un proxy restrictivo puede no alcanzar Cloudflare mientras que Node sí puede; cada byte sigue viniendo del despliegue real. Almacena las respuestas en un búfer, así que no transporta el flujo de cambios: una vista detrás de él recurre al polling, algo que también conviene probar.

tools/e2e.mjs maneja tools/harness.html — un host de MCP Apps escrito a mano, de ~120 líneas, que deliberadamente no comparte código con la app, de modo que un error de protocolo no pueda pasar desapercibido en ambos. Comprueba aquello que un comprobador de tipos no puede: que el panel se dibuja, que recomponer colorea una baldosa sin alterar el resto, que las filas añadidas llegan sin pedirlas, que un filtro mueve las métricas y la tabla a la vez, y que un widget guardado vuelve.

tools/push-latency.mjs mide lo que la arquitectura afirma: un panel inactivo no hace ninguna petición, y un cambio le llega en aproximadamente medio segundo con exactamente un fetch.

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

Licencia

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