# Observability Telemetry is gated on `RA_MCP_OTEL_ENABLED=true`. When enabled, traces, metrics, and logs are exported via OTLP. --- ## Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `RA_MCP_OTEL_ENABLED` | `false` | Master switch | | `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:4317` | Collector endpoint | | `OTEL_EXPORTER_OTLP_PROTOCOL` | `grpc` | `grpc` or `http/protobuf` | | `OTEL_SERVICE_NAME` | `ra-mcp` | Service name (`service.name`) | | `ENVIRONMENT` | _(unset)_ | `deployment.environment.name` resource attribute (falls back to `DEPLOYMENT_ENVIRONMENT`) | | `RA_MCP_OTEL_LOG_BRIDGE` | `true` | Bridge Python logging to OTel | The SDK sets `service.name`, `service.version`, a per-process `service.instance.id`, and — when `ENVIRONMENT` is set — `deployment.environment.name` as resource attributes; `OTEL_RESOURCE_ATTRIBUTES` is merged on top. `service.instance.id` defaults to a fresh UUID per process so replicas are distinguishable (the chart autoscales to several pods). To pin a **stable** per-pod id, set it from the Kubernetes downward API: ```yaml env: - name: POD_NAME valueFrom: { fieldRef: { fieldPath: metadata.name } } - name: OTEL_RESOURCE_ATTRIBUTES value: "service.instance.id=$(POD_NAME)" ``` ## Trace Tree Every MCP tool call produces a trace spanning from the protocol layer down to HTTP: ``` mermaid graph TD A["tools/call search_transcribed\nFastMCP — automatic"] B["delegate search_transcribed\nFastMCP — composed server"] C["tools/call search_transcribed\nFastMCP — provider"] D["SearchOperations.search\ndomain layer"] E["SearchClient.search\nAPI client"] F["HTTP GET\nHTTP client"] A --> B --> C --> D --> E --> F ``` ## Instrumented Components | Component | Tracer name | Spans | Metrics | |-----------|-------------|-------|---------| | HTTP client | `ra_mcp.http_client` | `HTTP GET` | request count, error count, retry count, duration, response size | | Search client | `ra_mcp.search.client` | `SearchClient.search` | — | | Search ops | `ra_mcp.search_operations` | `SearchOperations.search` | `ra_mcp.search.requests`, `ra_mcp.search.results` | | Browse ops | `ra_mcp.browse_operations` | `BrowseOperations.browse_document`, `BrowseOperations._fetch_page_contexts` | `ra_mcp.browse.requests`, `ra_mcp.browse.pages`, `ra_mcp.browse.empty_pages` | | ALTO client | `ra_mcp.alto_client` | `ALTOClient.fetch_content` | `ra_mcp.alto.fetches` | | IIIF client | `ra_mcp.iiif_client` | `IIIFClient.get_collection`, `IIIFClient.fetch_manifest` | — | | OAI-PMH client | `ra_mcp.oai_pmh_client` | `OAIPMHClient.get_metadata`, `OAIPMHClient.extract_manifest_id` | `ra_mcp.oai_pmh.fetches` | | Viewer fetchers | fastmcp tracer (`fetchers.py`) | `fetch_text_layer` | — | | LanceDB spine | `ra_mcp.lancedb` | `search