WU / DOCSUNIVERSAL MICROFRONTENDS
ES

Acciones IA y MCP ejecutables

Registra y ejecuta acciones WU sin proveedor; conecta un relay MCP real y comprueba schema, permisos, autenticación, cancelación y limpieza.

Una acción no necesita un proveedor LLM

wu.ai.execute invoca un handler registrado. Puedes usarlo desde una interfaz propia, un agente externo o una prueba sin configurar provider, hacer prompts ni introducir una API key. Los proveedores son necesarios para operaciones que conversan con modelos; el registro y la ejecución directa de acciones funcionan por separado.

La receta examples/ai/local-actions.mjs ejecuta una suma real y comprueba rechazos antes de que el handler realice su cálculo.

Descarga el proyecto de recetas, extrae el ZIP y ejecuta npm install para obtener las dependencias. Incluye las mismas acciones utilizadas por los ejemplos Node y MCP, junto con sus pruebas.

node examples/ai/local-actions.mjs
node scripts/verify-server-examples.mjs

Registrar, habilitar y ejecutar

import wu from 'wu-framework';

const ai = await wu.aiReady();
ai.init({ permissions: {
  executeActions: true,
  readStore: false,
  writeStore: false,
  emitEvents: false,
  readDOM: false,
  modifyDOM: false,
  readDiagnostics: false,
  navigate: false,
  network: false,
} });

ai.action('sum_local', {
  description: 'Suma dos números sin efectos externos',
  parameters: {
    type: 'object',
    properties: { a: { type: 'number' }, b: { type: 'number' } },
    required: ['a', 'b'],
  },
  handler({ a, b }) {
    if (!Number.isFinite(a) || !Number.isFinite(b) || !Number.isFinite(a + b)) {
      throw new Error('Se requieren números y resultado finitos');
    }
    return { sum: a + b };
  },
});

const outcome = await ai.execute('sum_local', { a: 2, b: 3 });
// { success: true, result: { sum: 5 } }

Espera aiReady() antes de operaciones que devuelven datos. action devuelve el objeto IA para encadenar registros. execute devuelve una promesa con { success, result? , reason? }; un fallo de permiso o validación normalmente se representa con success: false, no lanzando una excepción al caller.

ai.tools() expone schemas del catálogo para clientes externos. Que una herramienta aparezca en esa lista no concede permiso para ejecutarla.

Schema, permiso y reglas de dominio

La validación de parámetros de WU es deliberadamente pequeña: comprueba campos requeridos, tipos de propiedades de primer nivel —incluido integer— y enum. No es un validador completo de JSON Schema. Reglas como límites numéricos, additionalProperties, formatos y validación recursiva requieren validación del producto antes del efecto.

La receta prueba un campo ausente, un string donde se esperaba un número y un valor no finito. El primer y segundo caso los rechaza WU; el tercero lo rechaza el handler con una regla explícita. Un contador demuestra que sólo el caso permitido llegó al cálculo.

ai.permissions.configure({ executeActions: false });
const result = await ai.execute('sum_local', { a: 2, b: 3 });
// { success: false, reason: 'Permission denied: executeActions' }

Una acción puede declarar permissions: ['readStore'] o permissionsWhen(params). Los flags requeridos se comprueban antes de la validación y del handler. La API suministrada como segundo argumento sólo ofrece las operaciones declaradas y habilitadas, por ejemplo getState, setState, emit o fetch.

Mantén separados estos controles:

Control Decide
Capabilities de la app WU Acceso técnico a store, eventos y RPC a través de su facade
Flags IA Si el subsistema puede ejecutar acciones, leer DOM, escribir estado o usar red
Autorización de dominio Qué operación de negocio permite el servidor al actor autenticado
Capacidad del ejecutor Si el backend o runner implementa cancelación, transacción u otra operación

Los handlers son código confiable del host. Una closure puede acceder a objetos globales fuera de la API suministrada; el registro no es un sandbox para JavaScript hostil. Para acciones con efectos de backend, usa un servicio que revalide identidad, schema, scope y autorización. Estas recetas mantienen cálculos puros y no acceden a drivers privilegiados.

Confirmación y cleanup

const stop = wu.on('ai:tool:confirm', event => {
  // La receta de rechazo no concede ninguna aprobación.
  ai.rejectTool(event.data.callId);
});

try {
  const result = await ai.execute('sum_with_confirmation', { a: 2, b: 3 });
  // success: false; reason: 'User denied action'
} finally {
  stop();
  ai.destroy();
  await wu.destroy();
}

La acción sum_with_confirmation está registrada en examples/ai/register-actions.mjs con confirm: true. Una UI que obtenga una decisión afirmativa usa confirmTool(callId); rejectTool resuelve la denegación. Sin decisión, la confirmación vence a los 30 segundos y deniega.

Resuelve o rechaza las confirmaciones pendientes antes de destruir el subsistema y elimina las suscripciones que instaló tu integración. destroy limpia recursos de IA; no cancela arbitrariamente promesas o efectos capturados por handlers propios. Tampoco convierte el historial en memoria en una auditoría durable.

MCP: del cliente al navegador vivo

El servidor MCP del paquete es un relay. El cliente habla MCP/JSON-RPC por stdio; el relay envía comandos por WebSocket al bridge de una página que tiene WU cargado. La acción se ejecuta en esa página, con sus permisos IA.

Cliente MCP → stdio → wu-mcp-server → WebSocket → wu.mcp → wu.ai.execute

Ejecuta la receta completa:

node examples/mcp/local-relay.mjs
node scripts/verify-server-examples.mjs --mcp

La receta inicia el servidor empaquetado mediante el export wu-framework/mcp-server, sirve el bundle UMD instalado desde un listener local y abre Chromium headless. En Windows usa Edge; en otros sistemas utiliza Chromium de Playwright. Si falta el navegador de Playwright, instala sus binarios con npx playwright install chromium. Puedes elegir un canal instalado mediante WU_BROWSER_CHANNEL.

No necesita un cliente MCP externo instalado: examples/mcp/stdio-client.mjs implementa únicamente las operaciones JSON-RPC necesarias para inicializar, listar herramientas, invocar y cancelar una espera. Para una integración general utiliza un cliente MCP que gestione el protocolo completo.

Conectar tu propio cliente

El paquete instala el ejecutable wu-mcp-server. Configura su entorno desde el host que lanza ese proceso. No pongas el token en una URL ni lo publiques en código del frontend.

Variable Comportamiento
WU_MCP_TOKEN Obligatorio salvo opt-in inseguro; entre 16 y 4096 bytes
WU_MCP_HOST 127.0.0.1 por defecto
WU_MCP_PORT 19100; admite 1–65535
WU_MCP_ORIGINS Origins HTTP(S) exactos separados por comas; sin rutas
WU_MCP_TIMEOUT Espera de respuesta del bridge: 30000 ms por defecto, rango 50–300000
WU_MCP_AUTH_TIMEOUT Espera de autenticación: 5000 ms por defecto, rango 50–60000
WU_MCP_MAX_PAYLOAD 1048576 bytes por defecto, rango 1024–16777216
WU_MCP_INSECURE Sólo 1 permite omitir token; la receta mantiene autenticación obligatoria

Sin WU_MCP_ORIGINS, se aceptan páginas HTTP(S) de loopback; un cliente WebSocket sin Origin no pasa esa comprobación. La receta restringe el relay al origin exacto del servidor que acaba de crear.

En la página, una integración confiable entrega el token efímero al bridge:

await wu.mcp.connect(relayUrl, { token: sessionToken });

La promesa carga el módulo y comienza la conexión; no garantiza que el handshake ya haya terminado. Comprueba wu.mcp.isConnected() y consulta wu_conexion desde el cliente MCP para observar ambos extremos. El relay admite un bridge autenticado activo a la vez.

Herramientas y lectura de resultados

Herramienta Argumentos principales
wu_conexion {}; estado del relay aunque no haya página conectada
wu_list_actions {}; catálogo de acciones de la página
wu_execute_action { action, params? }
wu_get_state { path? }; requiere readStore
wu_set_state { path, value }; requiere writeStore
wu_emit_event { event, data? }; rechaza namespaces wu:, system: y app:

El relay también registra herramientas de estado de WU, apps, eventos, navegación, DOM, diagnóstico y montaje. tools/list devuelve el catálogo exacto de la versión instalada. Sus permisos continúan aplicándose dentro de la página.

Hay dos niveles de resultado: el sobre MCP y el resultado de la acción. Una acción denegada puede viajar en un sobre isError: false y contener success: false en el JSON de content[0].text. Comprueba ambos:

const response = await client.callTool('wu_execute_action', {
  action: 'sum_local', params: { a: 2, b: 3 },
});
if (response.isError) throw new Error(response.content[0].text);
const outcome = JSON.parse(response.content[0].text);
if (!outcome.success) throw new Error(outcome.reason);
console.log(outcome.result);

Ese fragmento utiliza el cliente mínimo de la receta. La firma de callTool de otro SDK puede ser diferente.

Cancelación que puedes observar

La receta envía notifications/cancelled cuando cancela la espera de un request MCP. Comprueba después que el handler bounded_sum, ya iniciado en el navegador, termina su demora fija y su cálculo. El relay no transmite un AbortSignal a wu.ai.execute.

Por tanto, cancelar una espera no demuestra que el trabajo se haya detenido. Para operaciones largas con efectos, diseña un servicio con identificador de operación, autorización de status/cancel y cancelación cooperativa del ejecutor. WASM/WASI puede alojar lógica portable, pero el host sigue necesitando implementar esos contratos y el transporte de red. El servicio conectado con WU muestra un caso diferente: conecta el signal RPC con la terminación efectiva de su Worker.

Al terminar, llama wu.mcp.disconnect() para detener reconexiones y liberar sus interceptores. La prueba comprueba que fetch y console.log recuperan sus referencias previas, que el relay ya no ve una app conectada y que se cierran los procesos creados. Consulta extensiones e IA y seguridad para los límites del runtime.

WU SE CONSTRUYE CONTIGO

¿Encontraste un bug? ¿Tienes una idea?

Tu experiencia mejora WU. Cuéntanos qué falla o ayuda a sostener su desarrollo.