> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vexlo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Token costs

> What one call of each tool costs in bytes and tokens, how it was measured, and which bounds those numbers set.

Every default page size and ceiling on this surface was set against a measured cost, not a
guess. This is that table. Each row is one tool call's result text, ascending by tokens, and
each carries a label:

* **measured**: a tokenizer run over the exact string the tool returned.
* **extrapolated**: computed from a measured per-row cost, because no seed held enough rows.
* **derived**: computed from a measured per-item rule, stated in prose below rather than in the
  table.

## The ladder

| Tool | Call | Bytes | Tokens | Label | Seed |
| - | - | -: | -: | - | - |
| `vexlo_list_tags` | 1 tag | 117 | 34 | measured | baseline |
| `vexlo_check_coverage` | 1 service | 172 | 65 | measured | baseline |
| `vexlo_find_related_traces` | empty result, window matched | 180 | 69 | measured | one fresh trace |
| `vexlo_check_health` | 1 service | 333 | 113 | measured | baseline |
| `vexlo_get_values` | 1 path, 2 slots | 396 | 113 | measured | baseline |
| `vexlo_find_related_traces` | 1 related trace | 354 | 122 | measured | two fresh traces |
| `vexlo_get_function_examples` | 1 example, preview | 466 | 134 | measured | baseline |
| `vexlo_get_values` | 1 path, `logs` slot of 3 entries | 621 | 144 | measured | logs fixture |
| `vexlo_get_function_examples` | 1 example, `includeValues` | 525 | 155 | measured | baseline |
| `vexlo_find_related_traces` | empty result, anchor outside the window, with `note` | 501 | 168 | measured | baseline |
| `vexlo_check_trace_status` | 1 trace id | 490 | 180 | measured | baseline |
| `vexlo_get_function` | 3 callers, 2 callees | 991 | 399 | measured | checkout fixture |
| `vexlo_get_function` | 1 caller, 6 callees | 1,297 | 520 | measured | baseline |
| `vexlo_get_function_examples` | 5 examples, preview | 1,906 | 575 | measured | baseline |
| `vexlo_get_function_examples` | 5 examples, `includeValues` | 2,201 | 680 | measured | baseline |
| `vexlo_get_values` | 8 paths, leading steps | 2,788 | 806 | measured | baseline |
| `vexlo_get_values` | 8 paths, the failing branch | 4,367 | 1,284 | measured | baseline |
| `vexlo_search_traces` | its default page, 10 traces | 4,606 | 1,473 | measured | baseline |
| `vexlo_list_functions` | 17 functions, unfiltered | 4,173 | 1,484 | measured | baseline |
| `vexlo_get_trace` | 17-step trace, structural order | 11,229 | 3,184 | measured | baseline |
| `vexlo_get_trace` | the same trace, `slowest_first`, when that order listed one row per attempt | 11,649 | 3,297 | measured | baseline |
| `vexlo_list_functions` | 50 functions | 12,200 | 4,300 | extrapolated | baseline |
| `vexlo_find_related_traces` | 100 related traces, its ceiling | 17,680 | 5,498 | measured | 101 traces |
| `vexlo_search_traces` | the API's default of 50, which this tool never issues | 22,606 | 7,127 | measured | baseline |
| `vexlo_check_trace_status` | 100 trace ids, the route's cap | 45,042 | 14,144 | measured | 101 traces |
| `vexlo_search_traces` | 100 traces, its ceiling | 45,107 | 14,191 | measured | 101 traces |

## How it was measured

The baseline seed is a server run with `-no-auth` and a long shape retention, holding the spec's
conformance trace (17 steps, `root_status: error`) ingested 60 times with fresh trace ids, read
back through the tools themselves. Seven rows needed a seed of their own, each named in the last
column: the `logs` row ingested the spec's three-entry logs fixture, the three-caller fan-out ran
against a purpose-built fixture of five synthetic traces naming one function as root once and as
a child four times under two parents, the three 100-row rows needed 101 freshly dated traces
because 60 cannot fill a 100-row page, and the two related-trace rows with a matched window
needed traces young enough to fall inside 24 hours. A difference between two rows is a
difference in cost only when they share a seed.

Bytes count the one-line tool result text, which is what enters an AI agent's context, not the
HTTP body it was parsed from, and not the `jq .` renderings the other pages show. Text and body
agree within a byte except where the process adds something of its own:
the empty-`state` rewrite on `vexlo_get_function_examples`, about 12 bytes an example, and
`vexlo_find_related_traces`'s staleness `note`, which the two related rows above put at 321
bytes including its key.

Tokens come from a tokenizer run over that same string, never from its length divided by a
constant. The tokenizer is `@anthropic-ai/tokenizer` 0.0.4, a published byte-pair encoding from
the Claude 2 generation, because no current model's tokenizer is published and counting with a
current one needs credentials this measurement did not have. Their error against a current
model is unmeasured in size and direction, so read any threshold here to the nearest ten
tokens, and two rows within a few percent of each other as needing a fresh measurement.

The startup handshake is excluded from every row: it is 672 bytes and 224 tokens on the server
these pages were captured against, paid once per process launch and never inside a tool result.

## What the numbers decided

A constant divisor would not do. The ratio runs from 2.5 bytes per token on
`vexlo_get_function`'s dense nested objects to 4.3 on a `logs` slot of English prose. On the
densest row, 991 bytes and 399 tokens, dividing bytes by four gives 248: 62% of the real count,
so the estimate falls 38% short in the one direction a claim about cheapness must not be wrong
in. The two columns do not even rank the calls alike. Read down the table, which ascends by
tokens, and the byte figure falls five times; across every pair of rows, nine pairs invert.

`vexlo_search_traces` defaults to 10 traces rather than the API's 50 because of two rows here:
10 rows cost 1,473 tokens and 50 cost 7,127, which is more than one whole trace's shape for a
page an agent has not decided to read yet.

`vexlo_get_trace` and `vexlo_search_traces` are the expensive members by construction, one
returning a whole call tree and the other enumerating traces. Pushed to their ceilings, the two
widest pages cost over 14,000 tokens, four times one trace's shape. One ceiling is wider still
and no row measures it: `vexlo_list_functions` accepts `limit: 200`, and at the 87 tokens a row
its 17-row page gives, 200 rows is roughly 17,400 tokens, derived. Size a context window against
that figure, not against the 50-row row. `vexlo_get_function` scales with distinct caller and
callee edges rather than call count. Its two measured fan-outs, five edges at 991 bytes and
seven at 1,297, put each further edge at about 153 bytes and 60 tokens; they sit on different
seeds, so treat that as an estimate rather than a measurement. Thirty edges is then roughly
4.8 KB and 1,900 tokens, derived.

The discovery tools are cheap enough to call freely before trusting an empty result:
`vexlo_list_tags`, `vexlo_check_coverage`, and an empty window-matched
`vexlo_find_related_traces` all sit under 70 tokens, and `vexlo_check_health` under 115.
`vexlo_check_trace_status` is the one to watch, at 180 tokens for a single id, because what it
returns is a full trace-summary row.

## The same calls on another seed

Fourteen of these calls were re-measured on the bearer server the rest of these pages were
captured against, which holds four demo traces and one fixture trace rather than 60 clones. Six
came back byte-for-byte and token-for-token identical: `vexlo_list_tags` at one tag,
`vexlo_check_health` at one service, `vexlo_get_values` at one path and at eight leading paths,
and both empty `vexlo_find_related_traces` answers. The other eight moved. Where another MCP page
quotes one of these calls, it quotes the right-hand column:

| Call | On the baseline seed | On the bearer server | What differs |
| - | - | - | - |
| `vexlo_check_coverage`, 1 service | 172 / 65 | 171 / 65 | `traces_24h` is 1 here against 60 |
| `vexlo_get_function_examples`, preview | 466 / 134 | 466 / 158 | the same length, a different example inside it |
| `vexlo_get_function_examples`, `includeValues` | 525 / 155 | 525 / 179 | the same |
| `vexlo_check_trace_status`, 1 id | 490 / 180 | 490 / 173 | the same length, different ids inside it |
| `vexlo_get_function`, 1 caller 6 callees | 1,297 / 520 | 1,282 / 518 | one trace rather than 60 clones, so every count is a single digit |
| `vexlo_list_functions`, 17 functions | 4,173 / 1,484 | 4,048 / 1,450 | the same |
| `vexlo_get_trace`, structural | 11,229 / 3,184 | 11,585 / 3,306 | the client passes `format_version` and each step's own `duration_us` through now |
| `vexlo_get_trace`, `slowest_first` | 11,649 / 3,297 | 11,585 / 3,307 | that order returned one row per attempt when the ladder was taken, one per step now |

Only the last two rows moved because the software changed; the other six moved because the data
did. Both `vexlo_get_trace` orders now return 17 rows for the 17-step trace, so `slowest_first`
is a reordering rather than a longer response.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.