Skip to main content
Glama

tracehub-mcp

CI codecov PyPI Python 3.11+ License mcpsmiths/tracehub-mcp MCP server M8ven Score

Also listed on the official MCP registry as io.github.mcpsmiths/tracehub-mcp (the registry's own ?search= endpoint can surface an outdated version first; this exact-name endpoint always reflects the current isLatest release).

tracehub-mcp MCP server – quality and maintenance score on Glama

Give your AI assistant a direct line into your observability backend. tracehub-mcp is an MCP (Model Context Protocol) server that lets Claude, Cursor, Windsurf, Gemini CLI, or any MCP client query OpenTelemetry traces from your LLM/GenAI application and reason about them — find expensive calls, debug errors, compare model performance, track token usage — without you copy-pasting trace JSON into a chat window.

It speaks OpenTelemetry's gen_ai.* semantic conventions natively, so it understands prompts, completions, token usage, and finish reasons as first-class concepts, not just generic span attributes.

tracehub-mcp started as a fork of traceloop/opentelemetry-mcp-server (Apache 2.0) — full attribution and fork history are in NOTICE. It's grown into a 5-backend, security-hardened server maintained independently under mcpsmiths; see What's Different From Upstream below for the parts that are new here.


Table of Contents


Related MCP server: otel-instrumentation-mcp

Quick Start

tracehub-mcp is on PyPI. No install step needed — uvx fetches and runs it in one shot:

// claude_desktop_config.json
{
  "mcpServers": {
    "tracehub-mcp": {
      "command": "uvx",
      "args": ["tracehub-mcp"],
      "env": {
        "BACKEND_TYPE": "jaeger",
        "BACKEND_URL": "http://localhost:16686"
      }
    }
  }
}

Or from Claude Code directly:

claude mcp add tracehub-mcp -e BACKEND_TYPE=jaeger -e BACKEND_URL=http://localhost:16686 -- uvx tracehub-mcp

That's it. Ask your assistant: "Show me traces with errors from the last hour."

See MCP Client Setup for Cursor, Windsurf, VS Code, and Gemini CLI, and Installation for pip/pipx/from-source alternatives.


Supported Backends

  • Jaeger — local/self-hosted, the most common open-source trace backend. No auth required.

  • Grafana Tempo — local or Grafana Cloud, TraceQL-native search.

  • Traceloop — cloud LLM observability platform, API-key auth.

  • Datadog — cloud APM, requires an API key and an Application key.

  • Sentry — cloud or self-hosted, requires an auth token and an organization slug.

  • AWS X-Ray — SigV4-signed via boto3, requires an AWS region and standard AWS credentials (not an API key). Because OTel span attributes land in unindexed X-Ray segment metadata by default (only annotations are queryable), native server-side filtering is narrower here than for the other backends — see the Backend Support Matrix.

All six implement the same BaseBackend interface, so every MCP tool works identically regardless of which one you point the server at. See Configuration for per-backend setup.


What's Different From Upstream

Upstream opentelemetry-mcp-server shipped Jaeger, Tempo, and Traceloop. tracehub-mcp adds Datadog and Sentry as full backends — not thin wrappers, but complete implementations of every tool (search, span search, trace hydration, service discovery, health checks). Along the way, all five backends — including the three inherited from upstream — were hardened to a consistent bar:

  • HTTPS-only enforcement on cloud backends. Datadog and Sentry both refuse to start against a plain http:// URL, because their auth is a bearer token / API+App key pair that has no business going out over plaintext.

  • Query-injection-safe escaping. Every value spliced into a Datadog span-search query or a Sentry Discover query is escaped and exact-quoted; field names (which are less obviously untrusted, since they come from the MCP tool's filters parameter) are validated against an allowlist pattern before being spliced into the query string, closing off structural injection through a crafted field name.

  • Bounded pagination on every backend that paginates via cursor (Datadog, Sentry) — a search stops at the requested limit or when the backend stops returning a continuation cursor, whichever comes first, so a single tool call can't degrade into an unbounded crawl.

  • Exact-ID re-verification. Where a backend's search API can return neighbors instead of an exact match (notably Datadog's trace reconstruction from grouped spans), every result is re-checked against the exact ID that was asked for before being returned.

  • No fabricated data on malformed responses, in the backends we built. Datadog and Sentry reject a span outright — rather than substituting a placeholder like now() for a missing timestamp or a literal "unknown" for a missing service_name/operation_name — since a fabricated value would silently corrupt trace ordering, duration aggregation, and any tool that groups by service or operation. (The three backends inherited from upstream — Jaeger, Tempo, Traceloop — predate this discipline and haven't been retrofitted; that's deliberate scope discipline, not an oversight, mirroring this project's own precedent of not reaching into shared/inherited code without full regression coverage for it.)

All of this is backed by 458 passing tests (2 skipped, zero regressions), a clean ruff check and mypy --strict run, and two rounds of adversarial CodeRabbit review on the new backends.


Installation

tracehub-mcp is on PyPI. Pick whichever of these your workflow already uses — they're equivalent.

Option 1: uvx (no install step)

uvx tracehub-mcp --backend jaeger --url http://localhost:16686

This is what the Quick Start config above uses — uv fetches the package and runs the tracehub-mcp entry point in one shot, nothing left behind on disk between runs.

Option 2: pip / pipx

pipx install tracehub-mcp
# or: pip install tracehub-mcp

tracehub-mcp --backend jaeger --url http://localhost:16686

Option 3: Clone and run from source

git clone https://github.com/mcpsmiths/tracehub-mcp.git
cd tracehub-mcp
uv sync

uv run tracehub-mcp --backend jaeger --url http://localhost:16686

Use this if you're developing locally, want to pin to a specific commit, or want the dev tooling installed (uv sync --group dev).

Option 4: Docker

docker run --rm -p 8000:8000 \
  -e BACKEND_TYPE=jaeger -e BACKEND_URL=http://host.docker.internal:16686 \
  ghcr.io/mcpsmiths/tracehub-mcp:latest

Runs HTTP transport by default (the image's CMD); clients connect to http://localhost:8000/mcp. This is also the form to use for MCP clients whose config takes a command/args pair pointing at docker directly (Cursor, Windsurf) instead of a local binary.

Prerequisites: Python 3.11+, plus uv for Options 1 and 3; Docker for Option 4.


Configuration

Configuration comes from environment variables, CLI flags, or both. Precedence: CLI arguments > environment variables > defaults.

# .env (see .env.example)
BACKEND_TYPE=jaeger
BACKEND_URL=http://localhost:16686
# Equivalent via CLI flags
tracehub-mcp --backend jaeger --url http://localhost:16686

All Configuration Options

Variable

Type

Default

Description

BACKEND_TYPE

string

jaeger

Backend type: jaeger, tempo, traceloop, datadog, sentry, or xray

BACKEND_URL

URL

-

Backend API endpoint (required; decorative-only placeholder for X-Ray)

BACKEND_API_KEY

string

-

API key/auth token (required for Traceloop, Datadog, and Sentry; unused by X-Ray)

BACKEND_APP_KEY

string

-

Application key (Datadog only, in addition to BACKEND_API_KEY)

BACKEND_TEMPO_INSTANCE_ID

string

-

Grafana Cloud stack/instance ID (Tempo only, enables Basic Auth in addition to BACKEND_API_KEY)

BACKEND_SENTRY_ORG

string

-

Organization slug (required for Sentry)

BACKEND_SENTRY_PROJECT

string

-

Project slug (optional for Sentry, narrows queries to one project)

BACKEND_AWS_REGION

string

-

AWS region, e.g. us-east-1 (required for X-Ray)

BACKEND_ENVIRONMENTS

string

prd

Comma-separated environments (Traceloop only)

BACKEND_TIMEOUT

float

30

Request timeout in seconds

LOG_LEVEL

string

INFO

Logging level: DEBUG, INFO, WARNING, ERROR (--log-level)

MAX_TRACES_PER_QUERY

integer

500

Server-wide ceiling (1-1000, --max-traces-per-query) - caps every tool's limit argument before it reaches a backend query, regardless of what the calling agent requests

SLOW_REQUEST_THRESHOLD_MS

float

unset

Logs a WARNING for any backend request slower than this, independent of LOG_LEVEL (--slow-request-threshold-ms)

MCP_TRANSPORT / MCP_HOST / MCP_PORT

string/int

stdio/0.0.0.0/8000

Env-var equivalents of --transport/--host/--port

MCP_INCLUDE_ARGS_IN_SPANS

bool

false

Include tool call arguments/results as OTel span attributes when self-instrumentation is enabled below - off by default since they may contain sensitive data. Known credential shapes (Bearer tokens, api_key=/secret=/password=-style fields, AWS/GitHub/common vendor key prefixes) are redacted before export, but this is a pattern match, not a guarantee - trace_id/span_id and other legitimate trace data are deliberately left untouched (--include-args-in-spans)

OTEL_EXPORTER_OTLP_ENDPOINT

URL

unset

Enables opt-in OTel self-instrumentation of tool calls when set; unset means zero overhead (no TracerProvider configured, no middleware registered)

OTEL_SERVICE_NAME

string

tracehub-mcp

Service name reported in self-instrumentation spans

QUERY_CACHE_TTL_SECONDS

float

unset

Cache backend query results (search_traces/search_spans/get_trace/list_services/get_service_operations) for this many seconds, with in-flight request coalescing (unset: disabled, --query-cache-ttl-seconds)

RATE_LIMIT_MAX_REQUESTS

integer

100

HTTP transport only. Max requests per client IP per RATE_LIMIT_WINDOW_SECONDS (--rate-limit-max-requests, set to 0 to disable)

RATE_LIMIT_WINDOW_SECONDS

float

60

HTTP transport only. Fixed window size in seconds for RATE_LIMIT_MAX_REQUESTS (--rate-limit-window-seconds)

SHUTDOWN_DRAIN_SECONDS

float

0.0

HTTP transport only. On shutdown, wait this many seconds inside the ASGI shutdown handler - after uvicorn has already finished draining in-flight connections - before closing the shared backend HTTP client (--shutdown-drain-seconds)

BACKEND_CLOSE_TIMEOUT_SECONDS

float

5.0

HTTP transport only. Abandon closing the shared backend HTTP client during shutdown if it does not finish within this many seconds - uvicorn places no timeout of its own around this wait (--backend-close-timeout-seconds)

GRACEFUL_SHUTDOWN_TIMEOUT_SECONDS

integer

2

HTTP transport only. uvicorn's own bound (whole seconds only) on waiting for in-flight connections/tasks to finish on shutdown before cancelling them (--graceful-shutdown-timeout-seconds)

Every backend-related CLI flag has a matching env var (--backend/BACKEND_TYPE, --url/BACKEND_URL, --api-key/BACKEND_API_KEY, --app-key/BACKEND_APP_KEY, --tempo-instance-id/BACKEND_TEMPO_INSTANCE_ID, --sentry-org/BACKEND_SENTRY_ORG, --sentry-project/BACKEND_SENTRY_PROJECT, --aws-region/BACKEND_AWS_REGION, --environments/BACKEND_ENVIRONMENTS). --disable-tools <name1,name2,...> / --enabled-tools <name1,name2,...> (CLI-only, no env var) remove/allowlist tools for reduced-trust deployments - --enabled-tools is applied first, --disable-tools on top of whatever it kept. Run tracehub-mcp --help for the full list.

Known third-party egress dependency: the underlying FastMCP framework checks PyPI (https://pypi.org/pypi/fastmcp/json) for a newer FastMCP release once every 12 hours when it prints its startup banner - this is FastMCP's own behavior, not tracehub-mcp's, and unrelated to the OTel self-instrumentation above. It fails silently if there's no network access. For network-restricted/air-gapped deployments, disable it with FASTMCP_CHECK_FOR_UPDATES=off, or suppress the banner entirely with FASTMCP_SHOW_SERVER_BANNER=false.

Backend-Specific Setup

BACKEND_TYPE=jaeger
BACKEND_URL=http://localhost:16686

No API key required. search_traces and search_spans_tool both require a service_name parameter — Jaeger's API is optimized for per-service queries, so querying across all services isn't supported. Discover service names first with list_services.

BACKEND_TYPE=tempo
BACKEND_URL=http://localhost:3200

No API key required for a local/self-hosted install. Search uses TraceQL under the hood; service_name is optional.

For Grafana Cloud-hosted Tempo, also set BACKEND_TEMPO_INSTANCE_ID to the stack's instance ID and BACKEND_API_KEY to a Cloud Access Policy token scoped to traces:read — Grafana Cloud requires Basic Auth (instance ID as username, token as password) instead of self-hosted Tempo's Bearer-token auth:

BACKEND_TYPE=tempo
BACKEND_URL=https://tempo-prod-XX-prod-XX-XXXX.grafana.net
BACKEND_TEMPO_INSTANCE_ID=your_stack_instance_id
BACKEND_API_KEY=your_cloud_access_policy_token
BACKEND_TYPE=traceloop
BACKEND_URL=https://api.traceloop.com
BACKEND_API_KEY=your_api_key_here

The API key encodes project information — the backend always uses a project slug of "default", and Traceloop resolves the actual project/environment from the key itself.

BACKEND_TYPE=datadog
# US site (default): https://api.datadoghq.com
# EU site:            https://api.datadoghq.eu
BACKEND_URL=https://api.datadoghq.com
BACKEND_API_KEY=your_api_key_here
BACKEND_APP_KEY=your_application_key_here

Datadog requires both an API key and an Application key — a single key is not enough for span/trace queries, even though ingestion only needs the API key. Trace search uses Datadog's span search query syntax rather than TraceQL or Jaeger-style tag params, and traces are reconstructed from grouped spans since Datadog has no trace-level lookup endpoint. The backend also refuses a plain http:// URL — see What's Different From Upstream.

Troubleshooting: a 403 from the Datadog API almost always means the Application key (not the API key) is missing or invalid. If you're on the EU site, double check BACKEND_URL is https://api.datadoghq.eu, not the US default.

BACKEND_TYPE=sentry
# SaaS (may be region-specific, e.g. https://us.sentry.io):
BACKEND_URL=https://sentry.io
BACKEND_API_KEY=your_auth_token_here
BACKEND_SENTRY_ORG=your-org-slug
# Optional: narrow queries to one project
BACKEND_SENTRY_PROJECT=your-project-slug

Sentry requires both an auth token and an organization slug — every endpoint this backend calls is organization-scoped. Trace search uses Sentry's search syntax against the Discover/Explore Events API. Unlike Datadog, Sentry does have a native trace-lookup endpoint, so get_trace calls it directly instead of reconstructing a trace from spans — search_traces still discovers candidate trace IDs via a span search first, since Sentry's search surface is itself span-centric. Like Datadog, this backend refuses a plain http:// URL.

Troubleshooting: a 403/401 from the Sentry API almost always means the auth token is missing, invalid, or lacks the necessary scopes. A 404 on an org-scoped endpoint usually means the organization slug is wrong. For a self-hosted install, BACKEND_URL should be the install's own base URL, not https://sentry.io. Some of the tracing endpoints this backend depends on are newer/experimental on Sentry's side and may not be available on every plan or self-hosted version — see the module docstring in backends/sentry.py for specifics.

BACKEND_TYPE=xray
# Decorative only - never dereferenced for a live request. Keep it
# consistent with BACKEND_AWS_REGION by convention.
BACKEND_URL=https://xray.us-east-1.amazonaws.com
BACKEND_AWS_REGION=us-east-1

Unlike every other backend here, X-Ray is queried via boto3/SigV4, not a bearer token — auth comes from boto3's standard credential chain (environment variables, ~/.aws/credentials, an assumed role, or an instance/task role). The running process needs xray:GetTraceSummaries, xray:BatchGetTraces, and (optionally, for faster list_services) xray:GetServiceGraph IAM permissions.

Filtering is more limited than the other backends. By default, OpenTelemetry span attributes are converted to X-Ray segment metadata, not annotations — only annotations are indexed and queryable via X-Ray's FilterExpression search syntax. This backend can only natively push down service name, duration, and error/fault/throttle-derived status; every other field (including all gen_ai.* attributes) is always applied client-side after hydrating full traces, unless your own OTel/ADOT collector config explicitly promotes those keys to indexed annotations.

Troubleshooting: an AccessDeniedException from GetServiceGraph is non-fatal — list_services automatically falls back to sampling recent traces. An AccessDeniedException from GetTraceSummaries/BatchGetTraces is fatal for search/hydration and will surface as an unhealthy health_check/doctor result; double check the IAM permissions above.

Transport Modes

# stdio (default) — local use, Claude Desktop, single process
uvx tracehub-mcp
tracehub-mcp                      # pipx/pip install
uv run tracehub-mcp               # from-source install

# HTTP — remote access, multiple clients, network deployment, sample applications
uvx tracehub-mcp --transport http --host 0.0.0.0 --port 8000
tracehub-mcp --transport http --host 0.0.0.0 --port 8000              # pipx/pip install
uv run tracehub-mcp --transport http --host 0.0.0.0 --port 8000       # from-source install

With HTTP transport, clients connect to http://<host>:<port>/mcp (streamable-HTTP, for compatibility across MCP clients).

Fly.io: the one-click fly mcp launch command only supports stdio-transport servers — it can't deploy this server's --transport http mode. Running tracehub-mcp on Fly.io with HTTP transport needs the manual fly.toml + fly deploy path instead.


Diagnostics

Validate a config before wiring it into a real MCP client:

tracehub-mcp doctor --backend jaeger --url http://localhost:16686
[OK] Configuration loaded and validated
[OK] Backend constructed: jaeger @ http://localhost:16686/
[OK] Health check: healthy
[OK] Connectivity probe (list_services): 2 service(s)

doctor accepts the same --backend/--url/etc. flags as the main command and exits non-zero if any step fails - unlike normal server startup, which lazily initializes the backend and deliberately keeps running even if the initial health check fails.

To see the fully-resolved configuration (env vars + CLI overrides merged) without starting the server:

tracehub-mcp --print-config --backend jaeger --url http://localhost:16686

Secrets (--api-key/--app-key) are reported as api_key_set/app_key_set booleans, never their actual value.


Security Considerations

Trace and span data returned by this server — attribute values, error messages, operation names — comes from whatever application your observability backend is instrumenting, not from tracehub-mcp itself. That makes it fundamentally the same category of untrusted external content as a webpage or a file, even though it's a trusted server (this one) handing it back to your MCP client.

  • Treat backend data as untrusted input. An LLM client consuming trace/span data from tracehub-mcp should apply the same caution it would to any other external tool output — a span attribute or error message is application data to reason about, not an instruction to follow, no matter how it's phrased.

  • This is a known MCP risk category, not a tracehub-mcp-specific one. OWASP's GenAI Security Project covers it in their Practical Guide for Secure MCP Server Development, and Anthropic's own engineering guidance, How We Contain Claude, states plainly that tool output is an attack surface even when the tool itself is trusted.

  • Practical implication: if you're querying traces from an application that processes untrusted user input (e.g. a customer-facing chatbot), be aware that adversarial content a user fed into that application could end up in a span attribute this server returns — and from there, in your LLM client's context.


Privacy Policy

tracehub-mcp is self-hosted software with no maintainer-operated service or account — it collects no data of its own. See PRIVACY.md for the full policy: what data the software touches, where network calls go, and how secrets and self-instrumentation are handled.


MCP Client Setup

Every example below uses uvx tracehub-mcp (no install step). Swap in tracehub-mcp (pip/pipx install) or uv run tracehub-mcp (from-source, --directory /absolute/path/to/tracehub-mcp) if you installed it a different way — see Installation.

Config file location:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Jaeger (no auth):

{
  "mcpServers": {
    "tracehub-mcp": {
      "command": "uvx",
      "args": ["tracehub-mcp"],
      "env": {
        "BACKEND_TYPE": "jaeger",
        "BACKEND_URL": "http://localhost:16686"
      }
    }
  }
}

Datadog (API key + App key):

{
  "mcpServers": {
    "tracehub-mcp": {
      "command": "uvx",
      "args": ["tracehub-mcp"],
      "env": {
        "BACKEND_TYPE": "datadog",
        "BACKEND_URL": "https://api.datadoghq.com",
        "BACKEND_API_KEY": "your_api_key_here",
        "BACKEND_APP_KEY": "your_application_key_here"
      }
    }
  }
}

Sentry (auth token + org slug):

{
  "mcpServers": {
    "tracehub-mcp": {
      "command": "uvx",
      "args": ["tracehub-mcp"],
      "env": {
        "BACKEND_TYPE": "sentry",
        "BACKEND_URL": "https://sentry.io",
        "BACKEND_API_KEY": "your_auth_token_here",
        "BACKEND_SENTRY_ORG": "your-org-slug"
      }
    }
  }
}

If you're running from a clone instead, the bundled wrapper script gives easy backend switching during local dev:

{
  "mcpServers": {
    "tracehub-mcp": {
      "command": "/absolute/path/to/tracehub-mcp/start_locally.sh"
    }
  }
}

(the script ships Jaeger/Traceloop/Tempo blocks only, with Jaeger active by default — to switch, comment out the active block and uncomment the one you want; Datadog/Sentry aren't in the script, so add their export lines manually).

claude mcp add tracehub-mcp -e BACKEND_TYPE=jaeger -e BACKEND_URL=http://localhost:16686 -- uvx tracehub-mcp

Datadog/Sentry work the same way — add more -e KEY=value flags for each backend's required env vars (see Backend-Specific Setup). Then:

claude mcp list
claude "Show me traces with errors from the last hour"

.cursor/mcp.json (project-level) or your global Cursor MCP config:

{
  "mcpServers": {
    "tracehub-mcp": {
      "command": "uvx",
      "args": ["tracehub-mcp"],
      "env": {
        "BACKEND_TYPE": "jaeger",
        "BACKEND_URL": "http://localhost:16686"
      }
    }
  }
}

~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "tracehub-mcp": {
      "command": "uvx",
      "args": ["tracehub-mcp"],
      "env": {
        "BACKEND_TYPE": "jaeger",
        "BACKEND_URL": "http://localhost:16686"
      }
    }
  }
}

.vscode/mcp.json in your workspace — note the top-level key is servers, not mcpServers, and stdio servers need no "type" field:

{
  "servers": {
    "tracehub-mcp": {
      "command": "uvx",
      "args": ["tracehub-mcp"],
      "env": {
        "BACKEND_TYPE": "jaeger",
        "BACKEND_URL": "http://localhost:16686"
      }
    }
  }
}

Config file: ~/.gemini/config.json, same JSON shape as Claude Desktop above. Then:

gemini "Analyze token usage for gpt-4 requests today"

Tools Reference

tracehub-mcp exposes 17 MCP tools:

Tool

Description

Use Case

search_traces

Search traces with simple params or advanced filters

Find specific requests or patterns

search_spans_tool

Search individual spans (not grouped into traces)

Find LLM tool calls, specific ops

get_trace

Get complete trace details by trace ID

Deep-dive into a single trace

get_llm_usage

Aggregate token usage metrics

Track costs and usage trends

list_services

List available services

Discover what's instrumented

find_errors

Find traces with errors

Debug failures quickly

list_llm_models

Discover models in use, with usage stats

Track model adoption, shadow AI

get_llm_model_stats

Latency/token percentiles + finish reasons for one model

Compare model efficiency

get_llm_expensive_traces

Find highest token-usage traces

Cost optimization

get_llm_slow_traces

Find slowest traces by duration

Latency debugging

list_llm_tools_tool

Discover LLM tool/function calls (traceloop.span.kind == tool)

Track agent tool usage

list_sessions

Group spans by gen_ai.conversation.id

Understand multi-turn conversation activity

get_session_stats

Detailed stats for one conversation ID

Drill into a single conversation

compare_time_windows

Diff aggregated usage between two time ranges

"This week vs last week" comparisons

investigate_cost_spike

Compare cost between a recent window and a baseline, ranked by model/service

"Why did our LLM bill spike?"

investigate_error_spike

Compare error rate between a recent window and a baseline, ranked by service/model/error type

"Is this error increase a real spike?"

get_prompt_version_stats

Group spans by gen_ai.prompt.name/.version

Compare prompt versions before promoting one

Backend Support Matrix

Feature

Jaeger

Tempo

Traceloop

Datadog

Sentry

AWS X-Ray

Search traces

✓†

✓‡

✓†

Search spans

*

✓†

Get trace by ID

✓†

Advanced filters

✓§

Error traces

All LLM tools

* Jaeger requires the service_name parameter for span search. † Datadog and AWS X-Ray have no trace-level search API (X-Ray's BatchGetTraces fetches by exact ID); traces are reconstructed by searching (spans, or X-Ray trace summaries) and hydrating, with every result re-verified against the exact ID requested. ‡ Sentry does have a native trace-lookup endpoint (unlike Datadog), so get_trace calls it directly; search_traces still discovers candidate trace IDs via a span search first, since Sentry's search surface is itself span-centric. § AWS X-Ray natively filters only service name, duration, and error/fault/throttle-derived status — OTel attributes (including all gen_ai.* fields) land in unindexed segment metadata by default, not indexed annotations, so they're always applied client-side rather than pushed down to FilterExpression.

Key Tool Details

search_traces

{
  "service_name": "my-app",
  "start_time": "2024-01-01T00:00:00Z",
  "end_time": "2024-01-01T23:59:59Z",
  "gen_ai_system": "openai",
  "gen_ai_request_model": "gpt-4",
  "min_duration_ms": 1000,
  "has_error": false,
  "limit": 50
}

Parameters: service_name, operation_name, start_time/end_time (ISO 8601), min_duration_ms/max_duration_ms, gen_ai_system, gen_ai_request_model, gen_ai_response_model, has_error, tags, filters (see Generic Filter System), limit (1-1000, default 100). Returns trace summaries with token counts.

get_trace

{ "trace_id": "abc123def456" }

Returns the full trace tree: all spans with attributes, parsed OpenTelemetry gen_ai.* data for LLM spans, per-span token usage, error information, and each span's raw events (e.g. gen_ai.evaluation.result, or any other instrumentation-emitted event — not filtered to a fixed set of names).

get_llm_usage

{
  "start_time": "2024-01-01T00:00:00Z",
  "end_time": "2024-01-01T23:59:59Z",
  "service_name": "my-app",
  "gen_ai_system": "openai",
  "limit": 1000
}

Returns aggregated prompt/completion/total tokens, broken down by model and by service, plus request counts.

list_services — no parameters. Returns the list of instrumented service names.

find_errors

{
  "start_time": "2024-01-15T14:00:00Z",
  "service_name": "my-app",
  "limit": 50
}

Returns error messages, error types, truncated stack traces, and LLM-specific error info.

list_llm_models / get_llm_model_stats / get_llm_expensive_traces / get_llm_slow_traces / list_llm_tools_tool / search_spans_tool / list_sessions / get_session_stats / compare_time_windows / investigate_cost_spike / investigate_error_spike / get_prompt_version_stats are documented in detail, with worked examples, in CLAUDE.md — this README covers the shape every tool shares; CLAUDE.md is the fuller reference for exact parameters and response fields on the LLM-analysis tools.


Generic Filter System

search_traces and search_spans_tool both accept a filters list in addition to (or instead of) their simple named parameters, for advanced queries. Each filter is:

{
  "field": "gen_ai.usage.total_tokens",
  "operator": "gt",
  "value": 5000,
  "value_type": "number"
}
  • field — dotted attribute name, e.g. gen_ai.usage.prompt_tokens, traceloop.span.kind, service.name

  • operator — see table below

  • value — single value (most operators) or values — list (for in, not_in, between)

  • value_type"string", "number", or "boolean"

Category

Operators

String

equals, not_equals, contains, not_contains, starts_with, ends_with, in, not_in

Number

equals, not_equals, gt, lt, gte, lte, between, in, not_in

Boolean

equals, not_equals

Existence

exists, not_exists (no value needed)

Multiple filters combine with AND logic. Legacy simple parameters (service_name, gen_ai_request_model, etc.) still work and are converted to filters internally — mix and match freely.

The server uses a hybrid filtering strategy: filters are pushed to the backend's native query language when supported (TraceQL for Tempo, span-search syntax for Datadog, Discover syntax for Sentry), and applied client-side afterward for anything the backend can't express natively.

Backend

Native filter support

Notes

Tempo (TraceQL)

equals, not_equals, gt, lt, gte, lte, contains (regex), in (OR), exists, not_exists

Traceloop

equals, not_equals, gt, lt, gte, lte

Datadog

Most operators via span-search syntax

Field names validated against an allowlist before being spliced into the query

Sentry

Most operators via Discover search syntax

Same field-name allowlisting as Datadog

Jaeger

equals (via tags only)

Requires service_name

Example — expensive OpenAI traces:

{
  "filters": [
    { "field": "gen_ai.system", "operator": "equals", "value": "openai", "value_type": "string" },
    { "field": "gen_ai.usage.total_tokens", "operator": "gt", "value": 5000, "value_type": "number" }
  ]
}

For the full semantic-convention attribute list (gen_ai.* vs legacy llm.*, token-naming variants across providers, finish-reason values, and the token-calculation fallback chain), see CLAUDE.md.


Example Queries

Find Expensive OpenAI Operations

Ask: "Show me OpenAI traces from the last hour that took longer than 5 seconds"

Tool call: search_traces

{
  "service_name": "my-app",
  "gen_ai_system": "openai",
  "min_duration_ms": 5000,
  "start_time": "2024-01-15T10:00:00Z",
  "limit": 20
}

Response:

{
  "traces": [
    {
      "trace_id": "abc123...",
      "service_name": "my-app",
      "operation_name": "chat.completions",
      "status": "OK",
      "duration_ms": 8250,
      "span_count": 3,
      "llm_span_count": 1,
      "total_tokens": 4523,
      "has_errors": false
    }
  ],
  "count": 1
}

Analyze Token Usage by Model

Ask: "How many tokens did we use for each model today?"

Tool call: get_llm_usage

{
  "start_time": "2024-01-15T00:00:00Z",
  "end_time": "2024-01-15T23:59:59Z",
  "service_name": "my-app"
}

Response:

{
  "period": { "start_time": "2024-01-15T00:00:00Z", "end_time": "2024-01-15T23:59:59Z" },
  "filters": { "service_name": "my-app" },
  "summary": {
    "total_requests": 487,
    "total_prompt_tokens": 82140,
    "total_completion_tokens": 43290,
    "total_tokens": 125430
  },
  "by_model": {
    "gpt-4": { "requests": 156, "prompt_tokens": 58300, "completion_tokens": 26900, "total_tokens": 85200 },
    "gpt-3.5-turbo": { "requests": 331, "prompt_tokens": 23840, "completion_tokens": 16390, "total_tokens": 40230 }
  },
  "by_service": {
    "my-app": { "requests": 487, "prompt_tokens": 82140, "completion_tokens": 43290, "total_tokens": 125430 }
  }
}

Find Traces with Errors

Ask: "Show me all errors from the last hour"

Tool call: find_errors

{
  "start_time": "2024-01-15T14:00:00Z",
  "service_name": "my-app",
  "limit": 10
}

Response:

{
  "count": 1,
  "error_traces": [
    {
      "trace_id": "def456...",
      "service_name": "my-app",
      "operation_name": "chat.completions",
      "start_time": "2024-01-15T14:23:15Z",
      "duration_ms": 1200,
      "status": "ERROR",
      "span_count": 2,
      "llm_span_count": 1,
      "total_tokens": 310,
      "has_errors": true,
      "error_spans": [
        {
          "span_id": "span789...",
          "operation_name": "chat.completions",
          "service_name": "my-app",
          "status": "ERROR",
          "error_message": "RateLimitError: Too many requests",
          "error_type": "openai.error.RateLimitError",
          "is_llm_error": true,
          "llm_provider": "openai",
          "llm_model": "gpt-4"
        }
      ]
    }
  ]
}

Compare Model Performance

Ask: "What's the performance difference between GPT-4 and Claude?"

Tool call 1: get_llm_model_stats for gpt-4

{ "model_name": "gpt-4", "start_time": "2024-01-15T00:00:00Z" }

Tool call 2: get_llm_model_stats for claude-3-opus

{ "model_name": "claude-3-opus-20240229", "start_time": "2024-01-15T00:00:00Z" }

Investigate High Token Usage

Ask: "Which requests used the most tokens today?"

Tool call: get_llm_expensive_traces

{ "limit": 10, "start_time": "2024-01-15T00:00:00Z", "min_tokens": 5000 }

Common Workflows

Cost Optimization

  1. get_llm_expensive_traces — find the highest-token requests

  2. get_llm_usage — see which models are costing the most

  3. get_trace on a specific trace_id — inspect the exact prompt/response

Performance Debugging

  1. get_llm_slow_traces — identify latency outliers

  2. find_errors — check for failure patterns

  3. get_llm_model_stats — check finish-reason distribution for truncation

Model Adoption Tracking

  1. list_llm_models — see every model actually being called

  2. get_llm_model_stats per model — compare performance

  3. Scan list_llm_models results for unexpected models/services (shadow AI)


Development

git clone https://github.com/mcpsmiths/tracehub-mcp.git
cd tracehub-mcp
uv sync --group dev   # pulls in pytest, mypy, ruff, etc. for local iteration

# Tests (458 passed, 2 skipped at time of writing)
uv run pytest

# With coverage
uv run pytest --cov=opentelemetry_mcp --cov-report=html

# Format, lint, type-check
uv run ruff format .
uv run ruff check .
uv run mypy src/

CI (.github/workflows/ci.yml) runs Ruff and mypy (strict) on every push, plus the full pytest suite.


Troubleshooting

Backend connection issues:

curl http://localhost:16686/api/services   # Jaeger
curl http://localhost:3200/api/search/tags  # Tempo

Authentication errors: confirm your key is set —

export BACKEND_API_KEY=your_key_here
# or: tracehub-mcp --api-key your_key_here

No traces found:

  • Check the time range (use recent timestamps)

  • Verify service names with list_services

  • Try searching without filters first

Token usage shows zero:

  • Confirm your traces have OpenTelemetry gen_ai.* (or legacy llm.*) instrumentation

  • Inspect raw span attributes with get_trace

Datadog/Sentry-specific issues: see the troubleshooting notes under each backend in Configuration.


Roadmap

Two ideas are deliberately not built yet — they're being deferred until they get real usage feedback against the six backends already shipped, rather than guessed at up front:

  • Cross-backend correlation — querying multiple configured backends in a single call and correlating results across them (e.g. a Datadog trace and its downstream Sentry error, joined).

  • Agent-native triage — tools that flag a likely root cause rather than just returning raw trace data, so an agent can act on a diagnosis instead of re-deriving one from a trace dump every time.

Beyond that, the next backends under research (in order, not yet started): New Relic, Honeycomb. (Grafana Cloud is not on this list — it already ships today via Tempo's Basic Auth path; see Grafana Tempo above.)

Carried over from upstream's older roadmap, re-prioritized behind the above rather than dropped: a dedicated model-vs-model comparison tool (today's get_llm_model_stats and compare_time_windows cover per-model stats and time-window diffing separately, but not a single tool that diffs two specific models directly), broader prompt-pattern analysis across templates rather than just version-over-version for one prompt (get_prompt_version_stats already covers the latter), MCP resources for common queries, and SigNoz/ClickHouse backend support. Cost calculation with built-in pricing tables and a query-result caching layer are shipped, not pending: every usage-reporting tool (e.g. investigate_cost_spike in the Tools Reference) returns a cost_usd/cost_usd_is_partial pair backed by a vendored litellm pricing table (src/opentelemetry_mcp/pricing/), and query results are cached with in-flight request coalescing via the QUERY_CACHE_TTL_SECONDS env var (see the configuration table above).

Everything else documented elsewhere in this README is shipped.


Contributing

Contributions are welcome. Before opening a PR, make sure:

  1. All tests pass: uv run pytest

  2. Code is formatted: uv run ruff format .

  3. No linting errors: uv run ruff check .

  4. Type checking passes: uv run mypy src/

License

Apache License 2.0 — see LICENSE. This project is a fork of traceloop/opentelemetry-mcp-server; full attribution and the fork relationship are documented in NOTICE.

Support

Available Tools

17 tools
compare_time_windowsCompare Time WindowsA
Read-onlyIdempotent

Compare aggregated LLM usage metrics between two time windows.

Runs the same usage aggregation for both ranges and returns the delta - useful for "this week vs last week" or "before/after a deploy" style comparisons of request/token counts.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of traces to analyze per range (default: 1000)
range_a_endNoRange A end time in ISO 8601 format
range_b_endNoRange B end time in ISO 8601 format
service_nameNoFilter by service name (applied to both ranges)
gen_ai_systemNoFilter by LLM provider (applied to both ranges)
range_a_startNoRange A start time in ISO 8601 format
range_b_startNoRange B start time in ISO 8601 format
gen_ai_request_modelNoFilter by requested model name (applied to both ranges)
gen_ai_response_modelNoFilter by actual model used (applied to both ranges)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish the tool as read-only, idempotent, and non-destructive. The description adds the key behavioral fact that both ranges run through the same aggregation and the result is a delta. It leaves default behavior for null range boundaries unspecified, but it still meaningfully exceeds what annotations alone convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded: it states the purpose first, then the mechanics, then concrete use cases. Every sentence earns its place with no redundant filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 9 optional parameters, and the description does not specify the sign/direction of the delta (range A minus range B vs. range B minus range A) or what happens when range boundaries are left null. The schema and output schema cover structure, but these ambiguities could prevent a correct first call.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description reinforces that the same aggregation is applied to both ranges and that filters apply to both, but it adds no parameter-level detail beyond what the schema already documents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Compare aggregated LLM usage metrics between two time windows.' It also names the unique outcome, returning a delta, which clearly differentiates it from single-window siblings like get_llm_usage.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives concrete use cases: 'this week vs last week' and 'before/after a deploy.' It does not explicitly name alternative tools or state when not to use this tool, but the provided context is clear enough for an agent to select it appropriately.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_errorsFind ErrorsB
Read-onlyIdempotent

Find traces with errors.

Including detailed error messages, stack traces, and LLM-specific error information.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum error traces to return (default: 100)
end_timeNoEnd time in ISO 8601 format
start_timeNoStart time in ISO 8601 format
service_nameNoFilter by service name

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the read-only, idempotent, non-destructive profile, so the safety burden is met. The description adds that results include detailed error content and LLM-specific information, but it does not describe how errors are selected, whether the output is sorted, or how the time-range and service filters interact with error detection.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short, front-loaded with the main action, and its second sentence provides useful detail. It avoids fluff, though it could have used one sentence to clarify its relationship with similar sibling tools.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a full output schema, rich annotations, and fully documented parameters, the core calling context is covered. However, the description is incomplete in guiding an agent through the large sibling set, especially when search_traces and error-specific investigation tools exist.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and each parameter already has a meaningful description and default value. The tool description adds no parameter-level information beyond indicating that the returned traces contain error details, so the baseline score of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool finds traces with errors and lists what is included (error messages, stack traces, LLM-specific information). This gives it a distinct purpose relative to the generic search_traces sibling, though it does not explicitly name a sibling for comparison.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is given about when to use this tool versus search_traces, investigate_error_spike, or get_trace. The intended usage is only implied by the tool's name and brief description.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_llm_expensive_tracesGet LLM Expensive TracesA
Read-onlyIdempotent

Find traces with highest LLM token usage.

Useful for cost optimization and identifying inefficient prompts.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of traces to return (default: 10)
end_timeNoEnd time in ISO 8601 format
min_tokensNoMinimum token count threshold (only return traces above this)
start_timeNoStart time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)
service_nameNoFilter by service name
gen_ai_request_modelNoFilter by requested model name (e.g., "gpt-4")
gen_ai_response_modelNoFilter by actual model used (e.g., "gpt-4-0613")

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, and non-destructive behavior, so the description's main job is to clarify semantics. It does that by specifying that 'expensive' means token usage rather than monetary cost, and it implies descending ordering by token count. It doesn't discuss pagination or limits, but the output schema and parameter defaults cover much of that.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two short sentences with the core operation front-loaded and the use case immediately after. There is no filler, repetition of schema details, or irrelevant context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and annotations covering safety and idempotency, the description plus structured data give an agent what it needs to call the tool correctly. It adds the essential ranking-by-token-usage context and intended use cases; minor details like default limit are already captured in the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and every parameter already has type, default, and filter semantics documented. The description itself adds no parameter-level information, so it provides no value beyond the schema, which makes the baseline 3 appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Find traces with highest LLM token usage,' which names a specific verb, resource, and ranking criterion. This clearly distinguishes the tool from latency-oriented siblings like get_llm_slow_traces and from generic trace/search tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says it is 'Useful for cost optimization and identifying inefficient prompts,' giving clear intended usage contexts. It does not explicitly name alternatives or exclusion conditions, but the use case guidance is strong enough for an agent to decide when to invoke this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_llm_model_statsGet LLM Model StatsA
Read-onlyIdempotent

Get detailed performance statistics for a specific LLM model.

Analyzes request count, latency percentiles (p50, p95, p99), token usage statistics, error rates, and finish reason distributions.

ParametersJSON Schema
NameRequiredDescriptionDefault
end_timeNoEnd time in ISO 8601 format
model_nameYesModel name to analyze (e.g., "gpt-4", "claude-3-opus", "gpt-3.5-turbo")
start_timeNoStart time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)
service_nameNoFilter by service name

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds the specific metrics analyzed, which is useful behavioral context. However, it doesn't disclose aggregation behavior, time window defaults, or whether results are grouped, which would add value beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded with the core purpose, followed by a compact list of metrics. The two-sentence structure is efficient, though the second sentence is a list that could arguably be more integrated. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only stats tool with full schema coverage and an output schema, the description is largely complete. It covers what the tool does and what metrics it returns. It could be more complete with explicit time-window behavior or grouping semantics, but the annotations and schema cover the essential context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters. The description adds the model_name example and metric context, but doesn't add meaning beyond the schema for start_time, end_time, or service_name. Baseline 3 is appropriate when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: getting detailed performance statistics for a specific LLM model, and enumerates the specific metrics (request count, latency percentiles, token usage, error rates, finish reason distributions). This distinguishes it from siblings like get_llm_usage (usage-focused) and get_llm_slow_traces (trace-focused).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage context (analyzing a specific model's performance) but does not explicitly state when to use this tool versus alternatives like get_llm_usage, get_session_stats, or get_llm_slow_traces. The sibling list provides context, but the description itself lacks explicit routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_llm_slow_tracesGet LLM Slow TracesA
Read-onlyIdempotent

Find slowest LLM traces by duration.

Useful for performance optimization and identifying latency bottlenecks.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of traces to return (default: 10)
end_timeNoEnd time in ISO 8601 format
start_timeNoStart time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)
service_nameNoFilter by service name
min_duration_msNoMinimum duration threshold in milliseconds (only return traces above this)
gen_ai_request_modelNoFilter by requested model name (e.g., "gpt-4")
gen_ai_response_modelNoFilter by actual model used (e.g., "gpt-4-0613")

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds 'slowest ... by duration' which implies an ordering behavior not present in annotations, but it stops short of explaining sorting direction, default time windows, or other behavioral details.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short and front-loaded: the first sentence states the core purpose, and the second provides practical context. Both sentences earn their place, though the second sentence is somewhat generic and could be more specific about the tool's differentiating value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has 7 optional parameters, a full schema, output schema, and annotations that cover read-only behavior. The description, while brief, is sufficient for an agent to understand the tool's primary function and call it correctly. The main missing piece is differentiation from similar siblings, but that is more of a usage-guidelines gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter is already documented. The description adds no additional meaning about parameters such as time filtering, service_name, or model filters; it only refers to duration generally. Baseline 3 is appropriate given the rich schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb ('Find'), resource ('LLM traces'), and criterion ('by duration', 'slowest'). It is unambiguous about what the tool does, but it does not explicitly contrast with close siblings like get_llm_expensive_traces or search_traces, so it falls short of full sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a general use case ('performance optimization and identifying latency bottlenecks') which implies when the tool is useful, but it does not explicitly state when to use it versus alternatives or provide exclusions. No alternative tools are named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_llm_usageGet LLM UsageB
Read-onlyIdempotent

Get aggregated LLM usage metrics (token counts) for a time period.

Provides breakdowns by model and service.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum traces to analyze (default: 1000)
end_timeNoEnd time in ISO 8601 format
start_timeNoStart time in ISO 8601 format
service_nameNoFilter by service name
gen_ai_systemNoFilter by LLM provider
gen_ai_request_modelNoFilter by requested model name
gen_ai_response_modelNoFilter by actual model used

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so the safety profile is covered. The description adds the time-period aggregation and breakdown context, which is useful, but does not disclose any additional behavioral traits such as how limit affects aggregation or whether empty time ranges return empty results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler. The core action and scope are front-loaded, and the breakdown mention is the only supporting detail—every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a full input schema, rich annotations, and an output schema, the structured context covers invocation details well. The description is sufficient for a simple read-only aggregation tool, though it would be stronger with an explicit pointer to the closest sibling tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all seven parameters are already documented in the schema. The description's mention of time period and breakdowns does not add meaningful parameter detail beyond what the schema provides, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Get aggregated LLM usage metrics'), the resource ('token counts'), and the time-period scope, and adds that breakdowns by model and service are included. It is specific enough to distinguish it from trace-level siblings like get_llm_expensive_traces, though it does not explicitly contrast it with get_llm_model_stats.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no guidance on when to use this tool versus the many sibling tools, no exclusions, and no alternative recommendations. With siblings like get_llm_model_stats and get_llm_expensive_traces, the agent is left to infer the intended use case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_prompt_version_statsGet Prompt Version StatsA
Read-onlyIdempotent

Get aggregated performance stats grouped by prompt name and version.

Groups spans by gen_ai.prompt.name + gen_ai.prompt.version, mirroring Langfuse's shipped per-prompt Metrics tab. Real-world adoption of these two attributes is still thin, so this tool may often return an empty list until more instrumentations populate them.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum spans to analyze (default: 1000)
end_timeNoEnd time in ISO 8601 format
start_timeNoStart time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)
service_nameNoFilter by service name
gen_ai_systemNoFilter by LLM provider (openai, anthropic, etc.)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and non-destructive behavior, so the bar for description-added context is lower. The description adds valuable behavioral disclosure by warning that 'real-world adoption of these two attributes is still thin' and that the tool 'may often return an empty list until more instrumentations populate them.'

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three short sentences with no filler. The core action is front-loaded, the grouping detail is explained precisely, and the sparse-adoption caveat earns its place as important operational guidance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With a full input schema, an output schema, and safety-related annotations, the description covers the essentials. It also supplies the non-obvious expectation about possible empty results. The only missing context is explicit guidance on when to choose this tool over sibling stats tools, which is not strictly necessary for invoking it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the input schema already documents all five parameters. The description adds no additional parameter-level semantics beyond the grouping concept, so the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Get aggregated performance stats grouped by prompt name and version.' It also reinforces the grouping by naming the concrete span attributes and referencing Langfuse's per-prompt Metrics tab. It does not explicitly distinguish itself from sibling tools, but the grouping and naming make its purpose clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool through the Langfuse per-prompt Metrics analogy and the caveat about sparse adoption. However, it never explicitly states when to prefer this tool over alternatives like get_llm_model_stats or get_session_stats, nor does it mention any exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_session_statsGet Session StatsA
Read-onlyIdempotent

Get detailed statistics for a single conversation/session.

Analyzes span count, distinct services, time bounds, LLM request/success/ error counts, latency percentiles, and token usage for every span sharing the given gen_ai.conversation.id.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum spans to analyze (default: 1000)
end_timeNoEnd time in ISO 8601 format
start_timeNoStart time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)
service_nameNoFilter by service name
conversation_idYesThe gen_ai.conversation.id to analyze

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempoten, and non-destructive behavior, and the description does not contradict them. The description adds useful behavioral detail: it aggregates over every span sharing the conversation ID and lists the statistical categories it produces.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The first sentence is a crisp front-loaded summary, and the second paragraph is a dense but relevant enumeration of the computed metrics. There is no filler or repetition of schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Combined with the full input schema, output schema, and annotations, the description covers scope, filtering, and the metrics computed. An agent can invoke it with just conversation_id and know what is included; no critical behavior is omitted.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and every paramter already has a clear description. The tool description adds no extra parameter-level detail, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb-plus-resource pattern ('Get detailed statistics for a single conversation/session') and then lists the exact computed metrics. This clearly differentiates it from sibling search/list/compare tools, which operate over multiple sessions or traces.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear scope: one conversation/session identified by gen_ai.conversation.id. It doesn't explicitly name alternatives or state when-not-to-use, but the single-session framing and metric detail tell an agent when this is the right tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_traceGet TraceA
Read-onlyIdempotent

Get complete trace details by trace ID.

Returns all spans with attributes, including parsed Opentelemetry data for LLM operations.

ParametersJSON Schema
NameRequiredDescriptionDefault
trace_idYesTrace identifier
detail_levelNo"full" (default) returns every attribute/event value in full, unchanged from this tool's original behavior. "summary" elides known-large gen_ai.* fields (input/output messages, system instructions, retrieval documents) and truncates long event-attribute values, for callers that don't need full prompt/completion bodies.full

Output Schema

ParametersJSON Schema
NameRequiredDescription
spansYes
statusYes
trace_idYes
has_errorsYes
span_countYes
start_timeYes
duration_msYes
llm_summaryNo
detail_levelYes
service_nameYes
root_operationYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds genuine behavioral context beyond annotations: it promises 'all spans with attributes,' flags parsed OTLP LLM data as included, and — via the detail_level parameter — discloses that 'full' retains original behavior while 'summary' elides known-large gen_ai.* fields (input/output messages, system instructions, retrieval documents) and truncates long event-attribute values. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two front-loaded sentences carry the entire tool purpose with zero filler: the primary action comes first, followed by a single sentence detailing return richness. The detail_level parameter text is longer but every clause earns its place by explaining behavioral consequences (elision targets and truncation behavior). Nothing is redundant with the input schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a point-lookup tool with a full output schema, safety annotations, and 100% schema coverage, the description is nearly complete: it states what is returned, mentions OTLP data specifically, and the detail_level parameter explains the only behavioral switch. The one gap is that it does not explicitly route the agent to search_traces for trace discovery when an ID is not known, but this is a minor omission given the tool's straightforward name and signature.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both trace_id and detail_level thoroughly. The description adds no format or syntax detail for trace_id beyond 'by trace ID,' and the detail_level parameter description in the schema is already rich. With full schema coverage, the baseline of 3 is appropriate; the description gestures at the parameter's purpose but does not materially extend it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Get complete trace details by trace ID') and clarifies the return content ('all spans with attributes, including parsed Opentelemetry data for LLM operations'). The 'by trace ID' framing makes this a point-lookup tool, clearly distinct from siblings like search_traces and get_llm_usage. The 'complete... all spans' language positions it precisely against the search/list siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage context is implied rather than explicit: the agent can infer 'use this when you already have a trace ID and want full details,' but the description never says when not to use it or names an alternative such as search_traces for discovery. The detail_level parameter does provide conditional guidance ('for callers that don't need full prompt/completion bodies'), which earns partial credit, but no explicit when/when-not routing exists.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

investigate_cost_spikeInvestigate Cost SpikeA
Read-onlyIdempotent

Investigate an LLM cost spike: compare a recent window against a baseline and rank which models/services contributed most to the change.

On-request/pull-based analysis, not a push alert - mirrors SigNoz's own "investigate telemetry cost" skill. Call this when you suspect (or want to check for) a cost increase, rather than polling get_llm_usage by hand.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of traces to analyze per window (default: 1000)
top_nNoMaximum ranked contributors to return per breakdown (default: 5, max: 50)
recent_endYesRecent window end time in ISO 8601 format
baseline_endNoBaseline window end (ISO 8601)
recent_startYesRecent window start time in ISO 8601 format
service_nameNoFilter by service name (applied to both windows)
gen_ai_systemNoFilter by LLM provider (applied to both windows)
baseline_startNoBaseline window start (ISO 8601). If omitted along with baseline_end, auto-computed as the same duration immediately preceding recent_start.
gen_ai_request_modelNoFilter by requested model name (applied to both windows)
gen_ai_response_modelNoFilter by actual model used (applied to both windows)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, and non-destructive behavior, so the lower bar is appropriate. The description adds meaningful behavioral context beyond annotations: it is on-request/pull-based, not a push alert, and it performs a comparative analysis rather than a simple fetch. It does not discuss rate limits or auth, but nothing in the context suggests those are needed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two compact sentences with the core purpose front-loaded. The second sentence earns its place by giving invocation guidance and an explicit alternative. There is no redundancy or filler; even the SigNoz reference is a brief provenance cue that helps an agent recognize the expected behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and full parameter documentation in the input schema, the description does not need to restate return values or syntax. It provides the selection context, the pull-based behavior, and the trigger condition. It could more explicitly differentiate from compare_time_windows, but that is a minor gap given the strength of the structured fields.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% parameter description coverage, so the baseline is 3. The description adds a useful high-level framing of comparing windows and ranking contributors, but it does not add parameter-level detail beyond what the schema already provides. That is acceptable because the schema carries the load here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific task (investigate an LLM cost spike), a concrete method (compare recent window against a baseline), and a distinct output (ranked contributors). It clearly separates itself from raw usage polling via get_llm_usage and from error-focused investigation via investigate_error_spike.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit trigger condition: 'Call this when you suspect (or want to check for) a cost increase'. It also names the alternative approach it replaces ('rather than polling get_llm_usage by hand') and clarifies it is pull-based, not a push alert, so an agent knows when it is appropriate to invoke.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

investigate_error_spikeInvestigate Error SpikeA
Read-onlyIdempotent

Investigate an error-rate spike: compare a recent window against a baseline and rank which services/models/error types contributed most.

is_spike requires both an absolute error-count floor and a relative rate-multiplier to hold, so a tiny sample (e.g. 1 error becoming 2) doesn't read as a spike.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of traces to analyze per window (default: 1000)
top_nNoMaximum ranked contributors to return per breakdown (default: 5, max: 50)
recent_endYesRecent window end time in ISO 8601 format
baseline_endNoBaseline window end (ISO 8601)
recent_startYesRecent window start time in ISO 8601 format
service_nameNoFilter by service name (applied to both windows)
baseline_startNoBaseline window start (ISO 8601). If omitted along with baseline_end, auto-computed as the same duration immediately preceding recent_start.
min_error_count_increaseNoMinimum absolute error-count increase to count as a spike (default: 3)
rate_multiplier_thresholdNoMinimum error-rate multiplier (recent / baseline) to count as a spike (default: 2.0)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, covering the safety profile. The description adds valuable behavioral context by explaining the spike detection criteria (absolute floor and relative multiplier), which prevents misuse on tiny samples. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no fluff. The primary purpose is front-loaded, and the nuance about spike criteria is concisely added. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (9 params, 100% schema coverage) and presence of an output schema, the description covers the core logic well. It could mention how the output is structured or when to prefer this over siblings, but those are covered elsewhere or optional. Overall, sufficient for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all parameters are already documented. The description adds marginal value by referencing the spike criteria, but it doesn't explicitly map to the min_error_count_increase and rate_multiplier_threshold parameters beyond what the schema states. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb ('investigate') and resource ('error-rate spike'), and explains the action: compare a recent window against a baseline and rank contributors. It distinguishes itself from sibling tools like investigate_cost_spike by focusing on error rates, and from compare_time_windows by ranking contributions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for investigating error spikes but does not explicitly state when to use this tool versus alternatives like compare_time_windows or search_traces. No exclusions or alternative routing are provided, leaving the agent to infer context from the name and sibling list.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_llm_modelsList LLM ModelsA
Read-onlyIdempotent

List all LLM models being used with usage statistics.

Discovers what models are deployed and tracks their usage patterns.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum traces to analyze for model discovery (default: 1000)
end_timeNoEnd time in ISO 8601 format
start_timeNoStart time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)
service_nameNoFilter by service name
gen_ai_systemNoFilter by LLM provider (e.g., openai, anthropic, cohere)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so safety is covered. The description adds that results are limited to models in use and include usage stats, but it discloses no further behavioral traits such as trace-based analysis, result limits, or aggregation details.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short and front-loaded, with the core action in the first sentence. The second sentence is slightly redundant but adds a discovery-oriented framing, so it isn't wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given rich annotations, a 100%-documented optional parameter set, and an output schema, the description provides enough context for invocation. It could be more explicit about sibling tool distinctions and the trace-derived nature of the results, but nothing critical is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%: all five parameters (limit, end_time, start_time, service_name, gen_ai_system) are already described inline with types, defaults, and examples. The tool description adds no parameter-specific meaning, which is acceptable because the schema carries the weight.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List'), resource ('LLM models'), and scope ('all ... being used'), and adds that it returns usage statistics. It is not a tautology, though it doesn't explicitly distinguish itself from the sibling tool get_llm_model_stats.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The second sentence ('Discovers what models are deployed and tracks their usage patterns') gives clear context for when this tool is useful. It doesn't name alternatives or state exclusions, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_llm_tools_toolList LLM ToolsA
Read-onlyIdempotent

List all LLM tools being used by identifying traceloop.span.kind == tool.

Discovers which tools/functions LLM applications are calling, grouped by tool name with usage statistics.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum spans to analyze (default: 1000)
end_timeNoEnd time in ISO 8601 format
start_timeNoStart time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)
service_nameNoFilter by service name
gen_ai_systemNoFilter by LLM provider (openai, anthropic, etc.)

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false bir, so the safety profile is covered. The description adds meaningful behavioral context beyond annotations: it reveals the internal filtering mechanism (traceloop.span.kind == tool) and the aggregation behavior (grouped by tool name with usage statistics), which helps the agent understand what the result represents.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two short sentences, with the core purpose front-loaded and no filler. The grouping/usage-statistics detail earns its place and is not redundant with the schema or annotations.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's relative simplicity, the output schema presence, and fully described parameters, the description is mostly complete. It explains the key behavioral detail (span kind filtering) and the return shape (grouped with usage statistics). The only gap is explicit guidance on when to choose this over related sibling tools.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter already has a clear description. The tool description does not add parameter-specific semantics beyond what the schema provides, which fits the baseline of 3 for full schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource ('List all LLM tools being used'), identifies the exact span condition (traceloop.span.kind == tool), and states the output grouping ('grouped by tool name with usage statistics'). This clearly distinguishes it from sibling tools like list_llm_models.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool ('Discovers which tools/functions LLM applications are calling'), but it does not explicitly compare it to alternatives such as list_llm_models or get_llm_usage, nor does it state when not to use it. Usage guidance is present but only implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_servicesList ServicesA
Read-onlyIdempotent

List all available services in the OpenTelemetry backend.

Returns: JSON string with list of services

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=false, covering the safety profile. The description adds the return format ('JSON string with list of services') and the scope 'all available services,' which are useful behavioral details beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two short, front-loaded sentences with no filler. The core action is stated first, and the return type is provided in a clearly separated line. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only listing tool with rich annotations and an output schema, the description is sufficient. It states what is listed, the backend scope, and the return format. There are no missing pieces an agent would need to invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the baseline is 4. The description adds no parameter information, but none is needed since the input schema is empty and schema coverage is 100% by definition.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('List') and resource ('all available services in the OpenTelemetry backend'). It clearly distinguishes this from sibling tools like list_llm_models or list_sessions by specifying services in the OpenTelemetry backend. The scope is explicit and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It does not mention exclusions, prerequisites, or conditions that would select this tool over sibling list tools. The intended usage is only implied by the name and one-line action.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_sessionsList SessionsA
Read-onlyIdempotent

List conversations/sessions grouped by gen_ai.conversation.id.

Groups spans that carry the gen_ai.conversation.id attribute (a real, cross-industry OTel semantic convention for session/conversation grouping) to surface per-conversation span counts, token usage, and time bounds - useful for understanding multi-turn conversation activity.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum spans to analyze (default: 1000)
end_timeNoEnd time in ISO 8601 format
start_timeNoStart time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)
service_nameNoFilter by service name
gen_ai_systemNoFilter by LLM provider (openai, anthropic, etc.)

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
messageNo
sessionsYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false. The description adds meaningful behavioral context by explaining the grouping mechanism, the OTel semantic convention, and the per-conversation metrics produced. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences with the primary action front-loaded. The OTel convention explanation earns its place by clarifying why this attribute is meaningful, and there is no redundant restatement of the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With fully documented parameters, rich annotations, and an output schema, the description is nearly complete. It clearly explains the grouping key and intended use case; a brief cross-reference to get_session_stats would make it fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all five parameters. The description adds no parameter-specific meaning beyond identifying the grouping key, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action and resource: list conversations/sessions grouped by gen_ai.conversation.id, and specifies the surfaced outputs (span counts, token usage, time bounds). This clearly distinguishes it from trace- and span-oriented sibling tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description says it is 'useful for understanding multi-turn conversation activity,' which implies when to use it, but it does not name alternatives or state when not to use it (e.g., versus get_session_stats). Guidance is present but only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_spans_toolSearch SpansA
Read-onlyIdempotent

Search for individual OpenTelemetry spans with optional filters.

Unlike search_traces, this returns individual spans rather than grouped traces, which is useful for analyzing specific operations or finding spans with certain characteristics (e.g., LLM tool calls with traceloop.span.kind == tool).

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNoAdditional tag filters as key-value pairs
limitNoMaximum number of spans to return (1-1000, default: 100)
filtersNoGeneric filter conditions - list of filter objects with: - field: Field name in dotted notation (e.g., "traceloop.span.kind") - operator: Comparison operator - value: Single value for most operators - values: List of values for "in", "not_in", "between" operators - value_type: Type of value(s) - "string", "number", or "boolean"
end_timeNoEnd time in ISO 8601 format
has_errorNoFilter spans with errors
start_timeNoStart time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)
service_nameNoFilter by service name
gen_ai_systemNoFilter by LLM provider (e.g., openai, anthropic)
operation_nameNoFilter by operation/span name
max_duration_msNoMaximum span duration in milliseconds
min_duration_msNoMinimum span duration in milliseconds
gen_ai_request_modelNoFilter by requested model name (e.g., "gpt-4")
gen_ai_response_modelNoFilter by actual model used (e.g., "gpt-4-0613")

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
spansYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only, idempotent, open-world, and non-destructive behavior. The description adds the key behavioral trait of returning individual spans rather than grouped traces, which is not fully encoded in the annotations. No contradiction with the annotations is present.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences deliver the purpose, the differentiating sibling, and a concrete use case without redundancy. Every sentence earns its place and the key distinction is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The schema is rich, every parameter is described, annotations already establish the safety profile, and an output schema exists. The description provides the selection context that the structured fields cannot, making the definition complete for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

All 13 parameters are fully documented in the schema, so the baseline applies. The description's tool-call filter example is useful context, but it does not add substantial parameter semantics beyond the schema's detailed field descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb-resource pair ('Search for individual OpenTelemetry spans') and immediately differentiates itself from search_traces by the returned granularity. This tells an agent exactly what the tool does and how to distinguish it from its closest sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly names the alternative (search_traces) and explains the condition that chooses this tool: individual spans rather than grouped traces, for analyzing specific operations or filter-matching characteristics. This is clear when-to-use guidance with a concrete example.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_tracesSearch TracesB
Read-onlyIdempotent

Search for OpenTelemetry traces with filters.

Supports both simple parameters and advanced generic filter system.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNoAdditional tag filters as key-value pairs
limitNoMaximum number of traces to return (1-1000, default: 100)
filtersNoGeneric filter conditions (advanced) - list of filter objects with: - field: Field name in dotted notation (e.g., "gen_ai.usage.prompt_tokens") - operator: Comparison operator (equals, not_equals, gt, lt, gte, lte, contains, not_contains, starts_with, ends_with, in, not_in, between, exists, not_exists) - value: Single value for most operators - values: List of values for "in", "not_in", "between" operators - value_type: Type of value(s) - "string", "number", or "boolean"
end_timeNoEnd time in ISO 8601 format
has_errorNoFilter traces with errors
start_timeNoStart time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)
service_nameNoFilter by service name (use filters for advanced queries)
gen_ai_systemNoFilter by LLM provider (e.g., openai, anthropic)
operation_nameNoFilter by operation/span name
max_duration_msNoMaximum trace duration in milliseconds
min_duration_msNoMinimum trace duration in milliseconds
gen_ai_request_modelNoFilter by requested model name (e.g., gpt-4)
gen_ai_response_modelNoFilter by actual model used (e.g., gpt-4-0613)

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
tracesYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds the filter-system feature but does not disclose any additional behavioral traits such as default time ranges, pagination behavior, or result ordering; this is acceptable but not a strong contribution.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short and front-loaded with the core purpose. The second sentence about simple versus advanced filters is useful, though it is somewhat generic and could have been replaced with more specific guidance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the rich input schema, full schema coverage, output schema, and comprehensive annotations, the description is adequate for invoking the tool. It could be more complete by clarifying the default search window or how results are returned, but those gaps are partially filled by the schema and output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 13 parameters in detail. The description's mention of 'simple parameters and advanced generic filter system' adds a useful high-level categorization, but it does not add meaning beyond what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool searches OpenTelemetry traces and supports filtering. It is specific about the resource and action, though it does not explicitly differentiate itself from search_spans_tool or call out that get_trace is for single-trace retrieval.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description mentions that both simple parameters and an advanced generic filter system are supported, which hints at how to choose between those approaches. However, it gives no guidance on when to use this tool versus sibling tools like search_spans_tool, get_trace, or find_errors.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 16 tool updatesv0.11.0
    • Changedcompare_time_windows9 fields changed
      • addedInput schema / properties / gen_ai_request_model / description
        Added value: +"Filter by requested model name (applied to both ranges)"
      • addedInput schema / properties / gen_ai_response_model / description
        Added value: +"Filter by actual model used (applied to both ranges)"
      • addedInput schema / properties / gen_ai_system / description
        Added value: +"Filter by LLM provider (applied to both ranges)"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum number of traces to analyze per range (default: 1000)"
      • addedInput schema / properties / range_a_end / description
        Added value: +"Range A end time in ISO 8601 format"
      • addedInput schema / properties / range_a_start / description
        Added value: +"Range A start time in ISO 8601 format"
      • addedInput schema / properties / range_b_end / description
        Added value: +"Range B end time in ISO 8601 format"
      • addedInput schema / properties / range_b_start / description
        Added value: +"Range B start time in ISO 8601 format"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name (applied to both ranges)"
    • Changedfind_errors4 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum error traces to return (default: 100)"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format"
    • Changedget_llm_expensive_traces7 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / gen_ai_request_model / description
        Added value: +"Filter by requested model name (e.g., \"gpt-4\")"
      • addedInput schema / properties / gen_ai_response_model / description
        Added value: +"Filter by actual model used (e.g., \"gpt-4-0613\")"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum number of traces to return (default: 10)"
      • addedInput schema / properties / min_tokens / description
        Added value: +"Minimum token count threshold (only return traces above this)"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)"
    • Changedget_llm_model_stats4 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / model_name / description
        Added value: +"Model name to analyze (e.g., \"gpt-4\", \"claude-3-opus\", \"gpt-3.5-turbo\")"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)"
    • Changedget_llm_slow_traces7 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / gen_ai_request_model / description
        Added value: +"Filter by requested model name (e.g., \"gpt-4\")"
      • addedInput schema / properties / gen_ai_response_model / description
        Added value: +"Filter by actual model used (e.g., \"gpt-4-0613\")"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum number of traces to return (default: 10)"
      • addedInput schema / properties / min_duration_ms / description
        Added value: +"Minimum duration threshold in milliseconds (only return traces above this)"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)"
    • Changedget_llm_usage7 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / gen_ai_request_model / description
        Added value: +"Filter by requested model name"
      • addedInput schema / properties / gen_ai_response_model / description
        Added value: +"Filter by actual model used"
      • addedInput schema / properties / gen_ai_system / description
        Added value: +"Filter by LLM provider"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum traces to analyze (default: 1000)"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format"
    • Changedget_prompt_version_stats5 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / gen_ai_system / description
        Added value: +"Filter by LLM provider (openai, anthropic, etc.)"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum spans to analyze (default: 1000)"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)"
    • Changedget_session_stats5 fields changed
      • addedInput schema / properties / conversation_id / description
        Added value: +"The gen_ai.conversation.id to analyze"
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum spans to analyze (default: 1000)"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)"
    • Changedget_trace2 fields changed
      • addedInput schema / properties / detail_level / description
        Added value: +"\"full\" (default) returns every attribute/event value\nin full, unchanged from this tool's original behavior. \"summary\"\nelides known-large gen_ai.* fields (input/output messages, system\ninstructions, retrieval documents) and truncates long\nevent-attribute values, for callers that don't need full\nprompt/completion bodies."
      • addedInput schema / properties / trace_id / description
        Added value: +"Trace identifier"
    • Changedinvestigate_cost_spike10 fields changed
      • addedInput schema / properties / baseline_end / description
        Added value: +"Baseline window end (ISO 8601)"
      • addedInput schema / properties / baseline_start / description
        Added value: +"Baseline window start (ISO 8601). If omitted along\nwith baseline_end, auto-computed as the same duration\nimmediately preceding recent_start."
      • addedInput schema / properties / gen_ai_request_model / description
        Added value: +"Filter by requested model name (applied to both windows)"
      • addedInput schema / properties / gen_ai_response_model / description
        Added value: +"Filter by actual model used (applied to both windows)"
      • addedInput schema / properties / gen_ai_system / description
        Added value: +"Filter by LLM provider (applied to both windows)"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum number of traces to analyze per window (default: 1000)"
      • addedInput schema / properties / recent_end / description
        Added value: +"Recent window end time in ISO 8601 format"
      • addedInput schema / properties / recent_start / description
        Added value: +"Recent window start time in ISO 8601 format"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name (applied to both windows)"
      • addedInput schema / properties / top_n / description
        Added value: +"Maximum ranked contributors to return per breakdown (default: 5, max: 50)"
    • Changedinvestigate_error_spike9 fields changed
      • addedInput schema / properties / baseline_end / description
        Added value: +"Baseline window end (ISO 8601)"
      • addedInput schema / properties / baseline_start / description
        Added value: +"Baseline window start (ISO 8601). If omitted along\nwith baseline_end, auto-computed as the same duration\nimmediately preceding recent_start."
      • addedInput schema / properties / limit / description
        Added value: +"Maximum number of traces to analyze per window (default: 1000)"
      • addedInput schema / properties / min_error_count_increase / description
        Added value: +"Minimum absolute error-count increase to\ncount as a spike (default: 3)"
      • addedInput schema / properties / rate_multiplier_threshold / description
        Added value: +"Minimum error-rate multiplier (recent /\nbaseline) to count as a spike (default: 2.0)"
      • addedInput schema / properties / recent_end / description
        Added value: +"Recent window end time in ISO 8601 format"
      • addedInput schema / properties / recent_start / description
        Added value: +"Recent window start time in ISO 8601 format"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name (applied to both windows)"
      • addedInput schema / properties / top_n / description
        Added value: +"Maximum ranked contributors to return per breakdown (default: 5, max: 50)"
    • Changedlist_llm_models5 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / gen_ai_system / description
        Added value: +"Filter by LLM provider (e.g., openai, anthropic, cohere)"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum traces to analyze for model discovery (default: 1000)"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)"
    • Changedlist_llm_tools_tool5 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / gen_ai_system / description
        Added value: +"Filter by LLM provider (openai, anthropic, etc.)"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum spans to analyze (default: 1000)"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)"
    • Changedlist_sessions5 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / gen_ai_system / description
        Added value: +"Filter by LLM provider (openai, anthropic, etc.)"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum spans to analyze (default: 1000)"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)"
    • Changedsearch_spans_tool13 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / filters / description
        Added value: +"Generic filter conditions - list of filter objects with:\n- field: Field name in dotted notation (e.g., \"traceloop.span.kind\")\n- operator: Comparison operator\n- value: Single value for most operators\n- values: List of values for \"in\", \"not_in\", \"between\" operators\n- value_type: Type of value(s) - \"string\", \"number\", or \"boolean\""
      • addedInput schema / properties / gen_ai_request_model / description
        Added value: +"Filter by requested model name (e.g., \"gpt-4\")"
      • addedInput schema / properties / gen_ai_response_model / description
        Added value: +"Filter by actual model used (e.g., \"gpt-4-0613\")"
      • addedInput schema / properties / gen_ai_system / description
        Added value: +"Filter by LLM provider (e.g., openai, anthropic)"
      • addedInput schema / properties / has_error / description
        Added value: +"Filter spans with errors"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum number of spans to return (1-1000, default: 100)"
      • addedInput schema / properties / max_duration_ms / description
        Added value: +"Maximum span duration in milliseconds"
      • addedInput schema / properties / min_duration_ms / description
        Added value: +"Minimum span duration in milliseconds"
      • addedInput schema / properties / operation_name / description
        Added value: +"Filter by operation/span name"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)"
      • addedInput schema / properties / tags / description
        Added value: +"Additional tag filters as key-value pairs"
    • Changedsearch_traces13 fields changed
      • addedInput schema / properties / end_time / description
        Added value: +"End time in ISO 8601 format"
      • addedInput schema / properties / filters / description
        Added value: +"Generic filter conditions (advanced) - list of filter objects with:\n- field: Field name in dotted notation (e.g., \"gen_ai.usage.prompt_tokens\")\n- operator: Comparison operator (equals, not_equals, gt, lt, gte, lte, contains,\n           not_contains, starts_with, ends_with, in, not_in, between, exists, not_exists)\n- value: Single value for most operators\n- values: List of values for \"in\", \"not_in\", \"between\" operators\n- value_type: Type of value(s) - \"string\", \"number\", or \"boolean\""
      • addedInput schema / properties / gen_ai_request_model / description
        Added value: +"Filter by requested model name (e.g., gpt-4)"
      • addedInput schema / properties / gen_ai_response_model / description
        Added value: +"Filter by actual model used (e.g., gpt-4-0613)"
      • addedInput schema / properties / gen_ai_system / description
        Added value: +"Filter by LLM provider (e.g., openai, anthropic)"
      • addedInput schema / properties / has_error / description
        Added value: +"Filter traces with errors"
      • addedInput schema / properties / limit / description
        Added value: +"Maximum number of traces to return (1-1000, default: 100)"
      • addedInput schema / properties / max_duration_ms / description
        Added value: +"Maximum trace duration in milliseconds"
      • addedInput schema / properties / min_duration_ms / description
        Added value: +"Minimum trace duration in milliseconds"
      • addedInput schema / properties / operation_name / description
        Added value: +"Filter by operation/span name"
      • addedInput schema / properties / service_name / description
        Added value: +"Filter by service name (use filters for advanced queries)"
      • addedInput schema / properties / start_time / description
        Added value: +"Start time in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)"
      • addedInput schema / properties / tags / description
        Added value: +"Additional tag filters as key-value pairs"
  2. 1 tool updatev0.9.0
    • Changedget_trace16 fields changed
      • addedInput schema / properties / detail_level
        Added value: +{
        +  "default": "full",
        +  "enum": [
        +    "summary",
        +    "full"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / description
        Added value: +"Structured response shape for the get_trace tool - see\nSearchTracesResult's docstring for why this is a real model rather than\na bare str.\n\ndetail_level echoes back what was actually applied: \"full\" reproduces\nthis tool's original byte-for-byte behavior; \"summary\" elides/truncates\nthe same known-large gen_ai.* fields that LLMSpanAttributes.prompt_preview/\ncompletion_preview already only ever preview (e.g. gen_ai.input.messages,\ngen_ai.output.messages) instead of dumping them in full."
      • addedOutput schema / properties / detail_level
        Added value: +{
        +  "enum": [
        +    "summary",
        +    "full"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / duration_ms
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / has_errors
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / llm_summary
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "default": null
        +}
      • removedOutput schema / properties / result
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / root_operation
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / service_name
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / span_count
        Added value: +{
        +  "type": "integer"
        +}
      • addedOutput schema / properties / spans
        Added value: +{
        +  "items": {
        +    "description": "Full per-span detail for the get_trace tool - see TraceDetail's\ndocstring for why this is a real model rather than a bare str.",
        +    "properties": {
        +      "attributes": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "duration_ms": {
        +        "type": "number"
        +      },
        +      "events": {
        +        "items": {
        +          "additionalProperties": true,
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "llm_attributes": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": true,
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "operation_name": {
        +        "type": "string"
        +      },
        +      "parent_span_id": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "service_name": {
        +        "type": "string"
        +      },
        +      "span_id": {
        +        "type": "string"
        +      },
        +      "start_time": {
        +        "format": "date-time",
        +        "type": "string"
        +      },
        +      "status": {
        +        "enum": [
        +          "OK",
        +          "ERROR",
        +          "UNSET"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "span_id",
        +      "parent_span_id",
        +      "operation_name",
        +      "service_name",
        +      "start_time",
        +      "duration_ms",
        +      "status",
        +      "attributes",
        +      "events"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / start_time
        Added value: +{
        +  "format": "date-time",
        +  "type": "string"
        +}
      • addedOutput schema / properties / status
        Added value: +{
        +  "enum": [
        +    "OK",
        +    "ERROR",
        +    "UNSET"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / trace_id
        Added value: +{
        +  "type": "string"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "result"
        -]New value: +[
        +  "trace_id",
        +  "service_name",
        +  "root_operation",
        +  "start_time",
        +  "duration_ms",
        +  "status",
        +  "span_count",
        +  "has_errors",
        +  "spans",
        +  "detail_level"
        +]
      • removedOutput schema / x-fastmcp-wrap-result
        Removed value: -true
  3. 2 tool updatesv0.8.1
    • Addedinvestigate_cost_spike
    • Addedinvestigate_error_spike
  4. 6 tool updatesv0.5.0
    • Addedcompare_time_windows
    • Addedget_prompt_version_stats
    • Addedget_session_stats
    • Addedlist_sessions
    • Changedsearch_spans_tool6 fields changed
      • addedOutput schema / description
        Added value: +"Structured response shape for the search_spans tool - see\nSearchTracesResult's docstring for why this is a real model rather than\na bare str."
      • addedOutput schema / properties / count
        Added value: +{
        +  "type": "integer"
        +}
      • removedOutput schema / properties / result
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / spans
        Added value: +{
        +  "items": {
        +    "description": "Simplified span summary for list results.",
        +    "properties": {
        +      "duration_ms": {
        +        "type": "number"
        +      },
        +      "extra_attributes": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": {
        +              "anyOf": [
        +                {
        +                  "type": "string"
        +                },
        +                {
        +                  "type": "integer"
        +                },
        +                {
        +                  "type": "number"
        +                },
        +                {
        +                  "type": "boolean"
        +                }
        +              ]
        +            },
        +            "type": "object"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "gen_ai_system": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "is_llm_span": {
        +        "default": false,
        +        "type": "boolean"
        +      },
        +      "operation_name": {
        +        "type": "string"
        +      },
        +      "parent_span_id": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "service_name": {
        +        "type": "string"
        +      },
        +      "span_id": {
        +        "type": "string"
        +      },
        +      "start_time": {
        +        "format": "date-time",
        +        "type": "string"
        +      },
        +      "status": {
        +        "enum": [
        +          "OK",
        +          "ERROR",
        +          "UNSET"
        +        ],
        +        "type": "string"
        +      },
        +      "total_tokens": {
        +        "anyOf": [
        +          {
        +            "type": "integer"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "default": null
        +      },
        +      "trace_id": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "trace_id",
        +      "span_id",
        +      "parent_span_id",
        +      "operation_name",
        +      "service_name",
        +      "start_time",
        +      "duration_ms",
        +      "status"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "result"
        -]New value: +[
        +  "count",
        +  "spans"
        +]
      • removedOutput schema / x-fastmcp-wrap-result
        Removed value: -true
    • Changedsearch_traces6 fields changed
      • addedOutput schema / description
        Added value: +"Structured response shape for the search_traces tool.\n\nA real return type (rather than a bare str) lets FastMCP auto-derive a\ngenuinely useful MCP outputSchema/structuredContent instead of the\ndegenerate {\"result\": \"<json string>\"} wrap every str-returning tool\nproduces today - see tools/search.py."
      • addedOutput schema / properties / count
        Added value: +{
        +  "type": "integer"
        +}
      • removedOutput schema / properties / result
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / traces
        Added value: +{
        +  "items": {
        +    "description": "Simplified trace summary for list results.",
        +    "properties": {
        +      "duration_ms": {
        +        "type": "number"
        +      },
        +      "has_errors": {
        +        "default": false,
        +        "type": "boolean"
        +      },
        +      "llm_span_count": {
        +        "default": 0,
        +        "type": "integer"
        +      },
        +      "operation_name": {
        +        "type": "string"
        +      },
        +      "service_name": {
        +        "type": "string"
        +      },
        +      "span_count": {
        +        "type": "integer"
        +      },
        +      "start_time": {
        +        "format": "date-time",
        +        "type": "string"
        +      },
        +      "status": {
        +        "enum": [
        +          "OK",
        +          "ERROR",
        +          "UNSET"
        +        ],
        +        "type": "string"
        +      },
        +      "total_tokens": {
        +        "default": 0,
        +        "type": "integer"
        +      },
        +      "trace_id": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "trace_id",
        +      "service_name",
        +      "operation_name",
        +      "start_time",
        +      "duration_ms",
        +      "status",
        +      "span_count"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "result"
        -]New value: +[
        +  "count",
        +  "traces"
        +]
      • removedOutput schema / x-fastmcp-wrap-result
        Removed value: -true
  5. 11 tool updatesv0.1.0
    • First observedfind_errors
    • First observedget_llm_expensive_traces
    • First observedget_llm_model_stats
    • First observedget_llm_slow_traces
    • First observedget_llm_usage
    • First observedget_trace
    • First observedlist_llm_models
    • First observedlist_llm_tools_tool
    • First observedlist_services
    • First observedsearch_spans_tool
    • First observedsearch_traces

TDQS

A3.7/5.0

Scored across 17 tools

Disambiguation3/5

Several tools have overlapping purposes: compare_time_windows and investigate_cost_spike both compare LLM usage windows, and get_llm_usage overlaps with both. find_errors and investigate_error_spike also share error-analysis territory. However, descriptions provide enough differentiators for most tools, such as search_traces versus search_spans_tool.

Naming Consistency4/5

Most tools follow a clear verb_noun snake_case pattern, e.g. get_trace, search_traces, list_services, compare_time_windows. The pattern is weakened by the awkward '_tool' suffixes on search_spans_tool and list_llm_tools_tool, plus mixed verbs like find_errors versus search_traces.

Tool Count4/5

At 17 tools, the set is on the heavier side but still justified by the broad observability domain: traces, spans, errors, sessions, LLM usage, models, prompts, services, and spike investigations. Each tool addresses a real workflow, so the count feels slightly over rather than bloated.

Completeness5/5

For a read-only telemetry/observability server, the tool surface is comprehensive: raw traces, individual spans, error discovery, LLM usage and cost analysis, model performance, session analytics, service enumeration, and slow/expensive trace discovery. There are no obvious dead ends or missing core operations for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Connects AI assistants to Warpmetrics telemetry data to monitor AI agent performance, execution runs, and LLM costs. It allows users to query success rates, latency, and spend metrics directly through natural language interfaces.
    20
    23 npm
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables natural language querying and analysis of OpenTelemetry traces, metrics, and logs stored in Elasticsearch/OpenSearch, allowing AI assistants to investigate performance issues, find root causes, and explore system behavior.
    12 npm
    14
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    MCP server that gives AI agents access to your application's OpenTelemetry traces for querying, analysis, and debugging.
    5
    7 npm
    2
    MIT