MCP Fusion/Core concepts/Tools

Tools

Pergunte à IA sobre a Vinkius

Defina AI Capabilities com f.query, f.mutation e f.action: parâmetros tipados, middleware, a monad Result e FSM state gating que remove tools que o agente não pode usar.

Tools são aquilo que o agente chama. Em termos do Vinkius, são as AI Capabilities do seu conector. O MCP Fusion lhe dá um builder fluente com três pontos de entrada semânticos, e a semântica mapeia para as anotações MCP que o agente vê.

BuilderSignificadoAnotação MCP
f.query()Lê dadosreadOnlyHint: true
f.mutation()Escreve dadosDicas destrutivas por tool
f.action()Efeitos colaterais, chamadas externasDicas destrutivas por tool

Uma tool completa

typescript
export default f.mutation('billing.refund')
  .describe('Refund an invoice by ID')
  .withString('id', 'Invoice ID')
  .withNumber('amount_cents', 'Amount to refund in CENTS')
  .withOptionalEnum('reason', ['duplicate', 'customer_request', 'fraud'],
    'Why the refund is happening')
  .returns(InvoicePresenter)
  .use(requireAuth)
  .handle(async (input, ctx) => {
    const result = await refunds.create(input, ctx.tenantId);
    if (!result.ok) return result.response;
    return result.value;
  });

Parâmetros

  • .withString(name, description), .withNumber, .withBoolean, .withEnum e as variantes .withOptional constroem o schema de entrada Zod
  • Tools guiadas por model podem usar .fromModel() e reutilizar os campos fillable de um Model como parâmetros
  • .toonDescription() comprime a descrição da tool em um formato de pipe que custa cerca de metade dos tokens
  • .bindState('approved', 'DISCHARGE') conecta a tool a um estado de FSM, coberto abaixo

Middleware

.use() anexa middleware a uma tool. O middleware compõe ao estilo Express e cada middleware retorna um contexto parcial que é mesclado em ctx, e é assim que auth, resolução de tenant e rate limiting ficam fora dos seus handlers:

typescript
// A middleware derives context: the returned object merges into ctx,
// typed through the whole fluent chain.
const withUser = f.middleware(async (ctx) => {
  const user = await auth.verify(ctx.request);
  return { user };
});

f.query('billing.get_profile').use(withUser);

Veja Routing para o middleware global aplicado a toda tool de um diretório.

A monad Result

Handlers que podem falhar retornam um Result em vez de lançar exceções, e o framework transforma um Failure em uma resposta de tool estruturada com a qual o agente pode agir:

typescript
import { succeed, fail, toolError } from '@mcpfusion/core';

.handle(async (input) => {
  const invoice = await db.invoices.findUnique({ where: { id: input.id } });
  if (!invoice) {
    return fail(toolError('NOT_FOUND', {
      message: 'No invoice with that ID',
      availableActions: ['billing.list_invoices'],
    }));
  }
  return succeed(invoice);
});

A lista availableActions é contexto autorreparável: quando o agente escolheu um ID errado, o erro ensina o que ele pode fazer em vez disso. Veja Governance para saber como a mesma ideia funciona em mudanças de contrato.

FSM state gating

Algumas tools não devem existir em certos estados. Uma tool de discharge não tem razão de aparecer antes de uma fatura ser aprovada. .bindState() conecta a tool a um estado de fluxo de trabalho e o MCP Fusion a remove fisicamente do tools/list enquanto o estado a proíbe:

typescript
export default f.action('billing.discharge')
  .describe('Discharge an approved invoice')
  .bindState('approved', 'DISCHARGE')
  .handle(async (input, ctx) => { /* ... */ });

O cliente recebe notifications/tools/list_changed conforme o estado muda, então o menu do agente corresponde à realidade. Isso elimina a clássica alucinação em que o model chama um passo fora de ordem. O state store é plugável, com opções de Redis e edge KV, então o gating funciona em serverless também.

O state gating remove a tool, não a esconde. O agente nunca vê uma tool que não pode chamar, então nunca tenta e nunca queima um turno com uma rejeição.

Próximos passos