Site
Alle Artikel

Veröffentlicht 20. Sept. 20265 Min. Lesezeit

MCP Fusion 5.1.0: MCP-Tool-Aufrufe in die verteilte Trace korrelieren

Veröffentlicht am 20. September 2026. MCP-Tool-Spans waren Inseln: Jeder Aufruf startete eine frische Wurzel, und Backends, die kein mcp.* sprechen, konnten sie gar nicht abfragen. 5.1.0 fügt jedem Tool-Span W3C-Trace-Context-Parent-Korrelation und doppelte GenAI/OpenInference-Ausgabe hinzu, ohne eine einzige OpenTelemetry-Abhängigkeit im Core.

Renato Marinho

Von Renato Marinho

Founder · Vinkius

MCP Fusion 5.1.0 trace flow: the agent's W3C traceparent is extracted into an opaque parent context, so every tool span, including the 404 span, parents to the caller's trace while emitting native mcp.* plus GenAI/OpenInference attributes

Die Release Notes der am 20. September 2026 veröffentlichten 5.1.0 listen zwei Arbeitspakete auf: G1, Parent-Korrelation über den W3C Trace Context, und G2, Emission nach doppelten Konventionen, und beide landen in einem einzigen Paket (Release Notes · MCP Fusion auf GitHub). Die anderen 15 Pakete steigen ohne eine einzige Codezeile im Lockstep auf 5.1.0: Ihr ^5.0.0-Range auf den Core ist bereits erfüllt, also ist das Release für sie eine einzige Zeile Semver-Buchhaltung. Was sich bewegt hat, ist eng, und es berührt genau die Sache, die darüber entscheidet, ob du die Tool-Aufrufe deines Agenten im Backend sehen kannst.

Der Waterfall endete am Gateway

Bis zu diesem Release nahm MCPFusionTracer.startSpan zwei Argumente, und die Spans, die es produzierte, waren stets frische Wurzeln. In der Praxis bedeutete das: Die verteilte Trace des Agenten endete am MCP-Gateway; jeder Tool-Aufruf erschien im Backend als seine eigene verwaiste Trace, und Agent → Tool in einem einzigen Waterfall zu verfolgen, war unmöglich. Und es war die Ursache für eine zweite Blindheit: Backends ohne Kenntnis des privaten mcp.*-Namespaces konnten auf „alle Aufrufe der letzten Stunde“ nicht antworten; diese Abfrage lief nur dort, wo man dem Anbieter den Namespace beigebracht hatte.

Vorher: Jeder Tool-Aufruf prägte seine eigene Trace-Wurzel. Danach: Der W3C traceparent pro Request hängt den Tool-Span an die Trace des Aufrufenden, 404s für unbekannte Tools eingeschlossen.

Ein Parent-Handle, das das Framework nicht berührt

Die neue exportierte Art MCPFusionSpanContext ist ein strukturell intransparents Parent-Handle: traceId (32 Kleinbuchstaben-Hex-Zeichen), spanId (16), flags (das W3C-Trace-Flags-Byte, 0x01, wenn sampled), dazu die optionalen remote, traceState, baggage und ein raw-Slot für den Tracer-Context des Hosts. Der Host baut daraus eines aus einem eingehenden traceparent / tracestate / baggage-Paar, HTTP-Header oder MCP-params._meta, und das Framework tut mit ihm genau eine Sache: Es leitet es weiter. Es inspiziert es niemals. Diese Intransparenz ist das Design, kein Zufall: Weil ein Host-Adapter traceId / spanId / raw auf SpanContext + Context von OpenTelemetry mappt, hält @mcpfusion/core null @opentelemetry/*-Abhängigkeiten. Ein roher OTel-Tracer ist nicht zu MCPFusionTracer zuweisbar (unveränderliche Attribut-Arrays, dazu die Context-Aufteilung), also bleibt die Grenze ein dünner Adapter in deinem Code statt einer Paketabhängigkeit.

Das Parsen ist absichtlich streng. Die Abhängigkeitsfreien Helper stehen auf crypto.randomUUID(): newTraceId(), newSpanId(), generateTraceparent(sampled = true), und parseTraceparent akzeptiert nur Version 00, Trace-IDs aus 32 kleinen, nicht-nuligen Hex-Zeichen, Span-IDs aus 16 kleinen, nicht-nuligen Hex-Zeichen und zwei Hex-Ziffern für die Flags; jede Abweichung liefert undefined, niemals ein fabriziertes Parent. tracestate und baggage passieren unverändert innerhalb ihrer W3C-Limits (512 Zeichen, 8192 Bytes), und extractW3CContext macht ein gültiges traceparent zur Pflicht: Kein gültiger Header, kein Context, und der Span ist eine frische Wurzel. Das Byte-Format ist das, das SwarmGateway bereits emittiert; Traces über das Monorepo hinweg interoperieren ohne weiteres.

Die Übernahme läuft pro Request. GroupedToolBuilder und ToolRegistry lesen einen konventionellen, duck-gepckten Key, ctx.mcpTraceContext (selbes Muster wie ctx.handoffTraceparent), und faden ihn in den Tool-Span ein, und der 404-Span für unbekannte Tools, den ToolRegistry.routeCall emittiert, bekommt denselben Umgang. Das zählt gerade deshalb, weil der 404 oft der Moment ist, in dem ein Agent verloren hat, welche Tools existieren. Eine Feinheit: Ohne contextFactory installiert attachToServer() einen Guard-Proxy, der bei jedem Property-Zugriff wirft; der neue readMcpTraceContext-Helper führt seine einzige Lektüre in einem try/catch durch und schluckt den Wurf, sodass das bloße Aktivieren des Tracings nie ein Factory zwingt. Abwesenheit von Context liest sich als „frische Wurzel“, nie als Fehler. Es gibt eine dokumentierte Grenze: Weil das Framework zur Laufzeit keinen OTel-Context hält, tauchen automatisch instrumentierte abgehende Aufrufe im Handler (Prisma, HTTP-Clients, Redis) als Geschwister des MCP-Spans auf, nicht als Kinder. Das eingehende Parent wird honoriert; der Tool-Span wird nicht der aktive Context für alles Abgehende.

Ein Span, drei Dialekte

Jeder Tool-Span trägt jetzt neben den nativen mcp.*-Attributen openinference.span.kind = "TOOL", gen_ai.operation.name = "tools/call" und tool.name, der 404-Span eingeschlossen. Derselbe Span ist damit portabel über Datadog, Arize und Phoenix, ohne dass einer von ihnen mcp.* verstehen muss; filtere überall auf openinference.span.kind = TOOL. Was nicht emittiert wird, wiegt genauso: keine Token- oder Kosten-Attribute an der Tool-Grenze, denn die leben auf dem LLM-Span auf der Agenten-Seite, und die 5.1.0 erfindet sie an der Tool-Ebene nicht. Die Status-Semantik bleibt mit dem Pipeline konsistent: UNSET für KI-seitige Ausfälle (Validierungsfehler, unbekannte Aktionen, unbekannte Tools; der 404-Span ist explizit UNSET mit Nachricht, nicht ERROR), OK bei Erfolg und ERROR nur, wenn ein Handler eine Systemstörung wirft. Ein LLM, das das falsche Tool ruft, weckt deinen On-Call nicht.

Falls du schon einen OpenTelemetry-Tracer betreibst

Die gesamte Einführung ist zwei Snippets. Erstens kapselst du den Tracer ein, damit der optionale Context-Parameter dort landet, wo er hingehört:

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

Dann, im context factory pro Request, entnimmst du den W3C-Context und lagerst ihn unter dem konventionellen Key:

const ctx = {
  ...baseContext,
  mcpTraceContext: extractW3CContext(request.headers),
};

Ab diesem Punkt hängt jeder Tool-Span, 404-Routing eingeschlossen, an der Trace des Aufrufenden, und jedes Backend, das die GenAI/OpenInference-Konventionen spricht, sieht ihn. Der Verifikationsblock des Releases stützt das: Core-Build mit null TypeScript-Fehlern, alle 16 Satelliten-Pakete sauber, die Core-Suite grün mit 272 Dateien / 5.263 Tests und null Ausfällen, und @mcpfusion/swarm bei 158/158. Die neue Tracing.test.ts fixiert die Dual-Emissions-Parität zwischen Tool- und 404-Span, die W3C-Roundtrips, die Ablehnung kaputter Eingaben, die Guard-Proxy-Toleranz und die Parent-Context-Propagation auf beiden Wegen.

Themenmcptracingobservabilitymcpfusion