Bug
MCP server usage never appears in the dashboard breakdown, and other tool invocations
(Agent spawns, EnterPlanMode, etc.) are silently dropped from turns that involve
streaming responses.
Environment
|
|
| codeburn |
0.8.1 |
| Claude Code |
2.1.114 |
| Node.js |
20.20.0 |
| OS |
Ubuntu 24.04.2 LTS (Linux 6.17.0-1010-aws x86_64) |
| Provider |
Claude Code sessions routed via Databricks AI Gateway (Bedrock backend) |
Root cause
Claude Code writes the same message.id to the session JSONL multiple times as a
response streams in:
- First write (
message_start) — model + ID, empty content, partial usage
- Intermediate writes — mid-stream updates
- Final write (
message_stop) — complete content including tool_use blocks,
final token counts
groupIntoTurns in src/parser.ts deduplicates by message.id keeping the
first occurrence and skipping all subsequent entries. The final entry — the only
one containing tool_use blocks — is discarded.
Example from a real session JSONL where mcp__playwright__browser_navigate only
appears in the third entry for the same message.id:
{"type":"assistant","message":{"id":"msg_01X...","model":"claude-opus-4-6","content":[],...}}
{"type":"assistant","message":{"id":"msg_01X...","model":"claude-opus-4-6","content":[],...}}
{"type":"assistant","message":{"id":"msg_01X...","model":"claude-opus-4-6","content":[{"type":"tool_use","name":"mcp__playwright__browser_navigate",...}],...}}
Only the first entry is parsed; the tool call is never counted.
Impact
- MCP server breakdown panel never populates for affected turns
tool_use blocks in streaming turns are missed (Agent, EnterPlanMode, Bash, etc.)
- Token counts may be slightly understated (final entry has the authoritative usage)
Fix
Add a within-file pre-pass in parseSessionFile that keeps the last occurrence
of each message.id before handing entries to groupIntoTurns. The existing
cross-file seenMsgIds dedup in groupIntoTurns (keep first-seen) is correct and
should remain unchanged — the two concerns need to be handled separately.
// In parseSessionFile, before groupIntoTurns:
const lastIdxById = new Map<string, number>()
for (let i = 0; i < filteredEntries.length; i++) {
const msgId = getMessageId(filteredEntries[i])
if (msgId) lastIdxById.set(msgId, i)
}
const dedupedEntries = filteredEntries.filter((entry, i) => {
const msgId = getMessageId(entry)
if (!msgId) return true
return lastIdxById.get(msgId) === i
})
// pass dedupedEntries to groupIntoTurns instead of filteredEntries
Verified
MCP calls (mcp__playwright__browser_navigate, mcp__playwright__browser_snapshot,
mcp__github__get_file_contents) confirmed present in JSONL but absent from dashboard
before fix, correctly attributed after. Total call counts unchanged — no
double-counting introduced. Full test suite: 273 pass, 0 regressions.
Please let me know if you want me to raise a PR for this as I am happy to. Awesome tool you have here and we use it every day since we discovered it.
Bug
MCP server usage never appears in the dashboard breakdown, and other tool invocations
(Agent spawns, EnterPlanMode, etc.) are silently dropped from turns that involve
streaming responses.
Environment
Root cause
Claude Code writes the same
message.idto the session JSONL multiple times as aresponse streams in:
message_start) — model + ID, empty content, partial usagemessage_stop) — complete content includingtool_useblocks,final token counts
groupIntoTurnsinsrc/parser.tsdeduplicates bymessage.idkeeping thefirst occurrence and skipping all subsequent entries. The final entry — the only
one containing
tool_useblocks — is discarded.Example from a real session JSONL where
mcp__playwright__browser_navigateonlyappears in the third entry for the same
message.id:{"type":"assistant","message":{"id":"msg_01X...","model":"claude-opus-4-6","content":[],...}} {"type":"assistant","message":{"id":"msg_01X...","model":"claude-opus-4-6","content":[],...}} {"type":"assistant","message":{"id":"msg_01X...","model":"claude-opus-4-6","content":[{"type":"tool_use","name":"mcp__playwright__browser_navigate",...}],...}}Only the first entry is parsed; the tool call is never counted.
Impact
tool_useblocks in streaming turns are missed (Agent, EnterPlanMode, Bash, etc.)Fix
Add a within-file pre-pass in
parseSessionFilethat keeps the last occurrenceof each
message.idbefore handing entries togroupIntoTurns. The existingcross-file
seenMsgIdsdedup ingroupIntoTurns(keep first-seen) is correct andshould remain unchanged — the two concerns need to be handled separately.
Verified
MCP calls (
mcp__playwright__browser_navigate,mcp__playwright__browser_snapshot,mcp__github__get_file_contents) confirmed present in JSONL but absent from dashboardbefore fix, correctly attributed after. Total call counts unchanged — no
double-counting introduced. Full test suite: 273 pass, 0 regressions.
Please let me know if you want me to raise a PR for this as I am happy to. Awesome tool you have here and we use it every day since we discovered it.