Publicado 17 sept 20264 min de lectura
MCP Fusion 5.0.10: descripciones más pequeñas, errores lanzados recuperados
Publicada el 17 de septiembre de 2026. Dos correcciones P2 en @mcpfusion/core apuntando a las superficies exactas que el modelo toca: descripciones agrupadas que repetían el resumen de la herramienta una vez por acción y subreportaban campos requeridos, y respuestas clasificadas lanzadas que se aplanaban en un INTERNAL_ERROR genérico.

Por Renato Marinho
Founder · Vinkius
Publicada el 17 de septiembre de 2026, la 5.0.10 es un release de mantenimiento, y todo el código que cambió vive dentro de @mcpfusion/core; las notas del release confirman que los otros 15 paquetes del workspace siguen construyendo limpios, sin tocarlos (notas del release · MCP Fusion en GitHub). Dos defectos P2 y una caída latente componen el release. Los tres importan, y los tres solo se observan desde donde se para el modelo de lenguaje.
Bug 152: el resumen, dicho 1 + N veces
Bajo toolExposition: 'grouped', una herramienta expone un nombre con un campo discriminante action en vez de N herramientas planas, y su descripción es por capas. La capa 1 abre con el resumen de la herramienta, la lista de módulo/acción y la instrucción de despacho; la capa 2 lleva una línea por acción: el bloque Workflow: en markdown, la columna desc: en TOON. Cuando un builder define un .description() pero sus acciones individuales no tienen, el resumen de la herramienta se hereda a cada acción (correcto, la exposición plana se apoya en ese relleno), y entonces se ecoaba una vez por acción en la capa 2. El modelo veía el resumen 1 + N veces, sin información nueva después de la primera. Una descripción redundante no solo infla el prompt; diluye precisamente la señal que el modelo debería pesar. La corrección trata una descripción igual al resumen de la herramienta como "no específica de la acción" y la omite de la capa 2; las descripciones específicas de acción pasan intactas.
Bug 153: el hint que el validador rechazaba
El hint "qué campos debo pasar", la línea Requires:, se calculaba solo del schema por acción. Nunca miraba el commonSchema a nivel de herramienta y no aplicaba omitCommonFields. La consecuencia en la práctica: un workspace_id requerido declarado vía .commonSchema() aparecía en inputSchema.required, pero no en el hint. El modelo omitía el campo, la validación rechazaba la llamada, el agente leía el error, llamaba de nuevo con el campo que faltaba, y acertaba. Un rebote de auto-sanación de más, pagado en cada llamada agrupada que compartía campo común. La corrección hace que getActionRequiredFields() refleje el mismo schema fusionado que buildValidationSchema() aplica, omitCommonFields incluido, el hint y el validador dejan de poder divergir.
El parámetro commonSchema añadido a getActionRequiredFields / generateDescription / generateToonDescription es opcional, lo que mantiene el cambio visible en el wire pero no rompedor: nada de la API, los tipos o las formas de schema cambia; la salida de la exposición plana es byte a byte idéntica, y las descripciones agrupadas solo encogen. La única consecuencia operacional: el integrityDigest de mcpfusion.lock cambia para los servidores agrupados que tenían descripciones heredadas; regenera el lockfile.
El catch que tragaba el significado
El idiom que el framework enseña es clasificar fallos, no solo lanzarlos: handlers y middleware pueden throw una respuesta ya clasificada (throw toolError('NOT_FOUND', {...}), throw error('Unauthorized')) en vez de devolverla. El bloque catch de runChain() reconocía una ToolResponse simple y nada más; una respuesta lanzada llegaba entonces sin su código de error, sin su guía de recuperación y sin su severidad advertencia-contra-error, y salía reempaquetada como INTERNAL_ERROR genérico.
Dos formas eran peores que "perdidas". Un HandoffResponse lanzado lleva la marca de respuesta-tool pero no tiene arreglo content; el chequeo solo de isToolResponse() lo reenviaba a código que indexa content, un crash en el camino de handoff federado. Un ResponseBuilder lanzado se descartaba en vez de construirse, perdiendo todos los bloques de contenido compuestos. El catch ahora espeja el orden de postProcessResult() (isHandoffResponse → isResponseBuilder → isToolResponse), y solo el residuo genuinamente inesperado se vuelve INTERNAL_ERROR.
Lo que más pesa en la frontera del modelo: ese relleno ya no afirma que el fallo sea transitorio. Un fallo permanente (un id malo, un recurso ausente, una auth vencida) de lo contrario mandaría al agente a un loop de retry con parámetros idénticos. El nuevo error reporta el origen [herramienta/acción] y le dice al modelo que inspeccione el mensaje en vez de reintentar a ciegas, la diferencia entre un agente que escala y uno que martilla la misma llamada hasta el timeout.
Fixado y a bordo
DescriptionInheritance-bug152-153.test.ts(18 casos) yThrownResponseRecovery.test.ts(12 casos) fijan ambos comportamientos, según las notas del release.- Suite completa del core: 5.243 aprobados, 0 fallados;
tsc --noEmitlimpio; los 16 paquetes del workspace construyen.
Instalar es una línea:
npm install @mcpfusion/core@5.0.10
¿Ejecutas exposición agrupada? Regenera tu mcpfusion.lock para que el integrityDigest coincida con la descripción (ahora menor), y nada más cambia en tus handlers; el idiom de lanzar una respuesta clasificada funciona por fin como los docs siempre prometieron.
