MCP Fusion/Core concepts/Models y Presenters

Models y Presenters

Pregunta a la IA sobre Vinkius

Declara tu dominio una sola vez con defineModel y moldea lo que el agente percibe con createPresenter: schemas, rules, redacción, bloques de UI, affordances y límites.

Models y Presenters son la M y la V de the MVA pattern. El Model declara tu dominio una sola vez. El Presenter moldea la percepción de ese dominio para el agente. La separación es intencionada: el mismo Model puede tener varios Presenters, uno por público o tarea.

Models

typescript
import { defineModel } from '@mcpfusion/core';

const InvoiceModel = defineModel('Invoice', (m) => {
  m.casts({ amount_cents: 'number' });
  m.hidden(['internal_notes', 'cost_basis']);
  m.guarded(['id', 'created_at']);
  m.fillable({
    create: ['customer_id', 'amount_cents', 'due_date'],
    update: ['status'],
  });
});
  • .casts(): conversiones de tipo aplicadas al leer
  • .hidden(): campos que nunca salen del servidor, ni siquiera en la salida de depuración
  • .guarded(): campos que el agente no puede escribir
  • .fillable(): los únicos campos que cada operación puede escribir

Todo lo que no declares simplemente no existe para el agente. El model compila a un schema de Zod, así que InvoiceModel.schema valida las entradas y typeof InvoiceModel.infer te da el tipo de TypeScript.

Las anotaciones .describe() en los campos se extraen automáticamente y se convierten en reglas del sistema para el agente, de modo que el significado del campo viaja con el campo.

Presenters

typescript
import { createPresenter, t, suggest, ui } from '@mcpfusion/core';

const InvoicePresenter = createPresenter('Invoice')
  .schema({
    id: t.string,
    customer: t.string,
    amount_cents: t.number.describe('CENTS, divide by 100'),
    status: t.enum('draft', 'paid', 'overdue'),
  })
  .rules([
    'CRITICAL: amount_cents is in CENTS. Divide by 100.',
  ])
  .redactPII(['customer.email', 'customer.ssn'])
  .ui((inv) => [
    ui.table(['Field', 'Value'], [
      ['Invoice', inv.id],
      ['Amount', inv.amount_cents / 100],
      ['Status', inv.status],
    ]),
  ])
  .suggest((inv) => [
    inv.status === 'overdue'
      ? suggest('billing.remind', 'Send a payment reminder')
      : null,
  ])
  .limit(50);

Los métodos del builder

MétodoQué hace
.schema()Los campos que existen para el agente, con tipos t y descripciones
.rules()Líneas de prompt de sistema inyectadas en cada respuesta de este Presenter
.redactPII()Rutas de campos eliminadas antes de la serialización, el firewall de salida
.ui()Bloques renderizados como tablas; sus datos omiten la redacción por diseño
.suggest()Affordances: siguientes acciones que el agente puede considerar
.limit()Tope de elementos devueltos, con un mensaje de truncado autorreparable
.embed()Presenters anidados para entidades relacionadas

Las rules son contratos, no comentarios

Las líneas de .rules() se inyectan en el contexto del sistema, así que el modelo no puede ignorarlas como ignora un comentario de código. Son el lugar adecuado para unidades, monedas, estados y todo aquello en lo que el modelo suele equivocarse.

La redacción se ejecuta tarde, a propósito

El motor de DLP compila las rutas de .redactPII() en una función de redacción optimizada que se guarda en caché por Presenter. La redacción se ejecuta después de renderizar los bloques de UI y justo antes de la serialización, de modo que los dashboards conservan los valores reales mientras el contexto del modelo permanece limpio.

Los datos de .ui() omiten la redacción por diseño: una tabla pensada para un operador humano puede mostrar valores reales. Mantén los secretos fuera de los bloques .ui() salvo que un humano sea el único consumidor.

Una entidad, muchos públicos

typescript
const AdminPresenter = createPresenter('Invoice').schema({ /* everything */ });
const SupportPresenter = createPresenter('Invoice')
  .schema({ id: t.string, status: t.enum('draft', 'paid', 'overdue') })
  .limit(10);

La percepción por rol no necesita ningún módulo extra: elige el Presenter por tenant o rol en el middleware, y la misma tool atiende a ambos públicos de forma segura. Consulta Credentials y Governance.

Próximos pasos

  • Tools: adjunta Presenters con .returns()
  • Routing: descubrimiento de tools basado en archivos
  • Testing: verifica lo que el agente recibe