⚡ Jaeger MCP Server
Context-Efficient Observability & Distributed Tracing for AI Agents
Empower LLMs and AI coding assistants (Claude Desktop, Cursor, Antigravity, OpenCode, Windsurf) to inspect microservice topologies, triage performance bottlenecks, and pinpoint root-cause errors in distributed systems without blowing up context windows.
🚀 Quickstart • 🎯 Why Jaeger MCP? • 🛠️ Tools Reference • 🔌 Client Configurations • 🏗️ Architecture • 🧪 Testing & Debugging
🎯 Why Jaeger MCP?
Distributed traces in production systems easily contain hundreds to thousands of spans, deep call graphs, and megabytes of JSON tags and log events.
If an AI assistant ingests an entire raw trace:
- 💸 Context Window Explosion: Traces consume tens of thousands of tokens per prompt.
- 📉 Hallucinations & Noise: LLMs struggle to locate relevant errors buried beneath healthy spans.
- 🐌 High Latency & Costs: Huge payloads slow down response times and skyrocket API billing.
jaeger-mcp solves this with a 5-Stage Progressive Discovery Funnel:
flowchart TD
A[🔍 1. Service Discovery<br/>get_all_services / get_operations_for_service] --> B[📊 2. Trace Discovery<br/>get_trace_summaries]
B --> C[📈 3. High-Level Triage<br/>get_trace_overview]
C -->|High Latency| D[⏱️ 4a. Bottleneck Isolation<br/>get_slowest_spans]
C -->|Failures / 5xx| E[💥 4b. Error Filtering<br/>get_trace_errors]
D --> F[🔬 5. Deep-Dive Inspection<br/>get_span_details]
E --> F
F --> G[🎯 Instant Root-Cause Resolution]
style A fill:#2d3748,stroke:#4a5568,color:#fff
style B fill:#2b6cb0,stroke:#3182ce,color:#fff
style C fill:#2c5282,stroke:#2b6cb0,color:#fff
style D fill:#c05621,stroke:#dd6b20,color:#fff
style E fill:#9b2c2c,stroke:#e53e3e,color:#fff
style F fill:#285e61,stroke:#319795,color:#fff
style G fill:#22543d,stroke:#38a169,color:#fff
Instead of sending 2MB raw trace blobs, the agent queries structured, paginated, and summarized slices of observability data.
🚀 Quickstart
Prerequisites
- Python:
3.11or newer - Package Manager:
uv(recommended) or standardpip - Jaeger Instance: Local or remote Jaeger Query service (default port
16686)
Installation & Run Options
Option 1: Instant Run with uvx (Recommended & Zero Setup)
uvx mcp-server-jaeger
Option 2: Install via PyPI
pip install mcp-server-jaeger
mcp-server-jaeger
Option 3: Run with Docker
docker run -i --rm --network=host -e SERVICE_API_VERSION=v3 ghcr.io/chahatsagarmain/jaeger-mcp:latest
Option 4: From Source (Development)
git clone https://github.com/chahatsagarmain/jaeger-mcp.git
cd jaeger-mcp
cp example.env .env
uv sync
uv run python -m jaeger_mcp.main
2. Spin up Local Jaeger & HotROD Demo (Optional)
# 1. Run Jaeger UI + Query API + OTLP Collector
docker run --rm --name jaeger \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
-p 5778:5778 \
-p 9411:9411 \
cr.jaegertracing.io/jaegertracing/jaeger:2.22.0
# 2. Run HotROD to generate realistic distributed traffic connected to Jaeger
docker run --rm -it --name hotrod \
-p 8080:8080 \
--link jaeger:jaeger \
-e OTEL_EXPORTER_OTLP_ENDPOINT="http://jaeger:4318" \
cr.jaegertracing.io/jaegertracing/example-hotrod:2.22.0 all
- Jaeger UI: http://localhost:16686
- HotROD Demo UI: http://localhost:8080 (click buttons to generate traces)
⚙️ Configuration & Environment
The server reads configuration from .env in the project root:
| Variable | Default Value | Description |
|---|---|---|
SERVICE_API_VERSION |
v3 |
Jaeger Query API version for services/operations/summaries (v3 or v2) |
Note on Jaeger URL: Each tool accepts an optional
ping_urlargument (defaults tohttp://localhost:16686). You can target local dev instances, staging clusters, or remote production Jaeger UI proxies on the fly.
🛠️ Tools Reference
| Tool | Signature | Purpose |
|---|---|---|
ping_jaeger |
ping_url: str |
Healthcheck Jaeger connectivity |
get_all_services |
ping_url: str |
List all instrumented microservices |
get_operations_for_service |
service_name: str, ping_url: str |
List operations/endpoints & span kinds for a service |
get_trace_summaries |
service_name, start_time_min?, start_time_max?, search_depth?, operation_name?, ping_url? |
Search recent traces with duration & span counts |
get_trace_overview |
trace_id: str, ping_url: str |
Wall-clock duration, error counts, and per-service breakdown |
get_slowest_spans |
trace_id: str, limit?: int, offset?: int, ping_url: str |
Paginated bottleneck isolation sorted by duration descending |
get_trace_errors |
trace_id: str, ping_url: str |
Isolate failed spans, HTTP status codes, and exception logs |
get_span_details |
trace_id: str, span_id: str, ping_url: str |
Granular span inspect: attributes, logs/events, and child span IDs |
Tool Outputs & Real Examples
1. ping_jaeger — Connection Healthcheck
Verifies that the Jaeger HTTP endpoint is reachable.
- Parameters:
ping_url: str = "http://localhost:16686" - Example Call:
ping_jaeger() - Actual Output:
"jaeger accessible on http://localhost:16686"
2. get_all_services — Service Discovery
Fetches every service registered in Jaeger's registry.
- Parameters:
ping_url: str = "http://localhost:16686" - Example Call:
get_all_services() - Actual Output:
{ "services": [ "customer", "driver", "frontend", "jaeger", "mysql", "redis-manual", "route" ] }
3. get_operations_for_service — Operation Discovery
Lists all instrumented endpoints and span kinds for a specific service.
- Parameters:
service_name: str,ping_url: str = "http://localhost:16686" - Example Call:
get_operations_for_service(service_name="driver") - Actual Output:
{ "operations": [ { "name": "driver.DriverService/FindNearest", "spanKind": "server" } ] }
4. get_trace_summaries — Filtered Trace Search
Queries traces matching service, operation, and time filters (defaults to the last 1 hour).
- Parameters:
service_name: str,start_time_min?: str,start_time_max?: str,search_depth?: int = 20,operation_name?: str,ping_url?: str - Example Call:
get_trace_summaries(service_name="driver", search_depth=1) - Actual Output:
{ "summaries": [ { "traceId": "0752f19be1bf63061958749442056b18", "rootServiceName": "frontend", "rootOperationName": "GET /dispatch", "minStartTimeUnixNano": "1791548491657998220", "maxEndTimeUnixNano": "1791548492941190177", "spanCount": 39, "services": [ { "name": "frontend", "spanCount": 13 }, { "name": "redis-manual", "spanCount": 13 }, { "name": "route", "spanCount": 10 }, { "name": "driver", "spanCount": 1 }, { "name": "customer", "spanCount": 1 }, { "name": "mysql", "spanCount": 1 } ] } ] }
5. get_trace_overview — Wall-Clock & Service Breakdown
Computes real wall-clock duration across the entire trace distributed graph, aggregate span counts, error counts, and per-service duration/error breakdown.
- Parameters:
trace_id: str,ping_url?: str - Example Call:
get_trace_overview(trace_id="0752f19be1bf63061958749442056b18") - Actual Output:
{ "traceId": "0752f19be1bf63061958749442056b18", "rootServiceName": "frontend", "rootOperationName": "GET /dispatch", "totalDurationMs": 1283.191, "spanCount": 39, "errorCount": 2, "hasErrors": true, "services": [ { "serviceName": "frontend", "spanCount": 13, "cumulativeDurationMs": 2899.862, "errorCount": 0 }, { "serviceName": "mysql", "spanCount": 1, "cumulativeDurationMs": 901.109, "errorCount": 0 }, { "serviceName": "customer", "spanCount": 1, "cumulativeDurationMs": 901.223, "errorCount": 0 }, { "serviceName": "route", "spanCount": 10, "cumulativeDurationMs": 525.791, "errorCount": 0 }, { "serviceName": "driver", "spanCount": 1, "cumulativeDurationMs": 185.873, "errorCount": 0 }, { "serviceName": "redis-manual", "spanCount": 13, "cumulativeDurationMs": 185.419, "errorCount": 2 } ] }
6. get_slowest_spans — Latency Bottleneck Isolation
Sorts spans across the trace by duration descending with pagination to immediately isolate the slowest operations.
- Parameters:
trace_id: str,limit?: int = 10,offset?: int = 0,ping_url?: str - Example Call:
get_slowest_spans(trace_id="0752f19be1bf63061958749442056b18", limit=3) - Actual Output:
{ "traceId": "0752f19be1bf63061958749442056b18", "totalSpans": 39, "limit": 3, "offset": 0, "hasMore": true, "spans": [ { "spanId": "0a5a9c536f8d4c84", "parentSpanId": null, "serviceName": "frontend", "operationName": "GET /dispatch", "durationMs": 1283.191, "statusCode": "OK", "isError": false }, { "spanId": "3b696fe3d834a2dd", "parentSpanId": "ba07eb94ad029741", "serviceName": "customer", "operationName": "GET /customer", "durationMs": 901.223, "statusCode": "OK", "isError": false }, { "spanId": "7b4c28197a5e4033", "parentSpanId": "3b696fe3d834a2dd", "serviceName": "mysql", "operationName": "SQL SELECT", "durationMs": 901.109, "statusCode": "OK", "isError": false } ] }
7. get_trace_errors — Error & Exception Filtering
Filters out healthy spans and returns only failing spans with associated exception events, HTTP error statuses, and relevant error attributes.
- Parameters:
trace_id: str,ping_url?: str - Example Call:
get_trace_errors(trace_id="0752f19be1bf63061958749442056b18") - Actual Output:
{ "traceId": "0752f19be1bf63061958749442056b18", "totalErrors": 2, "errors": [ { "spanId": "6b8040528892c12c", "serviceName": "redis-manual", "operationName": "GetDriver", "durationMs": 31.418, "statusCode": "ERROR", "statusMessage": "", "errorAttributes": { "otel.status_code": "ERROR", "error": true, "otel.status_description": "An error occurred" }, "events": [ { "timestamp": 1791548492624738, "fields": [ { "key": "event", "value": "exception" }, { "key": "exception.message", "value": "redis timeout" }, { "key": "exception.type", "value": "*errors.errorString" } ] } ] } ] }
8. get_span_details — Granular Span Inspection
Returns complete metadata for a single span, including raw tags/attributes, timing nanoseconds, event logs, and all direct child span IDs.
- Parameters:
trace_id: str,span_id: str,ping_url?: str - Example Call:
get_span_details(trace_id="706be6c35bb3a0d5560110c7ed4b9e91", span_id="5820db81696f3244") - Actual Output:
{ "traceId": "706be6c35bb3a0d5560110c7ed4b9e91", "spanId": "5820db81696f3244", "parentSpanId": "79d2fd6e5f9710c1", "serviceName": "driver", "operationName": "driver.DriverService/FindNearest", "startTimeUnixNano": "1791548492244601000", "endTimeUnixNano": "1791548492485296000", "durationMs": 240.695, "statusCode": "OK", "statusMessage": "", "isError": false, "attributes": { "rpc.system.name": "grpc", "rpc.method": "driver.DriverService/FindNearest", "server.address": "127.0.0.1", "server.port": 8082, "span.kind": "server" }, "events": [ { "timestamp": 1791548492301553, "fields": [ { "key": "event", "value": "Retrying GetDriver after error" }, { "key": "error", "value": "redis timeout" }, { "key": "retry_no", "value": 1 } ] }, { "timestamp": 1791548492485236, "fields": [ { "key": "event", "value": "Search successful" }, { "key": "driver_count", "value": 10 } ] } ], "childSpanIds": [ "b1faa12267c0c92d", "46da9189cc53c240" ] }
🔌 Client Configurations
Add jaeger-mcp to your favorite AI assistant or IDE in seconds:
💡 Path Placeholder: In the configurations below, replace
<PATH_TO_JAEGER_MCP>with the absolute path to your cloned repository:
- Windows:
"C:\\path\\to\\jaeger-mcp"(or"C:/path/to/jaeger-mcp")- macOS / Linux:
"/Users/username/jaeger-mcp"or"/home/username/jaeger-mcp"
Claude Desktop (claude_desktop_config.json)
- Windows:
%APPDATA%\Claude\claude_desktop_config.json - macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"jaeger": {
"command": "uvx",
"args": ["mcp-server-jaeger"],
"env": {
"SERVICE_API_VERSION": "v3"
}
}
}
}
Or for local source development:
{
"mcpServers": {
"jaeger": {
"command": "uv",
"args": [
"run",
"--directory",
"<PATH_TO_JAEGER_MCP>",
"python",
"src/jaeger_mcp/main.py"
],
"env": {
"SERVICE_API_VERSION": "v3"
}
}
}
}
Cursor (.cursor/mcp.json)
{
"mcpServers": {
"jaeger": {
"command": "uvx",
"args": ["mcp-server-jaeger"]
}
}
}
Or for local source development:
{
"mcpServers": {
"jaeger": {
"command": "uv",
"args": [
"run",
"--directory",
"<PATH_TO_JAEGER_MCP>",
"python",
"src/jaeger_mcp/main.py"
]
}
}
}
OpenCode (CLI or opencode.json)
Via CLI command:
# Via published package:
opencode mcp add jaeger -- uvx mcp-server-jaeger
# Or from local source:
opencode mcp add jaeger -- uv run --directory <PATH_TO_JAEGER_MCP> python src/jaeger_mcp/main.py
Via opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"jaeger": {
"type": "local",
"command": ["uvx", "mcp-server-jaeger"],
"enabled": true,
"environment": {
"SERVICE_API_VERSION": "v3"
}
}
}
}
Antigravity / Windsurf / Cline / Roo Code
{
"mcpServers": {
"jaeger": {
"command": "uvx",
"args": ["mcp-server-jaeger"],
"transport": "stdio"
}
}
}
Using standard Python / virtualenv instead of uv
{
"mcpServers": {
"jaeger": {
"command": "<PATH_TO_JAEGER_MCP>/.venv/bin/python",
"args": [
"<PATH_TO_JAEGER_MCP>/src/jaeger_mcp/main.py"
],
"env": {
"SERVICE_API_VERSION": "v3"
}
}
}
}
(On Windows, replace with <PATH_TO_JAEGER_MCP>\\.venv\\Scripts\\python.exe)
🏗️ Architecture
jaeger-mcp/
├── src/
│ └── jaeger_mcp/
│ ├── main.py # MCPServer initialization & tool registration
│ ├── tools/
│ │ └── tools.py # MCP tool handlers & default parameters
│ ├── helper/
│ │ └── tool_helper.py # Jaeger REST client, metrics calculation & parsing logic
│ ├── schemas/
│ │ ├── services.py # Pydantic v2 schemas for service and operation models
│ │ └── traces.py # Pydantic v2 schemas for traces, overviews, spans & errors
├── .agents/
│ └── mcp_config.json # Workspace-level AGY / agent configuration
├── pyproject.toml # Project metadata & dependencies
├── uv.lock # Deterministic dependency lockfile
├── example.env # Template environment variables
├── .env # Local runtime environment file
└── README.md # Project documentation
Architectural Highlights
- Stdio Transport: Ultra-lightweight, native process communication conforming to MCP specifications.
- Pydantic v2 Output Validation: Strict typing guarantees that LLM tool outputs are validated and structured.
- Accurate Wall-Clock Math:
get_trace_overviewcalculates real root-to-leaf span times rather than naive sums of overlapping parallel spans. - Heuristic Error Extraction: Filters error tags (
error=true,http.status_code >= 400,rpc.status_code != 0) and automatically isolates associated stack traces and log events.
🧪 Testing & Debugging
# 1. Interactive testing in browser with official MCP Inspector:
npx @modelcontextprotocol/inspector uv run python -m jaeger_mcp.main
# 2. Sanity check package & tool loading:
uv run python -c "import jaeger_mcp; from jaeger_mcp.main import mcp; print(f'Jaeger MCP loaded cleanly with {len(mcp._tool_manager._tools)} tools!')"
# 3. Format and lint with ruff:
uvx ruff check .
uvx ruff format .
❓ Troubleshooting
"cannot connect to jaeger on http://localhost:16686"
- Ensure Jaeger is running (
docker ps | grep jaeger). - If Jaeger runs in Docker or on a remote VM, verify that port
16686is mapped and exposed. - Test using
curl http://localhost:16686in your terminal. - Pass custom URLs in tool calls:
ping_jaeger(ping_url="http://my-internal-jaeger:16686").
"404 Not Found on /api/v3/services"
Older Jaeger instances (v1.x without v3 API support) may use v2. Update your .env file:
SERVICE_API_VERSION=v2
Or verify the API endpoints supported by your Jaeger deployment.
LLM says "Tool execution timed out"
For huge traces (10,000+ spans), fetching raw trace JSON can take time.
- Use
get_trace_summariesfirst to isolate small, specific traces. - Use
get_slowest_spanswith pagination (limit=10, offset=0) instead of dumping the whole trace.
Metadata
Release files for mcp-server-jaeger 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcp_server_jaeger-0.1.0.tar.gz | 22.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_server_jaeger-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.2 kB
Release files / mcp_server_jaeger-0.1.0.tar.gz
| Download URL | mcp_server_jaeger-0.1.0.tar.gz |
|---|---|
| Size | 22.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6ac5590c0beeaf356662ba0df588c72340e2fdfa5f3509f8dc97745e6177bc21
|
|
BLAKE2b-256 checksum How to use checksums |
1c7fa0a36717f3fb1abce22a89f64602861c44ffeed4858fce71bb996f289c85
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.22 {"installer":{"name":"uv","version":"0.11.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / mcp_server_jaeger-0.1.0-py3-none-any.whl
| Download URL | mcp_server_jaeger-0.1.0-py3-none-any.whl |
|---|---|
| Size | 17.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
875ffbc2d7248377c4f19585e1ae93d14310d2a99be1eea1ec52641a0ba7bd54
|
|
BLAKE2b-256 checksum How to use checksums |
5f28ecc12e76285a43c41f13716319c9dbae7afcab730a7856fc5299665387d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.22 {"installer":{"name":"uv","version":"0.11.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|