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

# Traces export

> Push one trace per MCP request to your own observability backend over OTLP.

Alpic can push a distributed trace for every MCP request your server handles to any OpenTelemetry-compatible backend over OTLP/HTTP: Datadog, Grafana Cloud, Honeycomb, or your own collector. There is nothing to install and no change to your code or deploys. Configure a destination once and spans start arriving within seconds.

<Note>
  Traces export is available on **paid plans**. Destinations are configured per environment and per signal, so traces
  can go to Honeycomb while logs go elsewhere, and staging and production can point at different backends.
</Note>

## Set up a destination

<Steps>
  <Step title="Open the Telemetry settings">
    In your project **Settings**, open the **Telemetry** section, pick the environment to configure, and add a destination under **Traces**.
  </Step>

  <Step title="Enter the destination endpoint">
    Paste the **full** traces URL from your vendor, signal path included, for example `https://otlp.example.com/v1/traces`.

    We push to this URL exactly as you enter it and **never append a path**. `/v1/traces` is only the OTLP default: some vendors serve a different path, or a different host per signal, so always copy the URL your vendor documents for traces.

    You can add more than one destination with **Add destination**, and the same spans go to all of them. Each destination is configured, tested and stopped on its own.
  </Step>

  <Step title="Pick the protocol">
    `HTTP/protobuf` is the OTLP default. Switch to `HTTP/JSON` only if your backend asks for it.
  </Step>

  <Step title="Add the authentication header">
    Authentication is a header you copy from your vendor, such as `Authorization` or `DD-API-KEY`, with your API key as
    the value. Mark it **secret** so it is stored write-only and never shown again.
  </Step>

  <Step title="Save and send a test trace">
    Save the destination, then click **Send a test trace**. Alpic serializes and delivers a synthetic trace through the same protocol, headers and format as your real spans. A passing test proves your endpoint, credentials and protocol choice; real request spans appear once traffic flows. The verification outcomes are the same as for [logs export](/telemetry/logs-export#verify-the-destination).
  </Step>
</Steps>

## The span hierarchy

Each MCP request becomes one trace:

```
mcp.tools.call                      SERVER   the complete proxied request
├── alpic.server.startup            INTERNAL your server process starting (cold requests only)
└── alpic.server.execution          INTERNAL your handler's round-trip
    ├── GET                         CLIENT   an outbound HTTP call your handler made
    └── inventory.lookup            INTERNAL an event you captured with the insights SDK
```

* **`mcp.<method>`**: the root span covers the whole request as the client experienced it, from the moment it reached Alpic to the response. Its name is the stable dot-form of the MCP method (`mcp.tools.call`, `mcp.initialize`, `mcp.ping`). Its status carries the request outcome; failed requests are marked as errors with `error.type` and, for JSON-RPC errors, `rpc.jsonrpc.error_code`.
* **`alpic.server.startup`**: present only on the request that paid for your server process to start: process spawn, port readiness and the initial MCP handshake.
* **`alpic.server.execution`**: the round-trip through your handler. Everything your own code did nests here. It appears when your server reports its execution span for the request; a `ping` answered by Alpic, or a request whose reported spans did not arrive, exports the root span alone.
* **Your own instrumentation**: events captured with the insights SDK become children of the execution span: an event with a `duration` becomes a child span named after your event, one without becomes a span event. Your error flag maps to the span status.
* **Outbound HTTP calls**: completed calls your handler made become `CLIENT` children of the execution span (see [coverage](#outbound-http-call-coverage) below).

Dynamic values stay in attributes, never in span names, so your backend's grouping stays useful: a tool call is always named `mcp.tools.call` and carries `mcp.method.name = "tools/call"` and `gen_ai.tool.name = "weather_forecast"`. Root spans also carry the session (`mcp.session.id`), conversation (`gen_ai.conversation.id`), resolved user (`enduser.id`), client name (`alpic.mcp.client.name`) and output token estimate (`gen_ai.usage.output_tokens`) when known. The resource's `service.name` is the environment id, as for logs and metrics.

The gaps are meaningful: Lambda cold start and Alpic's own proxying overhead remain **uncovered stretches inside the root** rather than appearing as customer-owned spans. Time not covered by `alpic.server.startup` or `alpic.server.execution` is time your code did not spend.

## Outbound HTTP call coverage

Outbound auto-instrumentation covers **Node servers using Streamable HTTP** first; other runtimes and transports export the same request waterfall without outbound children.

Capture observes Node's `diagnostics_channel`, so it never patches your HTTP clients, and covers `fetch`, Undici, `node:http`/`node:https` and clients built on them such as Axios. A call becomes a child span only once its **full response body** has completed or the call failed; calls still open when your handler returns produce no child.

Each child carries the method, a **sanitized URL** (scheme, host and path only) and the status code or a low-cardinality error type. Query strings, fragments, credentials, headers, bodies and error messages are never captured. Instrumentation failures only ever drop these child spans; they never affect your server or the MCP request.

## Common vendors

Always copy the endpoint from your vendor's OTLP documentation, since regions and paths vary by account. Typical shapes:

| Vendor        | Traces endpoint shape                                      | Authentication header                          |
| ------------- | ---------------------------------------------------------- | ---------------------------------------------- |
| Datadog       | see Datadog's OTLP intake docs for your site               | `DD-API-KEY: <API key>`                        |
| Grafana Cloud | `https://otlp-gateway-<region>.grafana.net/otlp/v1/traces` | `Authorization: Basic <base64 instance:token>` |
| Honeycomb     | `https://api.honeycomb.io/v1/traces`                       | `x-honeycomb-team: <API key>`                  |

## Plans and downgrades

Traces export requires a paid plan. If your team downgrades, export stops but your configuration is kept, and upgrading resumes export with nothing to re-enter.

To stop exporting on any plan, delete the destination.

## When a destination stops being retried

If a destination keeps failing, whether from a revoked credential, a decommissioned endpoint, or a vendor outage that does not end, Alpic stops retrying it and says so in the Telemetry section, along with the reason it stopped. A rejected credential or a wrong path stops it immediately, since neither recovers by being retried. A temporary failure has to persist for a long run of pushes first.

Its siblings keep exporting. To start it again, fix the endpoint or the headers and save, or click **Send a test trace**: either one clears the state once it succeeds. Spans produced while a destination was stopped are not replayed to it.

Traces are best-effort by design: they are produced inside the request path and buffered briefly before delivery, so a slow destination or a deploy can drop spans rather than ever slowing your requests down.
