MCP Fusion/Core concepts/Models e Presenters

Models e Presenters

Pergunte à IA sobre a Vinkius

Declare seu domínio uma única vez com defineModel e molde o que o agente percebe com createPresenter: schemas, rules, redação, blocos de UI, affordances e limites.

Models e Presenters são o M e o V de the MVA pattern. O Model declara o seu domínio uma única vez. O Presenter molda a percepção desse domínio para o agente. A separação é proposital: o mesmo Model pode ter vários Presenters, um para cada público ou tarefa.

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(): coerções de tipo aplicadas na leitura
  • .hidden(): campos que nunca saem do servidor, nem mesmo em saídas de depuração
  • .guarded(): campos que o agente não pode escrever
  • .fillable(): os únicos campos que cada operação pode escrever

Tudo o que você não declarar simplesmente não existe para o agente. O model compila para um schema Zod, então InvoiceModel.schema valida as entradas e typeof InvoiceModel.infer fornece o tipo TypeScript.

As anotações .describe() nos campos são extraídas automaticamente e viram regras de sistema para o agente, assim o significado do campo viaja junto com o 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);

Os métodos do builder

MétodoO que faz
.schema()Os campos que existem para o agente, com tipos t e descrições
.rules()Linhas de prompt de sistema injetadas em toda resposta deste Presenter
.redactPII()Caminhos de campos removidos antes da serialização, o firewall de saída
.ui()Blocos renderizados como tabelas; seus dados contornam a redação por design
.suggest()Affordances: próximas ações que o agente pode considerar
.limit()Limite de itens retornados, com uma mensagem de truncamento autorreparável
.embed()Presenters aninhados para entidades relacionadas

Rules são contratos, não comentários

As linhas de .rules() são injetadas no contexto do sistema, então o model não pode ignorá-las como ignora um comentário no código. Elas são o lugar certo para unidades, moedas, status e tudo aquilo em que o model vive errando.

A redação roda tarde, de propósito

O motor de DLP compila os caminhos de .redactPII() em uma função de redação otimizada, armazenada em cache por Presenter. A redação roda depois que os blocos de UI são renderizados e imediatamente antes da serialização, então os dashboards mantêm os valores reais enquanto o contexto do model permanece limpo.

Os dados de .ui() contornam a redação por design: uma tabela destinada a um operador humano pode exibir valores reais. Mantenha segredos fora dos blocos .ui(), a menos que um humano seja o único consumidor.

Uma entidade, vários 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);

A percepção por papel não precisa de módulo extra: escolha o Presenter por tenant ou papel no middleware, e a mesma tool atende os dois públicos com segurança. Veja Credentials e Governance.

Próximos passos

  • Tools: anexe Presenters com .returns()
  • Routing: descoberta de tools baseada em arquivos
  • Testing: verifique o que o agente recebe