---
title: telemetry
sidebarTitle: telemetry
---

# `fastmcp.server.telemetry`


Server-side telemetry helpers.

## Functions

### `get_auth_span_attributes` <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/telemetry.py#L43" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

```python
get_auth_span_attributes() -> dict[str, str]
```


Get auth attributes for the current request, if authenticated.


### `get_session_span_attributes` <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/telemetry.py#L60" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

```python
get_session_span_attributes() -> dict[str, str]
```


Get session attributes for the current request.


### `get_protocol_span_attributes` <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/telemetry.py#L74" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

```python
get_protocol_span_attributes() -> dict[str, str]
```


Get the negotiated MCP protocol version for the current request.

Mirrors the `mcp.protocol.version` attribute the SDK's own
`OpenTelemetryMiddleware` sets — FastMCP drops that middleware to avoid a
duplicate SERVER span, so this restores the attribute on FastMCP's span.


### `record_span_exception` <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/telemetry.py#L154" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

```python
record_span_exception(span: Span, e: Exception) -> None
```


Record an exception and error status on a span.


### `seam_span` <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/telemetry.py#L164" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

```python
seam_span(method: str, server_name: str) -> Generator[Span, None, None]
```


Open the per-request SERVER span at the FastMCP middleware seam.

The span is named after the method and carries the base MCP attributes
(`mcp.method.name`, `fastmcp.server.name`, auth/session context) so
seam-only methods (`logging/setLevel`, `tasks/*`, `ping`, `initialize`, ...)
are fully attributed even though they never reach the high-level path. It is
marked with `SEAM_SPAN_MARKER` so a later `server_span` call in the
high-level path enriches this span with component attributes instead of
opening a second one. Exceptions raised anywhere below the seam — including
rejections *before* the high-level path (auth, not-found, middleware vetoes)
that would otherwise produce no SERVER span at all — are recorded here.

In `propagation_only` mode no span is opened at all — this is the one place
that has to know the difference, because the seam is where the incoming
`_meta` parent context is applied for the whole request.


### `server_span` <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/telemetry.py#L224" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

```python
server_span(name: str, method: str, server_name: str, component_type: str, component_key: str, resource_uri: str | None = None, tool_name: str | None = None, prompt_name: str | None = None) -> Generator[Span, None, None]
```


Emit or enrich a SERVER span with standard MCP attributes and auth context.

When the current active span is the request's seam span (opened by
`FastMCPServerMiddleware` and marked with `SEAM_SPAN_MARKER`), this sets the
component attributes on that span and yields it *without* starting a second
span — so failures rejected before this point and the successful high-level
call share one richly-attributed SERVER span. Otherwise (non-seam contexts,
e.g. in-process `mcp.call_tool()` calls that bypass the dispatcher) it opens a
new SERVER span as before.

Automatically records any exception on the span and sets error status.

In `propagation_only` mode no span is opened or enriched. The seam has
normally already attached the incoming parent context for this request;
doing it again here is a no-op, and covers the in-process callers that
bypass the dispatcher and so never reach the seam at all.


### `delegate_span` <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/server/telemetry.py#L305" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>

```python
delegate_span(name: str, provider_type: str, component_key: str, method: str | None = None) -> Generator[Span, None, None]
```


Create an INTERNAL span for provider delegation.

Used by FastMCPProvider when delegating to mounted servers.
Automatically records any exception on the span and sets error status.

