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

# Metrics export

> Push your MCP server's request metrics to your own observability backend over OTLP.

Alpic pushes per-tool request metrics from your MCP server to your observability backend over OTLP/HTTP. There is nothing to install and no change to your code or deploys. Configure a destination once and data points start arriving on the next minute.

<Note>
  Metrics export is available on **paid plans**. Destinations are configured per environment and per signal, so metrics
  can go to Prometheus 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 **Metrics**.
  </Step>

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

    We push to this URL exactly as you enter it and **never append a path**. `/v1/metrics` 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 metrics.

    You can add more than one destination with **Add destination**, and the same metrics 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 metric">
    Save the destination, then click **Send a test metric**. Alpic pushes one synthetic Gauge data point (`alpic.connection.check`, value `1`, marked `alpic.synthetic`) through the exact same path your real metrics take and shows you the backend's answer. The verification outcomes are the same as for [logs export](/telemetry/logs-export#verify-the-destination).
  </Step>
</Steps>

## Backend compatibility

Alpic exports counters and histograms with delta temporality. Gauges do not carry aggregation temporality. Check whether your backend can receive the delta metrics directly:

| Backend               | Delta support                    | Action                               |
| --------------------- | -------------------------------- | ------------------------------------ |
| Datadog               | Required natively                | None                                 |
| New Relic             | Native and recommended           | None                                 |
| Honeycomb             | Native and understood by queries | None                                 |
| Dynatrace             | Required natively                | None                                 |
| Elastic Cloud         | Native                           | None                                 |
| Prometheus            | Not with standard PromQL         | Enable `otlp-deltatocumulative`      |
| Grafana Cloud / Mimir | No reliable direct support       | Convert through Alloy or a Collector |

<Warning>
  Do not point an Alpic metrics destination directly at Grafana Cloud or Mimir. Put Grafana Alloy or an OpenTelemetry
  Collector between Alpic and the backend, and configure it to convert the metrics before forwarding them.
</Warning>

## What gets exported

Every settled MCP request in the environment is aggregated into five metric families, one data point per minute per dimension set:

| Metric                          | Kind      | What it measures                                | Principal dimensions                                                                                   |
| ------------------------------- | --------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `alpic.mcp.server.requests`     | Counter   | Settled requests                                | `mcp.method.name`, `gen_ai.tool.name`                                                                  |
| `mcp.server.operation.duration` | Histogram | Request duration in seconds                     | `mcp.method.name`, `gen_ai.tool.name`, `error.type` (failed only)                                      |
| `alpic.mcp.server.errors`       | Counter   | Failed requests                                 | `mcp.method.name`, `gen_ai.tool.name`, `error.type`, `rpc.jsonrpc.error_code` (`"none"` when codeless) |
| `alpic.mcp.server.token.usage`  | Counter   | Output tokens                                   | `gen_ai.token.type` (`output`), `gen_ai.tool.name`                                                     |
| `alpic.mcp.server.sessions`     | Gauge     | Distinct sessions within the minute (see below) | `alpic.mcp.client.name`                                                                                |

`gen_ai.tool.name` is present on tool calls only. The resource's `service.name` is the environment id, so one dashboard can filter across environments. Dimensions are deliberately bounded: user, session and conversation identifiers never become metric dimensions.

The duration histogram uses the OpenTelemetry MCP explicit bucket boundaries: 10 ms, 20 ms, 50 ms, 100 ms, 200 ms, 500 ms, 1 s, 2 s, 5 s, 10 s, 30 s, 1 min, 2 min and 5 min. Backends interpolate percentiles within these buckets.

For example, this PromQL query computes p95 across all MCP operations over a five-minute window in Grafana Cloud:

```promql theme={null}
histogram_quantile(
  0.95,
  sum by (le) (
    rate(mcp_server_operation_duration_seconds_bucket[5m])
  )
)
```

Prometheus histogram buckets are cumulative. Apply `rate` to each bucket before aggregating, and keep the `le` label in the aggregation so `histogram_quantile` can interpolate correctly. Add `mcp_method_name` or `gen_ai_tool_name` to the `sum by` labels to compute separate percentiles for each method or tool. In Datadog, use a percentile aggregation on the distribution metric instead.

Failed duration points and error counter points carry `error.type`: `mcp_error` (the request failed with a JSON-RPC error), `tool_error` (the tool returned `isError`), or `timeout`. Successful duration points omit it. Only `mcp_error` carries a JSON-RPC code on the error counter; tool errors and timeouts always land in the explicit `"none"` code bucket.

## Resolution and delay

Metrics are aggregated at **one-minute resolution**. Counters and histograms use **delta temporality**; Gauges carry no temporality. Every data point is stamped with its minute's start and end.

A minute is exported roughly one minute after it closes, once its last events have settled. End to end, an event therefore reaches your backend between roughly **1 and 2 minutes** after it happened, depending on where it fell within its minute.

<Warning>
  `alpic.mcp.server.sessions` means **distinct sessions within one minute**. Two minutes can count the same session
  twice, so summing the series over an hour over-counts. Roll it up with **max or avg**, never sum. It is exported as a
  Gauge so backends treat it as a level rather than a rate.
</Warning>

## Plans and downgrades

Metrics 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 minutes first.

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