Skip to main content
A session is one client connection to your server. The SDK generates a session id when the first watch() runs and shares it for the life of the process, so every call a client makes lands in the same session.

Why sessions matter

Two of the most useful metrics are questions about a conversation rather than about a call:
  • Retries and first-call success are detected within one session. Two calls to the same tool in different sessions are two people, not one struggling model.
  • Cost per session is what your server costs someone for one conversation, which is the figure an author can actually act on.
Both are meaningless if sessions fragment. On streamable HTTP, where a fresh McpServer is built per request, the SDK deliberately shares one session per process for exactly this reason.

Counted by start time, never summed per day

Sessions get their own table rather than a daily counter, because a session can cross midnight. A session that opens at 23:50 and closes at 00:10 is one session. Summing daily session counts would make it two — and would halve cost per session, the number an author is most likely to quote back. So sessions are counted by started_at across the whole range, which is correct at any range length.

What is stored per session

The API returns totals plus the most recent sessions — up to 500, defaulting to 100 — each with its bytes converted to tokens and dollars.

Sessions have no tool dimension — but they do have a client

A session belongs to the server, not to a tool. Under a tool filter the sessions figure, calls per session and cost per session all come back null rather than as unfiltered numbers sitting in a filtered row. Scoping a session to a tool is not a harder query; it is a meaningless one. A client filter is different: sessions.client_name has always existed, so “sessions, for Cursor” is a real question and it narrows.

Depth is shown in bands, not as an average

The average of one 40-call session and nine single-call ones is 4.9, and 4.9 describes none of the ten. So the overview draws a distribution: even bands of three1–3, 4–6, … 19–21, then 22+ left open. Even, deliberately. The bands were uneven once — 1, 2, 3, 4, 5–9, 10–14, 15–24, 25+ — on the reasoning that the shallow end is where the finding is. That is a fair read of the data and a poor axis: bar widths going 1,1,1,1,5,5,10,∞ cannot be compared to each other, because a taller bar may only mean a wider bucket. single_call_share is counted from the sessions themselves, not from the first band. It read the first band’s count while that band happened to be exactly 1; at a width of three the same line would have reported the share making one, two or three calls under a name saying otherwise, and nothing on screen would have looked wrong.

Average calls per session

Returned alongside the totals, rounded to one decimal. A rough proxy for how much work a conversation makes your server do — and read next to first-call success, how much of that work was rework. The bands are what you look at when it moves.