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

# Tracing

> Every tool call as an OpenTelemetry span — automatically.

When you call `instrumentServer(server, config)`, the package patches
`server.registerTool` so every subsequent tool you register runs inside an
[OpenTelemetry](https://opentelemetry.io) span.

## Span shape

Each tool invocation produces a single span:

```text theme={null}
name:       tools/call <toolName>
status:     OK | ERROR
duration:   ms
attributes: { ... see below ... }
```

### Attributes

| Attribute                | Description                                                        |
| ------------------------ | ------------------------------------------------------------------ |
| `mcp.method.name`        | Always `"tools/call"` for tool invocations.                        |
| `mcp.tool.name`          | The tool name passed to `registerTool`.                            |
| `mcp.tool.title`         | Tool title from the tool config.                                   |
| `mcp.tool.description`   | Tool description from the tool config.                             |
| `mcp.request.id`         | UUID generated per request.                                        |
| `mcp.session.id`         | UUID generated when the SDK starts; constant for the process.      |
| `mcp.operation.success`  | `true` on OK, `false` on thrown error.                             |
| `mcp.operation.duration` | Duration in ms (also written as a histogram metric).               |
| `client.address`         | First non-internal IPv4 address of the host (`localhost` if none). |
| `client.port`            | `process.env.PORT` if set.                                         |
| `error.type`             | Error class name (only on failure).                                |
| `error.message`          | Error message (only on failure).                                   |

### Optional attributes

These show up only under specific configurations:

| Attribute                     | When                                                                                  |
| ----------------------------- | ------------------------------------------------------------------------------------- |
| `mcp.request.argument.<key>`  | When `enableArgumentCollection: true`. Each argument flattened into a span attribute. |
| `mcp.safety_check.content`    | When the handler is wrapped with `safetyCheck`.                                       |
| `mcp.safety_check.flagged`    | `true` if Sedata's safety API flagged the input.                                      |
| `mcp.safety_check.latency_ms` | Round-trip latency of the safety check.                                               |
| `mcp.safety_check.success`    | `true` if the safety API responded successfully (whether flagged or not).             |

<Warning>
  `enableArgumentCollection` is **off** by default. Tool arguments often
  contain user input, secrets, or PII — turn it on knowingly.
</Warning>

## Resource attributes

The OTel resource attached to every span carries:

| Key                            | Source                                    |
| ------------------------------ | ----------------------------------------- |
| `service.name`                 | `config.serverName`                       |
| `service.version`              | `config.serverVersion`                    |
| `mcp.session.id`               | UUID per process                          |
| Host / OS / env detector attrs | From `@opentelemetry/resources` detectors |

These are added once per process and merged into every export.

## Errors

If your handler throws, the package:

1. Sets the span status to `ERROR` with the error message.
2. Sets `error.type`, `error.message`, `mcp.operation.success: false`.
3. Records the duration histogram with `mcp.operation.success: false`.
4. **Re-throws** the original error so the MCP runtime sees it.

```text theme={null}
span.name             tools/call calculate-bmi
status                ERROR
status.message        height cannot be zero
attributes.error.type RangeError
```

## Sampling

By default, all spans are recorded (`samplingRate: 1.0`). To trim volume in
production, set a ratio:

```ts theme={null}
const config: TelemetryConfig = {
  // ...
  samplingRate: 0.1, // keep 10% of traces
}
```

The sampler is `TraceIdRatioBasedSampler` — head-based and deterministic per
trace id. See [Sampling](/guides/sampling) for tradeoffs.

## What's next

<CardGroup cols={2}>
  <Card title="Automatic attributes reference" icon="list" href="/metrics-and-traces/automatic-attributes">
    Full table of every attribute the package writes.
  </Card>

  <Card title="Custom spans" icon="code" href="/metrics-and-traces/custom-instrumentation">
    Record domain-specific operations alongside auto-spans.
  </Card>
</CardGroup>
