> ## 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.

# Shape

> The two tools that return one trace's full step tree or one function's observed edges, with previews instead of value bytes.

Two tools return one object's whole structure and no value bytes: `vexlo_get_trace` for a trace,
`vexlo_get_function` for a function's own callers and callees. Reach them with an id or a name
from [find](https://docs.vexlo.ai/mcp/tools/find.md); fetch bytes afterwards with [values](https://docs.vexlo.ai/mcp/tools/values.md).

Both responses below come from the seeded server [find](https://docs.vexlo.ai/mcp/tools/find.md) describes: the spec's
conformance trace on team `fixture`, 17 steps with one three-attempt step.

## vexlo\_get\_trace

Returns every step that ran, with `parent_path` and `depth`, per-attempt status and timing, and
a preview of each captured `input`, `output`, `error`, and `logs` slot. A preview carries the
slot's `encoding`, its `bytes_count`, and the first 64 code points of the value.

| Argument | Type | Default |
| - | - | - |
| `traceId` | the trace to read | required |
| `order` | `structural`, sent as `?steps_sort=path`, or `slowest_first`, sent as `?steps_sort=duration_desc` | `structural` |
| `cursor` | opaque string | first page |

There is no `limit`: the tool asks for the server's own maximum steps per call,
`trace_steps_limit_max`, 500 here, and `steps` is that one page rather than the whole trace.
`next_cursor` is present exactly when more steps remain, and only the count of distinct `path`s
against `step_count` proves a walk saw every step. A clipped page under `slowest_first` drops
the steps with no completed attempt, which on a hung trace are the ones worth reading. The API
caps a trace at 10,000 steps. No `team` or `environment` argument either, since a trace id
already belongs to one team.

```json theme={null}
{
  "trace_id": "0f1a2b3c4d5e6f708192a3b4c5d6e7f8",
  "service": "delivery-service",
  "team": "fixture",
  "environment": "prod",
  "format_version": 2,
  "instance_id": "delivery-service-7f9c8d6b5-x2n4q",
  "sdk_version": "0.4.0",
  "tags": {
    "order_id": "O-1234"
  },
  "started_at": "2026-09-07T19:30:01.402Z",
  "first_seen_at": "2026-11-05T05:51:22.869Z",
  "last_seen_at": "2026-11-05T05:51:22.869Z",
  "root_status": "error",
  "completeness": "complete",
  "step_count": 17,
  "error_step_count": 4,
  "duration_ms": 121,
  "coverage": {
    "records_lost": 0,
    "records_shed": 0,
    "truncated": false,
    "instance_mismatch": false,
    "service_loss_24h": {
      "delivery-service": 0
    }
  },
  "steps": [
    {
      "path": "",
      "parent_path": null,
      "depth": 0,
      "name": "delivery.api.AssignDasherHandler",
      "parent_name": null,
      "attempt_grouping": "single",
      "duration_us": 121750,
      "attempts": [
        {
          "attempt": 0,
          "started_us": 0,
          "duration_us": 121750,
          "status": "error",
          "error_class": "builtins.ValueError",
          "slots": {
            "input": {
              "state": "stored",
              "bytes_count": 70,
              "truncated": false,
              "encoding": "json",
              "preview": "{\"method\":\"POST\",\"order_id\":\"O-1234\",\"path\":\"/delivery/assign-da"
            },
            "error": {
              "state": "stored",
              "bytes_count": 104,
              "truncated": false,
              "encoding": "json",
              "preview": "{\"message\":\"no eligible candidate in list\",\"stack\":[\"assign_dash"
            }
          }
        }
      ]
    },
... 431 lines omitted
    {
      "path": "AACAAAIAAA",
      "parent_path": "AACAAAI",
      "depth": 3,
      "name": "delivery.dispatch.PickBestFromCandidates",
      "parent_name": "delivery.dispatch.SelectEligibleDasher",
      "attempt_grouping": "observed_retry",
      "duration_us": 2450,
      "attempts": [
        {
          "attempt": 0,
          "started_us": 118500,
          "duration_us": 850,
          "status": "error",
          "error_class": "builtins.ValueError",
          "slots": {
            "input": {
              "state": "stored",
              "bytes_count": 116,
              "truncated": false,
              "encoding": "json",
              "preview": "{\"candidate_ids\":[\"D-101\",\"D-102\",\"D-103\",\"D-104\",\"D-105\"],\"radi"
            },
            "error": {
              "state": "stored",
              "bytes_count": 147,
              "truncated": false,
              "encoding": "json",
              "preview": "{\"message\":\"no eligible candidate in list\",\"stack\":[\"select_elig"
            }
          }
        },
        {
          "attempt": 1,
          "started_us": 119400,
          "duration_us": 810,
          "status": "error",
          "error_class": "builtins.ValueError",
          "slots": {
            "input": {
              "state": "stored",
              "bytes_count": 116,
              "truncated": false,
              "encoding": "json",
              "preview": "{\"candidate_ids\":[\"D-101\",\"D-102\",\"D-103\",\"D-104\",\"D-105\"],\"radi"
            },
            "error": {
              "state": "stored",
              "bytes_count": 147,
              "truncated": false,
              "encoding": "json",
              "preview": "{\"message\":\"no eligible candidate in list\",\"stack\":[\"select_elig"
            }
          }
        },
        {
          "attempt": 2,
          "started_us": 120260,
          "duration_us": 790,
          "status": "error",
          "error_class": "builtins.ValueError",
          "slots": {
            "input": {
              "state": "stored",
              "bytes_count": 116,
              "truncated": false,
              "encoding": "json",
              "preview": "{\"candidate_ids\":[\"D-101\",\"D-102\",\"D-103\",\"D-104\",\"D-105\"],\"radi"
            },
            "error": {
              "state": "stored",
              "bytes_count": 147,
              "truncated": false,
              "encoding": "json",
              "preview": "{\"message\":\"no eligible candidate in list\",\"stack\":[\"select_elig"
            }
          }
        }
      ]
    },
... 66 lines omitted
  ],
  "limit": 500,
  "next_cursor": null
}
```

That whole response is 11,585 bytes and 3,306 tokens, measured over the one-line text the tool
returned; the blocks here are `jq .` renderings of it. Fetching one step's two values afterwards
costs 113 tokens on this trace.

Reading the fields:

* `completeness` says whether every record arrived (`running`: more are expected;
  `partial`/`abandoned`: some were lost or given up on; `complete`: all of them) and is
  independent of `root_status`: this trace is `complete` with `root_status: "error"`.
* `coverage` carries `records_lost`, `records_shed`, `truncated`, `instance_mismatch`, and
  `service_loss_24h`. A missing step was shed or lost rather than skipped when these are
  non-zero.
* One step carries one or more attempts. `attempt_grouping` is `single`, `declared`, or
  `observed_retry`; the step above retried three times, so each attempt has its own status,
  timing, and slots. `error_class` appears only on an errored attempt.
* `path` is a step's identity and is opaque. Rebuild the tree from `parent_path` and `depth`,
  never by decoding it, and pass it to `vexlo_get_values` exactly as it arrived.

`order: "slowest_first"` returns the same steps ranked by the step's own duration, one row per
step, each still carrying all of its attempts: the retried step above appears once. Both orders
return 17 rows for this trace, matching its `step_count`, and cost within a token of each other
(11,585 bytes, 3,307 tokens).

An attempt's `status` is `ok`, `error`, or `in_flight`: the third means its entry record
arrived and its completion record did not. Such an attempt carries `attempt` and `started_us`
and nothing else, with no `duration_us`, no `error_class`, and no `slots` key. A step whose
every attempt is open carries no `duration_us` of its own either, so
under `slowest_first` it has nothing to rank by and sorts after every step that has one. An open
attempt counts in `step_count`, never in `error_step_count`, and leaves `root_status` absent
rather than `error`, so it is not failure; read it with `completeness`. `format_version` is the
record format this trace arrived in, 2 above. [Traces](https://docs.vexlo.ai/api/traces.md) documents both fields.

## vexlo\_get\_function

Returns one function's observed callers and callees across every trace the server has ingested
for it, not one trace. Reach it with a name from a trace's `name` field or from
`vexlo_list_functions`.

| Argument | Type | Default |
| - | - | - |
| `service` | the service the function belongs to | required |
| `name` | exact `module.qualname` | required |
| `team` | array of team ids | every team in the token's set |
| `environment` | `{named}` or `{unset}` | no filter |

`team` and `environment` are as [find](https://docs.vexlo.ai/mcp/tools/find.md) defines them: `environment` takes
`{"named": [...]}` or `{"unset": true}` and nothing else.
`service` is required, so this route's `service_required` error is unreachable from this tool.
There is no `include` argument: worked input and output examples come from
`vexlo_get_function_examples`.

```json theme={null}
{
  "service": "delivery-service",
  "team": "fixture",
  "name": "delivery.api.AssignDasherHandler",
  "observed_count": 1,
  "error_count": 1,
  "first_seen_at": "2026-11-05T05:51:22.869Z",
  "last_seen_at": "2026-11-05T05:51:22.869Z",
  "is_entry_point": true,
  "observed_callers": [
    {
      "name": null,
      "observed_count": 1,
      "first_seen_at": "2026-11-05T05:51:22.869Z",
      "last_seen_at": "2026-11-05T05:51:22.869Z"
    }
  ],
  "observed_callees": [
    {
      "name": "delivery.api.ParseAssignRequest",
      "observed_count": 1,
      "first_seen_at": "2026-11-05T05:51:22.869Z",
      "last_seen_at": "2026-11-05T05:51:22.869Z"
    },
... 24 lines omitted
    {
      "name": "delivery.api.WriteAPIResponse",
      "observed_count": 1,
      "first_seen_at": "2026-11-05T05:51:22.869Z",
      "last_seen_at": "2026-11-05T05:51:22.869Z"
    }
  ]
}
```

An observed edge list is what was seen, not what exists: code nobody marked, and a path that has
not run yet, produce the same silence as code with no other caller. A `null` name in
`observed_callers` means this function has been seen as an entry point or as an orphan, whose own
caller never arrived, so it alone never proves an entry point. `is_entry_point` is the index's own
answer to that question.

`observed_count` counts steps and `error_count` counts attempts, so a function that ran once
and failed three times reads 1 and 3; both sum across every edge.
[Functions](https://docs.vexlo.ai/api/functions.md) covers the index's own rules.
`team` is present only when the lookup resolved to one team; where it is absent the counts sum
every team in scope.

Cost tracks the number of distinct callers and callees, not how often the function ran. The
response above is 1,282 bytes and 518 tokens for one caller and six callees. Dividing by seven
overstates one more edge, since the identifying fields are paid once:
[token costs](https://docs.vexlo.ai/mcp/token-costs.md) derives the marginal edge from two measured fan-outs.

A never-observed pair is an answer, not an error. `observed_count: 0`, empty edge lists, and
both timestamps as empty strings:

```json theme={null}
{
  "service": "delivery-service",
  "team": "fixture",
  "name": "delivery.api.NoSuchHandler",
  "observed_count": 0,
  "error_count": 0,
  "first_seen_at": "",
  "last_seen_at": "",
  "is_entry_point": false,
  "observed_callers": [],
  "observed_callees": []
}
```

Branch on `observed_count === 0`, never on parsing those two timestamps as instants.

When every requested `team` is outside the token's set, the other tools return an empty,
route-shaped result with a `scope_note`. This tool is the one exception. Its response is a single
object whose every field a real call would have filled, so it returns only the two identifying
arguments and the note, rather than an `observed_count: 0` that would read as "never observed":

```json theme={null}
{
  "service": "delivery-service",
  "name": "delivery.dispatch.AssignDasher",
  "scope_note": "none of the requested teams (team-nope) are in this token's team set (demo, fixture); no rows can exist for them under this credential — this is a scope limit, not an empty result"
}
```

Detect that case by the absence of `observed_count`.


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