MCP Apps permite que una tool devuelva una interfaz interactiva dentro del chat. Es útil para aprobar, explorar y decidir; no para saltarse permisos ni convertir el agente en una web embebida sin controles.
MCP Apps es una extensión de Model Context Protocol para que un servidor devuelva una interfaz interactiva —un dashboard, formulario, tabla o flujo de aprobación— dentro de un host de chat compatible. La UI vive en un iframe sandboxed y habla con el host mediante mensajes controlados; no obtiene acceso directo al DOM, cookies o almacenamiento del host.
TL;DR
La keyword principal es
MCP Apps. La intención es práctica: entender cuándo una tool necesita UI, cómo conectar la vista con un servidor MCP y qué límites de seguridad son imprescindibles antes de ponerla delante de usuarios o datos reales.Mi postura: una UI MCP tiene sentido cuando reduce ambigüedad humana, no cuando maquilla una tool demasiado poderosa. Un formulario de aprobación, una tabla filtrable o un explorador de resultados puede evitar decenas de turnos. Una mini-aplicación con acceso libre a red y tools de escritura solo multiplica superficie de ataque.
Qué es una MCP App y qué no es
Un servidor MCP normal expone tools, resources y prompts. La respuesta de una tool suele ser texto y, opcionalmente,
structuredContent. Una MCP App añade una resource de UI, normalmente identificada conui://, que el host puede renderizar junto al resultado. La vista recibe datos del resultado y puede pedir acciones al host por un puente de mensajes.No es una nueva forma de hacer una SPA pública. La conversación sigue siendo el contexto principal; la interfaz es una mejora progresiva para la parte que una lista de texto resuelve mal. Si el host no soporta MCP Apps, la tool debe seguir devolviendo una respuesta textual útil. Ese fallback no es un detalle: es el contrato de portabilidad.
Tampoco es una autorización implícita. Que la vista muestre un botón no significa que pueda ejecutar una operación. El servidor debe validar usuario, tenant, argumentos y política igual que lo haría si la llamada viniera de un cliente HTTP ordinario.
La UI no se conecta libremente al host: recibe contexto y solicita acciones a través de un bridge; el host sigue decidiendo qué capacidades permite.
La arquitectura: servidor, host y vista
Hay tres piezas. El servidor MCP registra una tool y una resource HTML. El host descubre ambas, ejecuta la tool y, si soporta la extensión, monta la resource en un iframe aislado. La vista es un cliente pequeño: se inicializa, recibe input y resultado de la tool, y puede solicitar
tools/call, recursos o acciones del host según sus capacidades.La separación entre
contentystructuredContentimporta.contentes la explicación que puede necesitar el modelo y sirve como fallback textual.structuredContentes un objeto pensado para renderizar: IDs, series de datos, estados y filas. No metas en el contexto del modelo 3.000 filas que solo necesita pintar una tabla; entrega una síntesis textual y datos estructurados a la UI.El host es la frontera de confianza. Puede restringir llamadas, enlaces externos, modo de visualización y capacidades de la app. Diseña la vista asumiendo que no tiene permiso para todo y que una petición puede ser rechazada; es una propiedad sana, no una limitación incómoda.
¿Te está sirviendo? Hay una dosis cada semana
Te resumo herramientas de IA para devs, agentes, MCP, seguridad y workflows en un email de 5 minutos. En español y sin ruido.
Cuándo una tool necesita UI
Usaría MCP Apps para explorar datos con filtros, comparar opciones, revisar un diff, rellenar un formulario de aprobación, visualizar un pipeline o confirmar una acción con consecuencias. En todos esos casos hay estado visual, selección humana o demasiada información para que el modelo la resuma sin perder control.
No la usaría para una búsqueda de documentación, una consulta determinista, una acción de una línea o un workflow que nadie necesita inspeccionar. Una respuesta textual o structuredContent basta y es más simple de probar. La UI también introduce lifecycle, accesibilidad, CSP, degradación y una matriz de hosts; no la añadas solo porque es nueva.
La pregunta de producto es concreta: ¿qué decisión humana mejora al ver y manipular este resultado? Si no puedes responderla, conserva la tool como texto. Si la respuesta es revisar, seleccionar o aprobar, una UI embebida puede reducir errores y turnos innecesarios.
server.ts — tool con fallback textual y datos para la vista
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
const server = new McpServer({ name: "release-dashboard", version: "1.0.0" });
server.registerResource(
"release-view",
"ui://release-dashboard/view.html",
{},
async () => ({
contents: [{
uri: "ui://release-dashboard/view.html",
mimeType: "text/html;profile=mcp-app",
text: await loadBundledHtml()
}]
})
);
server.registerTool(
"list_release_risks",
{
title: "Riesgos de despliegue",
inputSchema: { service: "string" },
_meta: { ui: { resourceUri: "ui://release-dashboard/view.html" } }
},
async ({ service }, extra) => {
const user = await requireAuthorizedUser(extra);
const risks = await readRisksForTenant(user.tenantId, service);
return {
content: [{ type: "text", text: `Hay ${risks.length} riesgos abiertos para ${service}.` }],
structuredContent: { service, risks: risks.map(toSafeViewModel) }
};
}
);
El ejemplo deja dos decisiones visibles. La resource no se inventa una URL web: usa un URI ui:// registrado. Y la tool comprueba identidad y tenant antes de leer datos; structuredContent solo contiene el modelo de vista seguro. El paquete @modelcontextprotocol/ext-apps ofrece helpers para registrar tools/resources y construir la vista, pero no sustituye esas validaciones.
La vista: trata el iframe como un cliente no confiable
La vista debe inicializarse con el bridge, esperar los eventos del host y renderizar solo datos validados. Su trabajo es presentar y recoger intención del usuario, no decidir permisos. Cuando el usuario pulsa aprobar, la vista llama a una tool estrecha con un ID; el servidor vuelve a comprobar que la persona puede aprobar ese recurso y que el estado sigue siendo válido.
Evita pasar secretos, tokens de larga vida o documentos completos en el HTML de la resource. El iframe aislado reduce privilegios, pero no convierte datos sensibles en inocuos. Envía el mínimo necesario, aplica redacción por tenant y considera que cualquier dato mostrado puede ser copiado por el usuario autorizado.
Para acciones de escritura, modela una transición explícita: preview → confirm → execute. La UI puede enseñar el impacto y pedir confirmación; el servidor debe usar un idempotency key y rechazar operaciones repetidas o estados caducados. Es el mismo patrón que usarías en una API de pagos, solo que aquí el disparador nació dentro de un chat.
CSP, red y enlaces: el límite que suele olvidarse
Una MCP App declara sus necesidades de red y el host puede aplicar esa política. Empieza con una CSP restrictiva: sin conexiones externas si no son necesarias; dominios concretos para API o assets; nada de comodines por comodidad. Si la app necesita datos, es preferible que los pida mediante una tool auditada antes que abrir
connect-src \*.No dejes que HTML o markdown procedente de tickets, documentos o usuarios llegue a la vista como markup confiable. Sanitiza, usa
textContentpara texto, limita URLs y evita inyectar plantillas dinámicas. Prompt injection no desaparece por mover el resultado a una UI: el contenido externo puede seguir intentando influir en el humano o en llamadas posteriores.Abrir un enlace externo debe ser una capacidad explícita del host, no un efecto lateral de renderizar una celda de tabla. Enseña dominio y destino cuando una acción saque al usuario de la conversación. La fricción pequeña es preferible a una redirección silenciosa desde un panel que parece interno.
Compatibilidad progresiva y testing
El soporte de MCP Apps varía entre hosts y puede cambiar. Por eso prueba dos salidas: una sesión con UI y otra con solo texto. El contenido textual debe explicar resultado, límites y siguiente acción sin depender de la interfaz. Si el host no renderiza la vista, la tool no puede convertirse en un callejón sin salida.
Automatiza tests de contrato en el servidor: schema de entrada, autorización, filtrado por tenant, modelo de
structuredContent, errores y doble ejecución. En la vista, prueba que una respuesta parcial, vacía o denegada no bloquee el chat. Y ensaya manualmente la interacción con los hosts que de verdad vas a soportar; no declares compatibilidad por haber visto un ejemplo funcionar en local.
Mide utilidad, no solo clicks: cuántos turnos evita la UI, cuántas aprobaciones se revierten, qué operaciones se cancelan, cuánto tarda en aparecer el resultado y cuántas veces se usa el fallback textual. Si no reduce error o tiempo de decisión, una respuesta bien diseñada probablemente era mejor.
Checklist de producción
- La tool devuelve una respuesta textual completa aunque el host no soporte UI.
- La resource usa un URI
ui://registrado y MIME type específico para MCP Apps. - La vista recibe
structuredContentmínimo y no secretos ni datos de otros tenants. - Cada tool de lectura o escritura revalida usuario, tenant, scopes y estado en servidor.
- Las acciones mutantes tienen preview, confirmación, idempotencia y auditoría.
- La CSP declara solo dominios imprescindibles; sin comodines ni scripts remotos no revisados.
- La UI trata todo contenido externo como datos y lo sanitiza antes de mostrarlo.
- Se prueba el fallback textual y la degradación en cada host objetivo.
- Logs guardan IDs, acción, resultado y denegaciones; no el contenido sensible por defecto.
Conclusión
MCP Apps resuelve una carencia real: hay decisiones que una conversación textual explica mal. El valor no es poner un dashboard bonito dentro de un chat; es dar una superficie de revisión pequeña, contextual y reversible a una tool que ya tiene un contrato claro.
Empezaría con una sola tool de lectura y una vista que haga una cosa excelente: filtrar incidencias, revisar resultados o comparar un plan. Mantén fallback textual, CSP corta, datos mínimos y calls de escritura separadas. Cuando eso sea operable, amplía. En agentes, cada pixel interactivo también es una superficie de permiso.
Preguntas frecuentes
¿Qué es MCP Apps?
Es una extensión de Model Context Protocol que permite a un servidor MCP entregar una interfaz interactiva dentro de un host compatible, además del contenido textual y estructurado normal de una tool.
¿Una MCP App funciona en todos los clientes?
No. El soporte depende del host. Por eso una tool debe seguir ofreciendo un fallback textual útil cuando la interfaz no se pueda renderizar.
¿La UI de MCP Apps puede acceder al DOM o las cookies del host?
No debería. La arquitectura usa un iframe sandboxed y comunicación mediante un bridge de mensajes; el host conserva el control de capacidades.
¿Cuándo usar MCP Apps en lugar de una respuesta de texto?
Cuando el usuario necesita explorar datos, seleccionar opciones, revisar un artefacto o aprobar una acción. Para consultas simples, texto o structuredContent suele ser más robusto.
¿Cómo protejo una MCP App?
Valida autorización en el servidor para cada tool, limita structuredContent, aplica CSP restrictiva, sanitiza datos externos, exige confirmación para escrituras y registra acciones sin guardar secretos por defecto.
¿Puedo reutilizar una web existente como MCP App?
Sí, si adaptas la vista al lifecycle y al bridge del host, declaras recursos y CSP, y conservas una salida textual. No presupongas que una SPA existente funciona segura dentro de un iframe MCP sin cambios.
Cómo crear una primera MCP App segura para una tool existente
- Elegir una decisión visual. Selecciona una tool de lectura donde filtrar, comparar o aprobar aporte más que texto.
- Definir fallback. Escribe primero el content textual completo que recibirá un host sin soporte de UI.
- Registrar resource. Publica una resource ui:// con HTML empaquetado y MIME type de MCP App.
- Devolver datos mínimos. Añade structuredContent con un view model seguro, sin secretos ni campos de otros tenants.
- Construir la vista. Inicializa el bridge, renderiza estados de carga y trata respuestas denegadas o parciales como normales.
- Añadir llamada estrecha. Si hay interacción, llama a una tool con IDs y valida usuario, tenant, scopes y estado en servidor.
- Cerrar CSP. Declara solo redes y capacidades imprescindibles; usa herramientas MCP antes que conexiones libres desde el iframe.
- Probar degradación. Ejecuta los tests de contrato y comprueba la salida textual en hosts sin UI antes de anunciar soporte. > ### Criterio técnico > > Un buen chunk en tiempo real no es el más corto ni el más semántico: es el que conserva evidencia, tiempo y estado suficiente para responder sin inventar continuidad.
Fuentes y referencias
- MCP Apps: overview
- MCP Apps: build guide
- MCP Apps: quickstart
- MCP Apps: security model
- MCP Apps: authorization
- MCP Apps SDK and examples
- MCP security best practices
También te puede interesar
- MCP en producción: seguridad, permisos y supply chain
- MCP outputSchema y structuredContent para agentes
- Playwright MCP para testing de UI
- Prompt injection en agentes de IA
- OpenAI Agents SDK: MCP, guardrails y tracing
Recibe una lectura semanal de herramientas IA para devs
Cada semana te resumo herramientas de IA para devs, agentes, MCP, seguridad y workflows en un email de 5 minutos. En español y sin ruido.

Top comments (0)