Publicado 20 sept 20265 min de lectura
MCP Fusion 5.1.0: correlacionar llamadas a herramientas MCP en la trace distribuida
Publicada el 20 de septiembre de 2026. Los spans de herramienta MCP eran islas: cada llamada iniciaba una raíz nueva, y los backends que no hablan mcp.* no podían consultarlos. La 5.1.0 añade correlación del contexto W3C Trace y emisión dual GenAI/OpenInference a cada span de herramienta, sin una sola dependencia OpenTelemetry en el core.

Por Renato Marinho
Founder · Vinkius
Las notas del release 5.1.0, publicado el 20 de septiembre de 2026, listan dos frentes de trabajo: G1, correlación de padre W3C Trace Context, y G2, emisión de doble convención, y ambos caen en un solo paquete (notas del release · MCP Fusion en GitHub). Los otros 15 paquetes suben a 5.1.0 en lockstep sin una línea de código: su range ^5.0.0 sobre el core ya está satisfecho, así que, para ellos, el release es una línea de contabilidad semver. Lo que se movió es estrecho, y toca exactamente la cosa que decide si puedes ver las llamadas a herramienta de tu agente en tu backend.
El waterfall moría en la puerta de enlace
Antes de este release, MCPFusionTracer.startSpan tomaba dos argumentos y los spans que producía eran siempre raíces nuevas. En la práctica, la trace distribuida del agente se detenía en la puerta de enlace del MCP: cada llamada a herramienta aparecía en tu backend como una trace huérfana propia, y seguir agente → herramienta en un solo waterfall era imposible. Era también la causa de otra ceguera: los backends sin conocimiento del namespace privado mcp.* no podían responder "todas las llamadas de la última hora"; esa consulta solo corría donde le habías enseñado el namespace a tu proveedor.
Un handle de padre que el framework no toca
El nuevo tipo exportado MCPFusionSpanContext es un handle de padre estructuralmente opaco: traceId (32 caracteres hex minúsculos), spanId (16), flags (el byte de flags W3C, 0x01 si está muestreado), más los opcionales remote, traceState, baggage y un slot raw para el contexto del tracer del host. El host construye uno a partir de una pareja traceparent / tracestate / baggage recibida, cabeceras HTTP, o params._meta del MCP, y el framework hace exactamente una cosa con él: lo reenvía. Nunca lo inspecciona. Esa opacidad es el diseño, no un accidente: como un adaptador en el host mapea traceId / spanId / raw sobre SpanContext + Context de OpenTelemetry, @mcpfusion/core mantiene cero dependencias @opentelemetry/*. Un Tracer de OTel puro no es asignable a MCPFusionTracer (arrays de atributos inmutables, más la separación del Context), así que la frontera sigue siendo un adaptador fino en tu código, no una dependencia de paquete.
El parsing es estricto por elección. Los helpers sin dependencias asientan sobre crypto.randomUUID(): newTraceId(), newSpanId(), generateTraceparent(sampled = true), y parseTraceparent solo acepta versión 00, trace IDs de 32 hex minúsculos no nulos, span IDs de 16 hex minúsculos no nulos y flags de dos dígitos hex; cualquier desviación devuelve undefined, nunca un padre fabricado. tracestate y baggage pasan intactos bajo sus límites W3C (512 caracteres, 8192 bytes), y extractW3CContext hace obligatorio un traceparent válido: sin cabecera válida no hay contexto, y el span es raíz nueva. El formato en bytes es el mismo que SwarmGateway ya emite; las traces del monorepo interoperan sin ceremonia.
La captura es por petición. GroupedToolBuilder y ToolRegistry leen una clave convencional duck-typed, ctx.mcpTraceContext (mismo patrón que ctx.handoffTraceparent), y la filan al span de herramienta, y el span de 404 de herramienta desconocida que ToolRegistry.routeCall emite recibe el mismo trato, lo cual cuenta precisamente porque el 404 suele ser el momento en que el agente perdió la noción de qué herramientas existen. Un matiz que vale conocer: sin contextFactory, attachToServer() instala un proxy de guardia que lanza en cualquier acceso a propiedad; el nuevo helper readMcpTraceContext hace su lectura única dentro de un try/catch y traga la excepción, así que habilitar tracing solo nunca te obliga a escribir un factory. La ausencia de contexto se lee como "raíz nueva", nunca como error. Hay un límite documentado: el framework no retiene ningún Context de OTel en runtime, así que las llamadas a valle auto-instrumentadas dentro del handler (Prisma, clientes HTTP, Redis) aparecen como hermanas del span MCP, no hijas. El padre recibido se honra; el span de herramienta no se vuelve el contexto activo para todo lo de abajo.
Un span, tres dialectos
Cada span de herramienta lleva ahora, junto a los atributos nativos mcp.*, openinference.span.kind = "TOOL", gen_ai.operation.name = "tools/call" y tool.name, el span de 404 incluido. El mismo span es entonces portable en Datadog, Arize y Phoenix sin que ninguno tenga que entender mcp.*; filtra por openinference.span.kind = TOOL en cualquier parte. Lo que no se emite pesa tanto como lo que sí: ningún atributo de tokens o costo en la frontera de la herramienta, porque esos viven en el span de LLM del lado del agente, y la 5.1.0 se niega a inventarlos en la capa de herramienta. La semántica de estado sigue el pipeline: UNSET para fallos del lado de la IA (errores de validación, acciones desconocidas, herramientas desconocidas; el span de 404 es explícitamente UNSET con mensaje, no ERROR), OK en éxito y ERROR solo si un handler lanza un fallo de sistema. Un LLM que llama a la herramienta equivocada no activa a tu guardia.
Si ya ejecutas un tracer de OpenTelemetry
Toda la adopción cabe en dos fragmentos. Primero, envuelve el tracer para que el argumento de contexto opcional aterrice en el lugar correcto:
import { trace, type SpanOptions, type Context } from '@opentelemetry/api';
const otel = trace.getTracer('mcpfusion');
registry.attachToServer(server, {
contextFactory: createContext,
tracing: {
startSpan: (name, options, context) =>
otel.startSpan(name, options as SpanOptions, context?.raw as Context | undefined),
},
});
Luego, en el context factory por petición, extrae el contexto W3C y guárdalo bajo la clave convencional:
const ctx = {
...baseContext,
mcpTraceContext: extractW3CContext(request.headers),
};
A partir de ahí, cada span de herramienta, ruteo 404 incluido, cuelga de la trace de quien llama, y cualquier backend que hable las convenciones GenAI/OpenInference lo ve. El bloque de verificación del release lo sustenta: build del core con cero errores de TypeScript, los 16 paquetes satélite limpios, la suite del core verde en 272 archivos / 5.263 tests y cero fallos, y @mcpfusion/swarm en 158/158. El nuevo Tracing.test.ts fija la paridad de emisión dual entre el span de herramienta y el de 404, los round-trips W3C, el rechazo de entradas malformadas, la tolerancia al proxy de guardia y la propagación del contexto padre en ambos caminos.
