Site
Tous les articles

Publié 17 sept. 20264 min de lecture

MCP Fusion 5.0.10 : des descriptions plus courtes, des erreurs lancées récupérées

Publiée le 17 septembre 2026. Deux corrections P2 dans @mcpfusion/core visant les surfaces exactes que le modèle touche : des descriptions groupées qui reprenaient le résumé de l'outil une fois par action et sous-déclaraient les champs requis, et des réponses classées lancées qui étaient aplaties en un INTERNAL_ERROR générique.

Renato Marinho

Par Renato Marinho

Founder · Vinkius

MCP Fusion 5.0.10 tool-boundary fixes: grouped descriptions that no longer echo the tool summary per action, and thrown classified responses recovered instead of flattened into a generic INTERNAL_ERROR

Publiée le 17 septembre 2026, la 5.0.10 est un release de maintenance, et tout le code qui a changé vit dans @mcpfusion/core ; les notes de version confirment que les quinze autres packages du workspace buildent toujours sans rien toucher (notes de version · MCP Fusion sur GitHub). Deux défauts P2 et une chute latente composent le release. Les trois comptent, et les trois ne s'observent que depuis l'endroit où se tient le modèle de langage.

Bug 152 : le résumé, dit 1 + N fois

Sous toolExposition: 'grouped', un outil expose un nom unique avec un champ discriminant action plutôt que N outils à plat, et sa description est empilée. La couche 1 ouvre avec le résumé de l'outil, la liste module/action et l'instruction de dispatch ; la couche 2 porte une ligne par action : le bloc Workflow: en markdown, la colonne desc: en TOON. Quand un builder définit un .description() mais que ses actions individuelles n'en ont pas, le résumé de l'outil est hérité par chaque action (juste, l'exposition à plat s'appuie sur ce repli), et il était alors ré-échoé une fois par action dans la couche 2. Le modèle voyait le résumé 1 + N fois, sans la moindre information nouvelle après la première. Une description redondante ne fait pas que gonfler le prompt ; elle dilue précisément le signal que le modèle est censé pondérer. La correction traite une description égale au résumé de l'outil comme « non spécifique à l'action » et l'omet de la couche 2 ; les descriptions spécifiques à l'action passent intactes.

La description d'outil groupée, couches 1 et 2 : en 5.0.9 le résumé hérité était échoé une fois par action et le hint Requires: sautait les champs du commonSchema ; en 5.0.10 l'écho est omis et le hint concorde avec le validateur.

Bug 153 : le hint que le validateur aurait rejeté

Le hint « quels champs dois-je passer », la ligne Requires:, était calculé sur le schema par action seulement. Il ne regardait jamais le commonSchema au niveau de l'outil et n'appliquait pas omitCommonFields. La conséquence en pratique : un workspace_id requis déclaré via .commonSchema() apparaissait dans inputSchema.required, mais jamais dans le hint. Le modèle omettait le champ, la validation rejetait l'appel, l'agent lisait l'erreur, rappelait avec le champ manquant, et réussissait. Un rebond d'auto-réparation de trop, payé à chaque appel groupé qui partageait un champ commun. La correction fait que getActionRequiredFields() reflète le même schema fusionné que buildValidationSchema() applique, omitCommonFields compris, le hint et le validateur ne peuvent plus diverger.

Le paramètre commonSchema ajouté à getActionRequiredFields / generateDescription / generateToonDescription est optionnel, ce qui garde le changement visible sur le fil mais non cassant : rien dans l'API, les types ou les formes de schéma ne change ; la sortie de l'exposition à plat est inchangée octet pour octet, et les descriptions groupées ne font que rétrécir. La conséquence opérationnelle unique : le integrityDigest de mcpfusion.lock change pour les serveurs groupés qui avaient des descriptions héritées ; régénérez le lockfile.

Le catch qui avalait le sens

L'idionme que le framework enseigne est de classer les échecs, pas seulement de les lever : handlers et middleware peuvent throw une réponse déjà classée (throw toolError('NOT_FOUND', {...}), throw error('Unauthorized')) au lieu de la renvoyer. Le bloc catch de runChain() reconnaissait une ToolResponse simple et rien d'autre ; une réponse lancée arrivait donc sans son code d'erreur, sans son guide de récupération et sans sa sévérité avertissement-contre-erreur, et repartait ré-empaquetée en INTERNAL_ERROR générique.

Deux formes étaient pires que « perdues ». Un HandoffResponse lancé porte la marque de réponse-outil mais n'a pas de tableau content ; la seule vérification isToolResponse() le transmettait à du code qui indexe content, une chute sur le chemin de handoff fédéré. Un ResponseBuilder lancé était jeté au lieu d'être construit, perdant tous les blocs de contenu composés. Le catch miroite désormais l'ordre de postProcessResult() (isHandoffResponseisResponseBuilderisToolResponse), et seul le reste réellement inattendu devient INTERNAL_ERROR.

Ce qui pèse le plus à la frontière du modèle : ce repli n'affirme plus que l'échec est transitoire. Un échec permanent (un id invalide, une ressource manquante, une auth expirée) enverrait sinon l'agent dans une boucle de retry à paramètres identiques. La nouvelle erreur rapporte l'origine [outil/action] et dit au modèle d'inspecter le message au lieu de rejouer à l'aveugle, la différence entre un agent qui escalade et un qui martèle le même appel jusqu'au dépassement de délai.

Épinglé et embarqué

  • DescriptionInheritance-bug152-153.test.ts (18 cas) et ThrownResponseRecovery.test.ts (12 cas) épinglent les deux comportements, selon les notes de version.
  • Suite core complète : 5 243 réussis, 0 échoués ; tsc --noEmit propre ; les 16 packages du workspace buildent.

Installer tient en une ligne :

npm install @mcpfusion/core@5.0.10

Vous faites tourner l'exposition groupée ? Régénérez votre mcpfusion.lock pour que le integrityDigest corresponde à la description (maintenant plus courte), et rien d'autre ne change dans vos handlers ; l'idionme de lancer une réponse classée fonctionne désormais comme la doc l'a toujours promis.

Sujetsmcpmcpfusionagents