Background
Since #1202, the TypeScript runtime's callMcpTool publishes exactly one trace span per call. When a call takes more than one attempt (retries configured and exercised), the span carries a call_attempts key — the TOTAL number of attempts the call burned (3 = two retries). The key is emitted only when > 1, so single-attempt spans are unchanged.
Gap
The field stops at the Redis stream. The Go ingestion side (TraceEvent.FromRedisMap in src/core/registry/tracing/events.go) only parses the fields it knows about, so call_attempts is silently dropped — it never reaches trace storage, the API, or the dashboard.
Scope
- Go ingestion — parse
call_attempts in FromRedisMap, carry it through the TraceEvent struct and trace storage.
- API/UI — expose it on the trace/span endpoints and render it in the dashboard span view (an attempts badge on retried calls).
- Runtime parity — TypeScript is currently the only emitter. Python and Java proxies have the same retry loop but do not record attempt counts on their spans; they should emit the same
call_attempts key with the same emit-only-when->1 semantics so the field means the same thing regardless of producing runtime.
Notes
- Wire name is
call_attempts (total attempts, not retry count) — named before any consumer existed, so no migration concerns.
- No backward-compat risk: spans without the key simply render without attempts info.
Background
Since #1202, the TypeScript runtime's
callMcpToolpublishes exactly one trace span per call. When a call takes more than one attempt (retries configured and exercised), the span carries acall_attemptskey — the TOTAL number of attempts the call burned (3= two retries). The key is emitted only when> 1, so single-attempt spans are unchanged.Gap
The field stops at the Redis stream. The Go ingestion side (
TraceEvent.FromRedisMapinsrc/core/registry/tracing/events.go) only parses the fields it knows about, socall_attemptsis silently dropped — it never reaches trace storage, the API, or the dashboard.Scope
call_attemptsinFromRedisMap, carry it through theTraceEventstruct and trace storage.call_attemptskey with the same emit-only-when->1 semantics so the field means the same thing regardless of producing runtime.Notes
call_attempts(total attempts, not retry count) — named before any consumer existed, so no migration concerns.