MCP Fusion/Core concepts/Tools

Tools

Demandez à l’IA à propos de Vinkius

Définissez des AI Capabilities avec f.query, f.mutation et f.action : paramètres typés, middleware, la monade Result et le FSM state gating qui retire les tools que l’agent ne peut pas utiliser.

Les tools sont ce que l’agent appelle. En termes Vinkius, ce sont les AI Capabilities de votre connecteur. MCP Fusion vous donne un builder fluide avec trois points d’entrée sémantiques, et la sémantique correspond aux annotations MCP que l’agent voit.

BuilderSignificationAnnotation MCP
f.query()Lit des donnéesreadOnlyHint: true
f.mutation()Écrit des donnéesHints destructifs par tool
f.action()Effets de bord, appels externesHints destructifs par tool

Une tool complète

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;
  });

Paramètres

  • .withString(name, description), .withNumber, .withBoolean, .withEnum et les variantes .withOptional construisent le schema d’entrée Zod
  • Les tools pilotées par un model peuvent prendre .fromModel() et réutiliser les champs fillable d’un Model comme paramètres
  • .toonDescription() compresse la description de la tool en un format pipe qui coûte environ deux fois moins de tokens
  • .bindState('approved', 'DISCHARGE') relie la tool à un état FSM, présenté plus bas

Middleware

.use() attache un middleware à une tool. Les middlewares se composent à la manière d’Express et chaque middleware renvoie un contexte partiel fusionné dans ctx, ce qui maintient l’auth, la résolution de tenant et le rate limiting hors de vos 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);

Voir Routing pour le middleware global appliqué à chaque tool d’un répertoire.

La monade Result

Les handlers qui peuvent échouer renvoient un Result au lieu de lever une exception, et le framework transforme un Failure en réponse de tool structurée sur laquelle l’agent peut 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);
});

La liste availableActions est un contexte auto-réparant : quand l’agent a choisi un mauvais ID, l’erreur lui apprend ce qu’il peut faire à la place. Voir Governance pour la façon dont la même idée fonctionne lors des changements de contrat.

FSM state gating

Certaines tools ne doivent pas exister dans certains états. Une tool de discharge n’a rien à faire visible avant qu’une facture soit approuvée. .bindState() relie la tool à un état de workflow et MCP Fusion la retire physiquement de tools/list tant que l’état l’interdit :

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

Le client reçoit notifications/tools/list_changed à mesure que l’état évolue, donc le menu de l’agent reflète la réalité. Cela élimine l’hallucination classique où le model appelle une étape hors séquence. Le state store est enfichable, avec des options Redis et edge KV, donc le gating fonctionne aussi en serverless.

Le state gating retire la tool, il ne la cache pas. L’agent ne voit jamais une tool qu’il ne peut pas appeler, donc il n’essaie jamais et ne gaspille jamais un tour sur un refus.

Prochaines étapes

  • Routing : organisez les tools par fichier, regroupez plusieurs actions en une tool
  • Models and Presenters : façonnez ce que chaque tool renvoie
  • Testing : testez le pipeline complet en mémoire