MCP UI frente a MCP Apps: diferencias, SDK y ejemplos

MCP UI empezó como un SDK comunitario para interfaces de herramientas interactivas, y MCP Apps es la extensión oficial que estandarizó la idea en enero de 2026. Este artículo pone los dos lado a lado: modelo de entrega, sandboxing, soporte de hosts, paquetes del SDK y código ejecutable para servidores, Views y hosts, además de consejos sobre cuál elegir para un proyecto nuevo.

MCP UI frente a MCP Apps: diferencias, SDK y ejemplos
Cristian Da Conceicao
Fundador de Picasso IA

Pregunta a diez desarrolladores qué separa MCP UI de MCP Apps y oirás diez respuestas distintas. La razón es sencilla: los dos nombres describen un proyecto comunitario y el estándar oficial que surgió de él, y muchas publicaciones los tratan como rivales. Si una de tus herramientas MCP debe mostrar un gráfico, un formulario o un mapa en lugar de un muro de texto, necesitas saber qué paquete instalar, dónde vive el HTML y qué hosts lo van a mostrar de verdad. Esta comparación de MCP UI frente a MCP Apps expone las diferencias, las piezas del SDK de cada lado y código que puedes adaptar hoy.

💡 Respuesta corta: MCP Apps es la extensión oficial de MCP que se lanzó el 26 de enero de 2026. MCP-UI es el proyecto SDK anterior que abrió el camino a la idea, y sus paquetes ahora funcionan con el estándar MCP Apps. Considéralos antecesor y sucesor, no competidores.

Qué es realmente cada uno

MCP UI en términos sencillos

MCP-UI es un SDK para crear componentes de interfaz interactivos para herramientas del Model Context Protocol. Apareció en 2025 y abrió el camino a la idea de que un servidor MCP pudiera responder con una interfaz en vivo en lugar de texto plano. Según la documentación de MCP-UI, el proyecto influyó directamente en la especificación de MCP Apps.

El conjunto de herramientas se divide en dos partes:

  • @mcp-ui/server expone createUIResource, que construye un recurso de UI a partir de una cadena HTML o de una URL externa.
  • @mcp-ui/client expone AppRenderer para renderizar la interfaz de una herramienta y AppFrame para el HTML que ya hayas obtenido.

También existen ayudas para el servidor en Ruby (mcp_ui_server) y en Python (mcp-ui-server), una ventaja real cuando tu servidor MCP no está escrito en TypeScript. En su forma inicial, MCP-UI ofrecía varios tipos de contenido, entre ellos HTML puro, URL externas y Remote DOM, y la interfaz viajaba dentro de la respuesta de la herramienta.

MCP Apps en términos sencillos

MCP Apps es la extensión oficial que permite a una herramienta devolver un componente interactivo, como un panel, un formulario o un flujo de trabajo de varios pasos, renderizado dentro de la conversación en un iframe en sandbox. El anuncio oficial lo llama la primera extensión oficial de MCP y afirma que está lista para producción.

Se apoya en dos primitivas habituales de MCP:

  1. Una herramienta que lleva metadatos de UI en el campo _meta.ui.resourceUri.
  2. Un recurso de UI servido mediante el esquema ui://, que contiene HTML y JavaScript empaquetados.

El SDK vive en un solo paquete de npm, @modelcontextprotocol/ext-apps, con subrutas para los hooks de React, la integración en hosts y el registro en el servidor.

Manos de un desarrollador escribiendo en un equipo portátil delgado que muestra una interfaz de gráfico de barras colorido sobre una mesa de cafetería de madera

Cómo se fusionaron los dos proyectos

Del experimento a la extensión

Los mantenedores propusieron MCP Apps en noviembre de 2025, basándose en el trabajo de MCP-UI y en el SDK de Apps de OpenAI. Dos meses después, el 26 de enero de 2026, la extensión se lanzó. El anuncio es explícito en que MCP-UI continúa como proyecto separado y en que pasar a la extensión oficial es opcional.

Ese detalle importa a quien tenga código antiguo. Nada obliga a reescribir mañana, y los paquetes de MCP-UI ahora apuntan a registerAppTool y registerAppResource del estándar MCP Apps como la forma de conectar herramientas y recursos.

Por qué importaba un estándar

Antes de la fusión, los experimentos de interfaz estaban atados a clientes concretos. Un panel diseñado para un host no podía funcionar en otro sin código específico de cada cliente. Reunir las ideas de MCP-UI y del SDK de Apps en una sola extensión significa que quien crea el servidor escribe una interfaz y cualquier host compatible puede renderizarla.

Para los equipos que distribuyen servidores MCP a muchos clientes, esa es toda la clave: una sola compilación, muchos hosts y un único modelo de seguridad.

Dos colegas dibujando con un rotulador dos rectángulos conectados en una pizarra blanca dentro de una oficina luminosa

Las diferencias que de verdad importan

La tabla comparativa

AspectoMCP-UIMCP Apps
OrigenProyecto de SDK comunitario de 2025Extensión oficial de MCP, propuesta en noviembre de 2025, lanzada el 26 de enero de 2026
FunciónAbrió el camino a la interfaz interactiva sobre MCP y ofrece ayudasEspecificación estándar más un SDK de referencia
Vínculo con la herramientaEl modelo original devuelve la UI dentro de la respuesta de la herramienta_meta.ui.resourceUri apunta a un recurso ui://
Tipo MIMEtext/html;profile=mcp-app cuando se usa con el estándartext/html;profile=mcp-app
Ayudas para el servidorcreateUIResource en @mcp-ui/serverregisterAppTool y registerAppResource en ext-apps/server
Vista y clienteAppRenderer y AppFrame en @mcp-ui/clientClase App, más app-bridge para hosts
LenguajesAyudas para servidor en TypeScript, Ruby y PythonSDK en TypeScript con hooks de React
EstadoContinúa como proyecto separado, migración opcionalDescrito como listo para producción

Lee la tabla como un mapa de capas, no como un marcador. MCP Apps define el contrato, y MCP-UI ofrece ayudas prácticas sobre ese contrato.

Dónde vive el HTML

La diferencia estructural más grande es dónde está la interfaz. En MCP Apps, el servidor guarda la UI bajo un URI ui:// y la herramienta lo señala mediante _meta.ui.resourceUri. El host obtiene ese recurso por separado y lo renderiza cuando le conviene, así que el HTML no se mete en cada respuesta de la herramienta.

Las ventajas prácticas:

  • Plantillas revisables. Un host puede leer la plantilla antes de ejecutarla.
  • Separación limpia. Los resultados de la herramienta siguen siendo datos, y el recurso sigue siendo la interfaz.

Vista aérea de un escritorio de roble con bocetos a lápiz, un equipo portátil con una interfaz de mapa y una tableta con un diseño similar

Seguridad y sandboxing

El código interactivo dentro de un chat es un riesgo, así que el modelo de seguridad es una característica de primer nivel. El anuncio enumera cuatro capas:

  • Aislamiento del iframe en un sandbox con permisos restringidos
  • Plantillas declaradas de antemano que los hosts pueden revisar
  • Mensajería JSON-RPC auditable para cada intercambio entre la interfaz y el host
  • Consentimiento opcional del usuario antes de una llamada a una herramienta iniciada desde la interfaz

En el lado de MCP-UI, AppRenderer recibe una propiedad sandbox que apunta a una página proxy separada, que el ejemplo de la documentación sirve desde su propio puerto. El HTML no confiable nunca comparte página con tu aplicación host.

💡 Consejo: El manejador onOpenLink documentado comprueba que una URL empiece por https:// o http:// antes de llamar a window.open. Copia ese hábito. Una View es una entrada no confiable, así que filtra lo que le pide al host que haga.

Primer plano macro de un terrario de vidrio con pequeños bloques de madera y un candado de latón, como un entorno de pruebas aislado

Hosts que renderizan Views

En el lanzamiento, el anuncio mencionó Claude (web y escritorio), Goose y Visual Studio Code Insiders, con ChatGPT llegando la misma semana. El repositorio ext-apps ahora enumera ChatGPT, Claude, VS Code, Goose, Postman, MCPJam, el inspector de mcp-use y Alpic Playground. JetBrains, AWS, Google DeepMind y Antigravity se nombraron como partes que estudian añadir soporte.

Revisa el estado actual del host de destino antes de prometer una fecha de lanzamiento. Esa lista cambia rápido.

Presentador en una sala de reuniones de paredes de cristal junto a una pantalla que muestra un panel limpio mientras los compañeros observan

Las piezas del SDK con las que vas a trabajar

Dos familias de paquetes hacen el trabajo, y encajan entre sí.

PaqueteFunción
@modelcontextprotocol/ext-appsCrear Views interactivas con la clase App
@modelcontextprotocol/ext-apps/reactHooks de React para Views
@modelcontextprotocol/ext-apps/app-bridgeIntegrar Views en un cliente de chat
@modelcontextprotocol/ext-apps/serverRegistrar herramientas y recursos en tu servidor MCP
@mcp-ui/servercreateUIResource y ayudas para Ruby y Python
@mcp-ui/clientAppRenderer y AppFrame para hosts

Desarrollador visto desde atrás en un escritorio de pie con tres monitores que muestran editores de código en tonos apagados

Lado servidor con ext-apps

Para un servidor MCP, el comando de instalación del repositorio es este:

npm install -S @modelcontextprotocol/ext-apps \
  @modelcontextprotocol/client@^2.0.0 \
  @modelcontextprotocol/server@^2.0.0 \
  @modelcontextprotocol/node@^2.0.0 \
  @modelcontextprotocol/express@^2.0.0 \
  zod@^4.2.0

El paquete del servidor te ofrece dos ayudas, registerAppTool y registerAppResource, además de la constante RESOURCE_MIME_TYPE. Una añade metadatos de UI a una herramienta, y la otra sirve el paquete HTML.

Lado View con la clase App

La View es la página que se ejecuta dentro del iframe. Su clase App se comunica con el host a través de un PostMessageTransport. Creas la aplicación, defines manejadores como ontoolresult y llamas a connect(). A partir de ahí, la View puede llamar a herramientas del servidor con callServerTool y enviar notas al modelo con updateModelContext.

Lado host con AppRenderer

Si construyes tu propio cliente de chat, AppRenderer de @mcp-ui/client es el componente de alto nivel. Necesita un client de MCP, un toolName, una URL de sandbox y el toolInput y los toolResult de la llamada. Los callbacks como onOpenLink y onMessage permiten que el host decida lo que puede hacer una View. AppFrame es la opción de bajo nivel para el HTML que hayas obtenido por tu cuenta.

Ejemplos de código funcionales

Una herramienta que devuelve la hora

Este código de servidor sigue la guía de inicio rápido oficial. Una herramienta llamada get-time está vinculada a un recurso ui://, y el manejador del recurso lee un archivo HTML empaquetado.

import { z } from "zod";
import fs from "node:fs/promises";
import path from "node:path";
import {
  registerAppResource,
  registerAppTool,
  RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";

const DIST_DIR = path.join(process.cwd(), "dist");
const resourceUri = "ui://get-time/mcp-app.html";

registerAppTool(
  server,
  "get-time",
  {
    title: "Get Time",
    description: "Returns the current server time.",
    inputSchema: z.object({}),
    _meta: { ui: { resourceUri } },
  },
  async () => {
    const time = new Date().toISOString();
    return { content: [{ type: "text", text: time }] };
  },
);

registerAppResource(
  server,
  resourceUri,
  resourceUri,
  { mimeType: RESOURCE_MIME_TYPE },
  async () => {
    const html = await fs.readFile(path.join(DIST_DIR, "mcp-app.html"), "utf-8");
    return {
      contents: [{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html }],
    };
  },
);

Fíjate en lo poco que hay: una herramienta, un recurso y un campo de metadatos que los une.

La View que la llama

La View recibe el primer resultado mediante ontoolresult y puede pedir al servidor datos nuevos cuando el usuario hace clic en un botón.

import { App } from "@modelcontextprotocol/ext-apps";

const app = new App({ name: "Get Time App", version: "1.0.0" });
const serverTimeEl = document.getElementById("server-time")!;

const readTime = (result: { content?: Array<{ type: string; text?: string }> }) =>
  result.content?.find((c) => c.type === "text")?.text ?? "[ERROR]";

app.ontoolresult = (result) => {
  serverTimeEl.textContent = readTime(result);
};

document.getElementById("get-time-btn")!.addEventListener("click", async () => {
  const result = await app.callServerTool({ name: "get-time", arguments: {} });
  serverTimeEl.textContent = readTime(result);
});

app.connect();

Tableta y equipo portátil uno al lado del otro sobre una mesa de madera clara mostrando diseños de panel casi idénticos

Empaquetar la UI con createUIResource

Con MCP-UI, createUIResource de @mcp-ui/server construye el objeto de recurso por ti:

import { createUIResource } from "@mcp-ui/server";

const widgetUI = await createUIResource({
  uri: "ui://my-server/widget",
  content: { type: "rawHtml", htmlString: "<h1>Widget</h1>" },
  encoding: "text",
});

El formato de transmisión que produce es un recurso MCP sencillo con el tipo MIME estándar:

{
  type: "resource",
  resource: {
    uri: "ui://my-server/widget",
    mimeType: "text/html;profile=mcp-app",
    text: "<h1>Widget</h1>",
  },
}

Enviar contexto de vuelta al modelo

Una View no es un callejón sin salida. Puede contarle al modelo lo que el usuario acaba de hacer, para que la siguiente respuesta refleje el clic:

await app.updateModelContext({
  content: [{ type: "text", text: "User selected option B" }],
});

Esta sola llamada es lo que convierte un widget estático en parte de la conversación.

Cuál deberías elegir

La respuesta honesta es que la mayoría de los proyectos nuevos deberían partir del estándar MCP Apps y tratar MCP-UI como una caja de herramientas que lo acompaña.

Elige el SDK de MCP Apps cuando:

  • Empiezas un proyecto nuevo en TypeScript y quieres la vía oficial, neutral respecto al host.
  • Quieres que una misma interfaz se renderice en varios hosts, como Claude, VS Code, Goose y ChatGPT.
  • Quieres los hooks de React, o app-bridge para integrar Views en tu propio cliente de chat.
  • Tu herramienta ejecuta trabajos largos. La generación de imágenes y video es asíncrona: una herramienta inicia un trabajo y luego algo consulta hasta que termina. Una View con una barra de progreso y una galería de resultados supera a un registro de texto en todos los casos.

Mantén las ayudas de MCP-UI cuando:

  • Tu servidor está escrito en Ruby o Python y quieres mcp_ui_server o mcp-ui-server.
  • Ya distribuyes salida createUIResource y se renderiza bien en tus hosts.
  • Quieres AppRenderer como renderizador listo para usar dentro de un cliente que controlas.

Una lista breve para migrar:

  1. Añade _meta.ui.resourceUri a cada herramienta que tenga interfaz.
  2. Sirve el HTML desde un recurso ui:// con el tipo MIME text/html;profile=mcp-app.
  3. Sustituye las cargas de UI incrustadas en las respuestas de las herramientas por punteros a recursos.
  4. Pasa la lógica de la View a la clase App y lee los resultados en ontoolresult.
  5. Prueba en al menos dos hosts antes de publicar.

Vista aérea de un sendero de senderismo que se divide en dos a través de un bosque otoñal de abedules con un excursionista solitario en la bifurcación

Cómo usar Sonnet 5 en PicassoIA

Las Views son sobre todo HTML, CSS y una capa fina de TypeScript, que es exactamente el trabajo en el que un modelo de programación destaca. Claude Sonnet 5 en PicassoIA está pensado para tareas de programación de varios pasos y uso de herramientas, lee capturas de pantalla y bocetos, y puede redactar una primera versión de un servidor, una View o un envoltorio para host a partir de una petición sencilla.

  1. Abre la página del modelo. Ve a la página de Claude Sonnet 5 en PicassoIA.
  2. Rellena el campo obligatorio. prompt es el único parámetro obligatorio. Prueba con: "Escribe una herramienta MCP en TypeScript llamada show-chart que registre un recurso ui://, y una View que use la clase App para renderizar un gráfico de barras a partir del resultado de la herramienta."
  3. Fija el nivel de esfuerzo. El valor por defecto es low, que desactiva el razonamiento para obtener la respuesta más rápida. Súbelo a high o max cuando la tarea afecte a varios archivos, como un servidor, una View y un paso de compilación juntos.
  4. Añade un prompt de sistema. Fija un rol una vez, por ejemplo: "Escribes código de MCP Apps con @modelcontextprotocol/ext-apps y nunca incrustas secretos en el HTML." Se aplica a lo largo de toda la sesión.
  5. Adjunta una imagen si tienes una. El parámetro opcional image acepta un boceto o una captura de pantalla, escalada con max_image_resolution para ahorrar tiempo y dinero.
  6. Genera y revisa. La salida puede llegar hasta 8.192 tokens por defecto. Copia el código y pruébalo en un host.
ParámetroObligatorioPor defectoPara qué sirve
promptSíNingunoLa petición en sí
effortNolowCuánto piensa el modelo antes de responder
max_tokensNo8192Limitar la longitud de la salida
system_promptNoVacíoRol y estilo de programación
imageNoNingunoUn boceto o una captura de pantalla como contexto
max_image_resolutionNo0,5 megapíxelesReducir la imagen antes de enviarla

💡 Consejo: Pega los fragmentos de este artículo en tu prompt como referencia. Así el modelo usa los nombres reales de la API en lugar de adivinarlos.

Mujer en un escritorio de estudio revisando una hoja de contactos impresa con una lupa junto a un equipo portátil que muestra una cuadrícula de galería de imágenes

Crea tus propias imágenes hoy

Cada MCP App acaba necesitando imágenes: una imagen principal para una página de inicio, fotos de producto para una galería en una View, un clip corto para una demo. PicassoIA reúne en un solo lugar los modelos para todo eso, así que puedes probar ideas antes de conectar nada a un servidor.

  • Empieza con imágenes fijas de Seedream 5 Pro, y dale al prompt una lente, una dirección de luz y una textura para obtener un resultado fotográfico.
  • Convierte la mejor imagen en movimiento con Seedance 2.0, que combina video con audio integrado.
  • Sigue avanzando en el código con Claude Sonnet 5, siguiendo los pasos de arriba.

Elige un prompt, genera una imagen y ve hasta dónde llega una sola idea. Luego abre la colección de modelos de PicassoIA y prueba un segundo modelo con el mismo prompt. La comparación por sí sola te enseñará qué hace mejor cada uno.

Compartir este artículo

Elige tu idioma