Skip to main content
Glama
mshegolev

jaeger-mcp

by mshegolev
README.md
# jaeger-mcp

<!-- mcp-name: io.github.mshegolev/jaeger-mcp -->

[![PyPI version](https://img.shields.io/pypi/v/jaeger-mcp.svg)](https://pypi.org/project/jaeger-mcp/)
[![Python versions](https://img.shields.io/pypi/pyversions/jaeger-mcp.svg)](https://pypi.org/project/jaeger-mcp/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Tests](https://github.com/mshegolev/jaeger-mcp/actions/workflows/test.yml/badge.svg)](https://github.com/mshegolev/jaeger-mcp/actions/workflows/test.yml)

**MCP server for [Jaeger](https://www.jaegertracing.io/) distributed tracing.**
Give Claude (or any MCP-capable agent) read access to your trace data — search traces, inspect spans, compare traces, compute span statistics, map service dependencies, predict performance issues, and forecast capacity needs — without leaving the conversation.

## Why another Jaeger MCP?

The existing Jaeger integrations require a running UI or custom scripts. This server:

- Speaks the standard [Model Context Protocol](https://modelcontextprotocol.io/) over **stdio** — works with Claude Desktop, Claude Code, Cursor, and any MCP client.
- Is **read-only**: all 15 tools carry `readOnlyHint: true` — zero risk of modifying trace data.
- Returns **dual-channel output**: structured JSON (`structuredContent`) for programmatic use + Markdown (`content`) for human-readable display.
- Has **actionable error messages** that name the exact env var to fix and suggest a next step.
- Supports **Bearer token**, **HTTP Basic auth**, or **no auth** (common for internal deployments).
- Includes **OpenAPI specification** documenting the underlying Jaeger Query API (`openapi.yaml`).

## Tools

| Tool | Endpoint | Description |
|------|----------|-------------|
| `jaeger_list_services` | `GET /api/services` | List all instrumented services |
| `jaeger_list_operations` | `GET /api/services/{service}/operations` | List operation names for a service |
| `jaeger_search_traces` | `GET /api/traces` | Search traces with rich filters |
| `jaeger_get_trace` | `GET /api/traces/{traceID}` | Full trace detail with span tree |
| `jaeger_get_dependencies` | `GET /api/dependencies` | Service-to-service call graph |
| `jaeger_compare_traces` | `GET /api/traces/{traceID}` ×2 | Structural diff between two traces |
| `jaeger_span_statistics` | `GET /api/traces` | Per-operation latency and error stats |
| `jaeger_critical_path` | `GET /api/traces/{traceID}` | Longest-duration span chain and bottleneck ranking |
| `jaeger_compare_windows` | `GET /api/traces` ×2 | Aggregate trace behavior diff between two time periods |
| `jaeger_detect_anomalies` | `GET /api/traces` ×2 | Statistical latency/error-rate spike detection per operation |
| `jaeger_predict_degradation` | `GET /api/traces` | Predict performance degradation 2-24 hours in advance |
| `jaeger_forecast_capacity` | `GET /api/traces` | Forecast throughput demands and resource requirements |
| `jaeger_find_test_traces` | `GET /api/traces` | Correlate a test run to its traces by tag query (Allure/pytest/custom) |
| `jaeger_regression_diff` | `GET /api/traces` ×2 | Classify per-operation regressions between two time windows |
| `jaeger_test_profile` | `GET /api/traces` | Per-operation latency hotspots for a tagged test run |

## Installation

```bash
pip install jaeger-mcp
```

Or run directly without installing:

```bash
uvx jaeger-mcp
```

## Configuration

All configuration is via environment variables:

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `JAEGER_URL` | **Yes** | — | Jaeger query service URL, e.g. `https://jaeger.example.com` |
| `JAEGER_TOKEN` | No | — | Bearer token (takes precedence over Basic auth) |
| `JAEGER_USERNAME` | No | — | HTTP Basic auth username |
| `JAEGER_PASSWORD` | No | — | HTTP Basic auth password |
| `JAEGER_SSL_VERIFY` | No | `true` | Set `false` for self-signed certificates |
| `JAEGER_TIMEOUT` | No | `30` | HTTP request timeout in seconds |
| `JAEGER_RETRY_ATTEMPTS` | No | `3` | Retry count for transient failures (0 to disable) |
| `JAEGER_CACHE_TTL` | No | `120` | TTL in seconds for discovery endpoint cache (0 to disable) |

Copy `.env.example` to `.env` and fill in your values.

## Claude Desktop / Claude Code setup

Add to your MCP config (`claude_desktop_config.json` or `.claude/mcp.json`):

```json
{
  "mcpServers": {
    "jaeger": {
      "command": "jaeger-mcp",
      "env": {
        "JAEGER_URL": "https://jaeger.example.com",
        "JAEGER_TOKEN": "your-token-here"
      }
    }
  }
}
```

Or with `uvx` (no install required):

```json
{
  "mcpServers": {
    "jaeger": {
      "command": "uvx",
      "args": ["jaeger-mcp"],
      "env": {
        "JAEGER_URL": "https://jaeger.example.com"
      }
    }
  }
}
```

## Docker

```bash
docker run --rm -e JAEGER_URL=https://jaeger.example.com jaeger-mcp
```

## Example queries

Once configured, ask Claude:

- "What services does Jaeger know about?"
- "Find traces with HTTP 500 errors in `order-service` from the last hour"
- "Show me the slowest traces (over 2 seconds) for `GET /checkout`"
- "What caused the error in trace `abcdef1234567890`?"
- "Map the service dependency graph for the last 7 days"
- "Which services call `postgres` most frequently?"
- "Compare trace `abc123` against trace `def456` — what spans changed?"
- "What are the p95 latencies per operation in `order-service`?"

## Tool usage guide

### `jaeger_list_services`

Returns all service names Jaeger has seen. **Start here** when you don't know which services are instrumented. Output is capped at 500 services with a truncation hint.

### `jaeger_list_operations`

Returns all operation names for a given service (e.g. HTTP route names, gRPC method names). Use to discover valid operation names before filtering `jaeger_search_traces`.

### `jaeger_search_traces`

The main search tool. Filters:

- `service` (required) — service name from `jaeger_list_services`
- `operation` — narrow to a specific endpoint
- `tags` — JSON string of tag filters, e.g. `{"http.status_code":"500"}` or `{"error":"true"}`
- `start` / `end` — time range in **microseconds** UTC
- `min_duration` / `max_duration` — duration strings like `"100ms"`, `"1.5s"`, `"2m"`
- `limit` — default 20, max 1500

Returns trace summaries with `trace_id`, `duration_us`, `span_count`, `service_count`, `root_operation`, `errors_count`.

### `jaeger_get_trace`

Full trace detail. Accepts a `trace_id` (hex string, 16-32 chars) and returns:

- All spans with tags, service names, parent/child relationships
- Per-service statistics (span count, total duration, error count)
- Execution tree (each node lists its child span IDs)

Error spans are identified by `tags["error"] = "true"`.

### `jaeger_get_dependencies`

Service topology graph. Returns directed edges `(parent → child)` with `call_count`. Use `lookback_hours` (default 24, max 720) to control the window.

### `jaeger_compare_traces`

Structural diff between two traces. Accepts two `trace_id` hex strings and matches spans by `(operationName, serviceName, parentOperation)` — not span ID. Reports:

- **Added spans** — present in trace B but not trace A
- **Removed spans** — present in trace A but not trace B
- **Changed spans** — matched but differ in duration or tags (shows deltas)
- **Unchanged count** — number of identical spans

Use to compare a slow trace against a fast one, or to see what changed between deployments.

### `jaeger_span_statistics`

Per-operation latency percentiles and error rates. Fetches up to `limit` traces (default 20, max 100) for a service and aggregates all spans by operation name. Reports per operation:

- `count` — total spans observed
- `p50_duration_us`, `p95_duration_us`, `p99_duration_us` — latency percentiles
- `error_count`, `error_rate` — errors (identified by `tags["error"] = "true"`)

Use to find the slowest or most error-prone operations in a service.

### `jaeger_critical_path`

Identifies the longest-duration span chain from root to leaf in a trace (the critical path) and ranks spans by self-time to find performance bottlenecks. 

Reports:
- Critical path spans with operation, service, duration, and percentage-of-total
- Bottleneck spans ranked by exclusive duration (self-time)

Use to answer "Why is this trace so slow?" and "Which operations consume the most CPU/self-time?"

### `jaeger_compare_windows`

Compares aggregate trace behavior between two time periods for a service to detect performance regressions or improvements across deployments.

Reports:
- Per-operation diff summary showing added, removed, faster, slower operations
- Deviation scoring with numeric scores per operation and overall
- Latency percentile changes (p50, p95) and error rate deltas

Use to answer "Did our latest deployment affect performance?" and "Which operations got slower after the database upgrade?"

### `jaeger_detect_anomalies`

Scans for statistically significant latency spikes or error-rate increases in a service's recent traces compared to historical baselines.

Reports:
- Flagged operations with anomaly type (latency or error_rate)
- Severity classification (low to critical) with z-scores
- Current vs baseline values for affected metrics

Use to proactively identify performance degradations and reliability issues before they impact users.

## Library facade (in-process use)

`jaeger-mcp` can also be used as a Python library without an MCP server:

```python
from jaeger_mcp import JaegerClient

client = JaegerClient.from_env()  # reads JAEGER_URL from env
trace = client.get_trace("abcdef1234567890abcdef1234567890")

for span in trace.spans:
    if span.error:
        print(f"{span.service_name}: {span.operation} at {span.start_utc}")
        print(f"  tags: {span.tags}")
```

Available methods: `get_trace()`, `search_traces()`, `list_services()`, `get_dependencies()`, `compare_traces()`, `span_statistics()`, `critical_path()`, `compare_windows()`, `detect_anomalies()`, `predict_degradation()`, `forecast_capacity()`, `find_test_traces()`, `regression_diff()`, `test_profile()`.

Domain objects: `Span`, `Trace`, `TraceSummary`, `ServiceDep`, `TraceComparison`, `SpanIdentity`, `SpanChange`, `SpanStatisticsResult`, `OperationStatResult`, `CriticalPathOutput`, `CriticalPathSpan`, `BottleneckSpan`, `WindowComparisonOutput`, `OperationDiff`, `AnomalyDetectionOutput`, `OperationAnomaly` — all with typed fields.

## API Documentation

This project includes comprehensive OpenAPI specifications in the `docs/` directory:

1. **Jaeger Query Service API** (`openapi.yaml`) - Documents the actual Jaeger API endpoints
2. **MCP Tools API** (`docs/mcp-tools-openapi.yaml`) - Documents the MCP tools as conceptual HTTP endpoints

These specifications are useful for:
- Understanding the underlying API calls made by each tool
- Developing alternative integrations
- Debugging API interactions
- Generating client libraries or documentation

See `docs/README.md` for more details on both specifications.

## Performance characteristics

- All tools use a single persistent `requests.Session` with connection pooling.
- The session has `trust_env = False` to bypass environment proxies (Jaeger is typically an internal service).
- Requests time out after 30 seconds (configurable via `JAEGER_TIMEOUT`).
- Transient HTTP errors (429/5xx) are retried with exponential backoff (configurable via `JAEGER_RETRY_ATTEMPTS`).
- `list_services` and `list_operations` responses are cached for 120 seconds (configurable via `JAEGER_CACHE_TTL`).
- `jaeger_search_traces` passes `limit` directly to Jaeger — avoid requesting more traces than needed.
- `jaeger_get_trace` fetches the full trace in one call — large traces (thousands of spans) may be slow.
- `jaeger_get_dependencies` aggregates over the full lookback window; large windows may be slow on busy clusters.

## Development

```bash
git clone https://github.com/mshegolev/jaeger-mcp
cd jaeger-mcp
pip install -e '.[dev]'
pytest tests/ -v
ruff check src tests
ruff format src tests
```

## License

MIT — see [LICENSE](LICENSE).

TDQS

A3.9/5.0

Scored across 15 tools

Disambiguation2/5

Several tools have overlapping purposes. jaeger_search_traces and jaeger_find_test_traces both search traces with tag filters, and jaeger_compare_windows, jaeger_detect_anomalies, and jaeger_regression_diff all compare two time windows to identify performance changes, making it easy for an agent to select the wrong one. The differences between these are subtle and not clearly delineated.

Naming Consistency3/5

All tools share the jaeger_ prefix and use snake_case, but the naming pattern is inconsistent: some are verb_noun (list_services, search_traces) while others are noun_phrase (span_statistics, critical_path, test_profile). This mixed convention is readable but lacks the predictability of a uniform verb_noun scheme.

Tool Count4/5

15 tools is at the upper boundary of a well-scoped set, but the advanced analytics tools (predict_degradation, forecast_capacity, detect_anomalies) expand the server's capability beyond basic tracing. The count is reasonable, though some tools could be merged without losing functionality.

Completeness4/5

The core Jaeger read operations are fully covered: service discovery, operation listing, trace search, trace detail, and dependency graph. Advanced analytics like comparisons, anomaly detection, and predictions provide extra depth, leaving few obvious gaps for a tracing-focused server.

Maintenance

ActivityMaintained
ResponsivenessNo issues