mcp-server-jaeger 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chahat Sagar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,675 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-server-jaeger
3
+ Version: 0.1.0
4
+ Summary: Context-efficient Model Context Protocol (MCP) server for Jaeger distributed tracing
5
+ Author-email: Chahat Sagar <chahatsagar2003@gmail.com>
6
+ Maintainer-email: Chahat Sagar <chahatsagar2003@gmail.com>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/chahatsagarmain/jaeger-mcp
9
+ Project-URL: Repository, https://github.com/chahatsagarmain/jaeger-mcp
10
+ Project-URL: Issues, https://github.com/chahatsagarmain/jaeger-mcp/issues
11
+ Project-URL: Documentation, https://github.com/chahatsagarmain/jaeger-mcp#readme
12
+ Keywords: mcp,model-context-protocol,jaeger,opentelemetry,tracing,distributed-tracing,observability,telemetry,ai,llm,claude,cursor
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Bug Tracking
20
+ Classifier: Topic :: System :: Monitoring
21
+ Classifier: Topic :: System :: Distributed Computing
22
+ Classifier: Topic :: System :: Systems Administration
23
+ Requires-Python: >=3.11
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: mcp[cli]>=2.3.0
27
+ Requires-Dist: pydantic>=2.13.5
28
+ Requires-Dist: python-dotenv>=1.2.4
29
+ Requires-Dist: requests>=2.34.2
30
+ Dynamic: license-file
31
+
32
+ <div align="center">
33
+
34
+ # โšก Jaeger MCP Server
35
+
36
+ **Context-Efficient Observability & Distributed Tracing for AI Agents**
37
+
38
+ [![PyPI version](https://img.shields.io/badge/PyPI-mcp--server--jaeger-blue?style=flat-square&logo=pypi&logoColor=white)](https://pypi.org/project/mcp-server-jaeger/)
39
+ [![Model Context Protocol](https://img.shields.io/badge/MCP-Compatible-blueviolet?style=flat-square&logo=anthropic)](https://modelcontextprotocol.io/)
40
+ [![Python](https://img.shields.io/badge/Python-3.11+-3776AB?style=flat-square&logo=python&logoColor=white)](https://python.org)
41
+ [![FastMCP / MCP SDK](https://img.shields.io/badge/MCP%20SDK-v2.3+-green?style=flat-square)](https://github.com/modelcontextprotocol/python-sdk)
42
+ [![Jaeger](https://img.shields.io/badge/Jaeger-Distributed%20Tracing-60D0E4?style=flat-square&logo=jaeger&logoColor=white)](https://www.jaegertracing.io/)
43
+ [![License](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](LICENSE)
44
+
45
+ *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.*
46
+
47
+ ---
48
+
49
+ [๐Ÿš€ Quickstart](#-quickstart) โ€ข
50
+ [๐ŸŽฏ Why Jaeger MCP?](#-why-jaeger-mcp) โ€ข
51
+ [๐Ÿ› ๏ธ Tools Reference](#๏ธ-tools-reference) โ€ข
52
+ [๐Ÿ”Œ Client Configurations](#-client-configurations) โ€ข
53
+ [๐Ÿ—๏ธ Architecture](#๏ธ-architecture) โ€ข
54
+ [๐Ÿงช Testing & Debugging](#-testing--debugging)
55
+
56
+ ---
57
+
58
+ </div>
59
+
60
+ ## ๐ŸŽฏ Why Jaeger MCP?
61
+
62
+ Distributed traces in production systems easily contain **hundreds to thousands of spans**, deep call graphs, and megabytes of JSON tags and log events.
63
+
64
+ If an AI assistant ingests an entire raw trace:
65
+ 1. ๐Ÿ’ธ **Context Window Explosion:** Traces consume tens of thousands of tokens per prompt.
66
+ 2. ๐Ÿ“‰ **Hallucinations & Noise:** LLMs struggle to locate relevant errors buried beneath healthy spans.
67
+ 3. ๐ŸŒ **High Latency & Costs:** Huge payloads slow down response times and skyrocket API billing.
68
+
69
+ **`jaeger-mcp` solves this with a 5-Stage Progressive Discovery Funnel:**
70
+
71
+ ```mermaid
72
+ flowchart TD
73
+ A[๐Ÿ” 1. Service Discovery<br/>get_all_services / get_operations_for_service] --> B[๐Ÿ“Š 2. Trace Discovery<br/>get_trace_summaries]
74
+ B --> C[๐Ÿ“ˆ 3. High-Level Triage<br/>get_trace_overview]
75
+ C -->|High Latency| D[โฑ๏ธ 4a. Bottleneck Isolation<br/>get_slowest_spans]
76
+ C -->|Failures / 5xx| E[๐Ÿ’ฅ 4b. Error Filtering<br/>get_trace_errors]
77
+ D --> F[๐Ÿ”ฌ 5. Deep-Dive Inspection<br/>get_span_details]
78
+ E --> F
79
+ F --> G[๐ŸŽฏ Instant Root-Cause Resolution]
80
+
81
+ style A fill:#2d3748,stroke:#4a5568,color:#fff
82
+ style B fill:#2b6cb0,stroke:#3182ce,color:#fff
83
+ style C fill:#2c5282,stroke:#2b6cb0,color:#fff
84
+ style D fill:#c05621,stroke:#dd6b20,color:#fff
85
+ style E fill:#9b2c2c,stroke:#e53e3e,color:#fff
86
+ style F fill:#285e61,stroke:#319795,color:#fff
87
+ style G fill:#22543d,stroke:#38a169,color:#fff
88
+ ```
89
+
90
+ Instead of sending 2MB raw trace blobs, the agent queries structured, paginated, and summarized slices of observability data.
91
+
92
+ ---
93
+
94
+ ## ๐Ÿš€ Quickstart
95
+
96
+ ### Prerequisites
97
+ - **Python**: `3.11` or newer
98
+ - **Package Manager**: [`uv`](https://docs.astral.sh/uv/) (recommended) or standard `pip`
99
+ - **Jaeger Instance**: Local or remote Jaeger Query service (default port `16686`)
100
+
101
+ ### Installation & Run Options
102
+
103
+ #### Option 1: Instant Run with `uvx` (Recommended & Zero Setup)
104
+ ```bash
105
+ uvx mcp-server-jaeger
106
+ ```
107
+
108
+ #### Option 2: Install via PyPI
109
+ ```bash
110
+ pip install mcp-server-jaeger
111
+ mcp-server-jaeger
112
+ ```
113
+
114
+ #### Option 3: Run with Docker
115
+ ```bash
116
+ docker run -i --rm --network=host -e SERVICE_API_VERSION=v3 ghcr.io/chahatsagarmain/jaeger-mcp:latest
117
+ ```
118
+
119
+ #### Option 4: From Source (Development)
120
+ ```bash
121
+ git clone https://github.com/chahatsagarmain/jaeger-mcp.git
122
+ cd jaeger-mcp
123
+ cp example.env .env
124
+ uv sync
125
+ uv run python -m jaeger_mcp.main
126
+ ```
127
+
128
+ ### 2. Spin up Local Jaeger & HotROD Demo (Optional)
129
+
130
+ ```bash
131
+ # 1. Run Jaeger UI + Query API + OTLP Collector
132
+ docker run --rm --name jaeger \
133
+ -p 16686:16686 \
134
+ -p 4317:4317 \
135
+ -p 4318:4318 \
136
+ -p 5778:5778 \
137
+ -p 9411:9411 \
138
+ cr.jaegertracing.io/jaegertracing/jaeger:2.22.0
139
+
140
+ # 2. Run HotROD to generate realistic distributed traffic connected to Jaeger
141
+ docker run --rm -it --name hotrod \
142
+ -p 8080:8080 \
143
+ --link jaeger:jaeger \
144
+ -e OTEL_EXPORTER_OTLP_ENDPOINT="http://jaeger:4318" \
145
+ cr.jaegertracing.io/jaegertracing/example-hotrod:2.22.0 all
146
+ ```
147
+
148
+ - **Jaeger UI**: [http://localhost:16686](http://localhost:16686)
149
+ - **HotROD Demo UI**: [http://localhost:8080](http://localhost:8080) (click buttons to generate traces)
150
+
151
+ ---
152
+
153
+ ## โš™๏ธ Configuration & Environment
154
+
155
+ The server reads configuration from `.env` in the project root:
156
+
157
+ | Variable | Default Value | Description |
158
+ |:---|:---:|:---|
159
+ | `SERVICE_API_VERSION` | `v3` | Jaeger Query API version for services/operations/summaries (`v3` or `v2`) |
160
+
161
+ > **Note on Jaeger URL:** Each tool accepts an optional `ping_url` argument (defaults to `http://localhost:16686`). You can target local dev instances, staging clusters, or remote production Jaeger UI proxies on the fly.
162
+
163
+ ---
164
+
165
+ ## ๐Ÿ› ๏ธ Tools Reference
166
+
167
+ | Tool | Signature | Purpose |
168
+ |:---|:---|:---|
169
+ | [`ping_jaeger`](#1-ping_jaeger) | `ping_url: str` | Healthcheck Jaeger connectivity |
170
+ | [`get_all_services`](#2-get_all_services) | `ping_url: str` | List all instrumented microservices |
171
+ | [`get_operations_for_service`](#3-get_operations_for_service) | `service_name: str, ping_url: str` | List operations/endpoints & span kinds for a service |
172
+ | [`get_trace_summaries`](#4-get_trace_summaries) | `service_name, start_time_min?, start_time_max?, search_depth?, operation_name?, ping_url?` | Search recent traces with duration & span counts |
173
+ | [`get_trace_overview`](#5-get_trace_overview) | `trace_id: str, ping_url: str` | Wall-clock duration, error counts, and per-service breakdown |
174
+ | [`get_slowest_spans`](#6-get_slowest_spans) | `trace_id: str, limit?: int, offset?: int, ping_url: str` | Paginated bottleneck isolation sorted by duration descending |
175
+ | [`get_trace_errors`](#7-get_trace_errors) | `trace_id: str, ping_url: str` | Isolate failed spans, HTTP status codes, and exception logs |
176
+ | [`get_span_details`](#8-get_span_details) | `trace_id: str, span_id: str, ping_url: str` | Granular span inspect: attributes, logs/events, and child span IDs |
177
+
178
+ ---
179
+
180
+ ### Tool Outputs & Real Examples
181
+
182
+ <details open>
183
+ <summary><b>1. <code>ping_jaeger</code></b> &mdash; Connection Healthcheck</summary>
184
+
185
+ Verifies that the Jaeger HTTP endpoint is reachable.
186
+
187
+ - **Parameters:** `ping_url: str = "http://localhost:16686"`
188
+ - **Example Call:** `ping_jaeger()`
189
+ - **Actual Output:**
190
+ ```text
191
+ "jaeger accessible on http://localhost:16686"
192
+ ```
193
+ </details>
194
+
195
+ <details>
196
+ <summary><b>2. <code>get_all_services</code></b> &mdash; Service Discovery</summary>
197
+
198
+ Fetches every service registered in Jaeger's registry.
199
+
200
+ - **Parameters:** `ping_url: str = "http://localhost:16686"`
201
+ - **Example Call:** `get_all_services()`
202
+ - **Actual Output:**
203
+ ```json
204
+ {
205
+ "services": [
206
+ "customer",
207
+ "driver",
208
+ "frontend",
209
+ "jaeger",
210
+ "mysql",
211
+ "redis-manual",
212
+ "route"
213
+ ]
214
+ }
215
+ ```
216
+ </details>
217
+
218
+ <details>
219
+ <summary><b>3. <code>get_operations_for_service</code></b> &mdash; Operation Discovery</summary>
220
+
221
+ Lists all instrumented endpoints and span kinds for a specific service.
222
+
223
+ - **Parameters:** `service_name: str`, `ping_url: str = "http://localhost:16686"`
224
+ - **Example Call:** `get_operations_for_service(service_name="driver")`
225
+ - **Actual Output:**
226
+ ```json
227
+ {
228
+ "operations": [
229
+ {
230
+ "name": "driver.DriverService/FindNearest",
231
+ "spanKind": "server"
232
+ }
233
+ ]
234
+ }
235
+ ```
236
+ </details>
237
+
238
+ <details>
239
+ <summary><b>4. <code>get_trace_summaries</code></b> &mdash; Filtered Trace Search</summary>
240
+
241
+ Queries traces matching service, operation, and time filters (defaults to the last 1 hour).
242
+
243
+ - **Parameters:** `service_name: str`, `start_time_min?: str`, `start_time_max?: str`, `search_depth?: int = 20`, `operation_name?: str`, `ping_url?: str`
244
+ - **Example Call:** `get_trace_summaries(service_name="driver", search_depth=1)`
245
+ - **Actual Output:**
246
+ ```json
247
+ {
248
+ "summaries": [
249
+ {
250
+ "traceId": "0752f19be1bf63061958749442056b18",
251
+ "rootServiceName": "frontend",
252
+ "rootOperationName": "GET /dispatch",
253
+ "minStartTimeUnixNano": "1791548491657998220",
254
+ "maxEndTimeUnixNano": "1791548492941190177",
255
+ "spanCount": 39,
256
+ "services": [
257
+ { "name": "frontend", "spanCount": 13 },
258
+ { "name": "redis-manual", "spanCount": 13 },
259
+ { "name": "route", "spanCount": 10 },
260
+ { "name": "driver", "spanCount": 1 },
261
+ { "name": "customer", "spanCount": 1 },
262
+ { "name": "mysql", "spanCount": 1 }
263
+ ]
264
+ }
265
+ ]
266
+ }
267
+ ```
268
+ </details>
269
+
270
+ <details>
271
+ <summary><b>5. <code>get_trace_overview</code></b> &mdash; Wall-Clock & Service Breakdown</summary>
272
+
273
+ Computes real wall-clock duration across the entire trace distributed graph, aggregate span counts, error counts, and per-service duration/error breakdown.
274
+
275
+ - **Parameters:** `trace_id: str`, `ping_url?: str`
276
+ - **Example Call:** `get_trace_overview(trace_id="0752f19be1bf63061958749442056b18")`
277
+ - **Actual Output:**
278
+ ```json
279
+ {
280
+ "traceId": "0752f19be1bf63061958749442056b18",
281
+ "rootServiceName": "frontend",
282
+ "rootOperationName": "GET /dispatch",
283
+ "totalDurationMs": 1283.191,
284
+ "spanCount": 39,
285
+ "errorCount": 2,
286
+ "hasErrors": true,
287
+ "services": [
288
+ { "serviceName": "frontend", "spanCount": 13, "cumulativeDurationMs": 2899.862, "errorCount": 0 },
289
+ { "serviceName": "mysql", "spanCount": 1, "cumulativeDurationMs": 901.109, "errorCount": 0 },
290
+ { "serviceName": "customer", "spanCount": 1, "cumulativeDurationMs": 901.223, "errorCount": 0 },
291
+ { "serviceName": "route", "spanCount": 10, "cumulativeDurationMs": 525.791, "errorCount": 0 },
292
+ { "serviceName": "driver", "spanCount": 1, "cumulativeDurationMs": 185.873, "errorCount": 0 },
293
+ { "serviceName": "redis-manual", "spanCount": 13, "cumulativeDurationMs": 185.419, "errorCount": 2 }
294
+ ]
295
+ }
296
+ ```
297
+ </details>
298
+
299
+ <details>
300
+ <summary><b>6. <code>get_slowest_spans</code></b> &mdash; Latency Bottleneck Isolation</summary>
301
+
302
+ Sorts spans across the trace by duration descending with pagination to immediately isolate the slowest operations.
303
+
304
+ - **Parameters:** `trace_id: str`, `limit?: int = 10`, `offset?: int = 0`, `ping_url?: str`
305
+ - **Example Call:** `get_slowest_spans(trace_id="0752f19be1bf63061958749442056b18", limit=3)`
306
+ - **Actual Output:**
307
+ ```json
308
+ {
309
+ "traceId": "0752f19be1bf63061958749442056b18",
310
+ "totalSpans": 39,
311
+ "limit": 3,
312
+ "offset": 0,
313
+ "hasMore": true,
314
+ "spans": [
315
+ {
316
+ "spanId": "0a5a9c536f8d4c84",
317
+ "parentSpanId": null,
318
+ "serviceName": "frontend",
319
+ "operationName": "GET /dispatch",
320
+ "durationMs": 1283.191,
321
+ "statusCode": "OK",
322
+ "isError": false
323
+ },
324
+ {
325
+ "spanId": "3b696fe3d834a2dd",
326
+ "parentSpanId": "ba07eb94ad029741",
327
+ "serviceName": "customer",
328
+ "operationName": "GET /customer",
329
+ "durationMs": 901.223,
330
+ "statusCode": "OK",
331
+ "isError": false
332
+ },
333
+ {
334
+ "spanId": "7b4c28197a5e4033",
335
+ "parentSpanId": "3b696fe3d834a2dd",
336
+ "serviceName": "mysql",
337
+ "operationName": "SQL SELECT",
338
+ "durationMs": 901.109,
339
+ "statusCode": "OK",
340
+ "isError": false
341
+ }
342
+ ]
343
+ }
344
+ ```
345
+ </details>
346
+
347
+ <details>
348
+ <summary><b>7. <code>get_trace_errors</code></b> &mdash; Error & Exception Filtering</summary>
349
+
350
+ Filters out healthy spans and returns only failing spans with associated exception events, HTTP error statuses, and relevant error attributes.
351
+
352
+ - **Parameters:** `trace_id: str`, `ping_url?: str`
353
+ - **Example Call:** `get_trace_errors(trace_id="0752f19be1bf63061958749442056b18")`
354
+ - **Actual Output:**
355
+ ```json
356
+ {
357
+ "traceId": "0752f19be1bf63061958749442056b18",
358
+ "totalErrors": 2,
359
+ "errors": [
360
+ {
361
+ "spanId": "6b8040528892c12c",
362
+ "serviceName": "redis-manual",
363
+ "operationName": "GetDriver",
364
+ "durationMs": 31.418,
365
+ "statusCode": "ERROR",
366
+ "statusMessage": "",
367
+ "errorAttributes": {
368
+ "otel.status_code": "ERROR",
369
+ "error": true,
370
+ "otel.status_description": "An error occurred"
371
+ },
372
+ "events": [
373
+ {
374
+ "timestamp": 1791548492624738,
375
+ "fields": [
376
+ { "key": "event", "value": "exception" },
377
+ { "key": "exception.message", "value": "redis timeout" },
378
+ { "key": "exception.type", "value": "*errors.errorString" }
379
+ ]
380
+ }
381
+ ]
382
+ }
383
+ ]
384
+ }
385
+ ```
386
+ </details>
387
+
388
+ <details>
389
+ <summary><b>8. <code>get_span_details</code></b> &mdash; Granular Span Inspection</summary>
390
+
391
+ Returns complete metadata for a single span, including raw tags/attributes, timing nanoseconds, event logs, and all direct child span IDs.
392
+
393
+ - **Parameters:** `trace_id: str`, `span_id: str`, `ping_url?: str`
394
+ - **Example Call:** `get_span_details(trace_id="706be6c35bb3a0d5560110c7ed4b9e91", span_id="5820db81696f3244")`
395
+ - **Actual Output:**
396
+ ```json
397
+ {
398
+ "traceId": "706be6c35bb3a0d5560110c7ed4b9e91",
399
+ "spanId": "5820db81696f3244",
400
+ "parentSpanId": "79d2fd6e5f9710c1",
401
+ "serviceName": "driver",
402
+ "operationName": "driver.DriverService/FindNearest",
403
+ "startTimeUnixNano": "1791548492244601000",
404
+ "endTimeUnixNano": "1791548492485296000",
405
+ "durationMs": 240.695,
406
+ "statusCode": "OK",
407
+ "statusMessage": "",
408
+ "isError": false,
409
+ "attributes": {
410
+ "rpc.system.name": "grpc",
411
+ "rpc.method": "driver.DriverService/FindNearest",
412
+ "server.address": "127.0.0.1",
413
+ "server.port": 8082,
414
+ "span.kind": "server"
415
+ },
416
+ "events": [
417
+ {
418
+ "timestamp": 1791548492301553,
419
+ "fields": [
420
+ { "key": "event", "value": "Retrying GetDriver after error" },
421
+ { "key": "error", "value": "redis timeout" },
422
+ { "key": "retry_no", "value": 1 }
423
+ ]
424
+ },
425
+ {
426
+ "timestamp": 1791548492485236,
427
+ "fields": [
428
+ { "key": "event", "value": "Search successful" },
429
+ { "key": "driver_count", "value": 10 }
430
+ ]
431
+ }
432
+ ],
433
+ "childSpanIds": [
434
+ "b1faa12267c0c92d",
435
+ "46da9189cc53c240"
436
+ ]
437
+ }
438
+ ```
439
+ </details>
440
+
441
+ ---
442
+
443
+ ## ๐Ÿ”Œ Client Configurations
444
+
445
+ Add `jaeger-mcp` to your favorite AI assistant or IDE in seconds:
446
+
447
+ > ๐Ÿ’ก **Path Placeholder:** In the configurations below, replace `<PATH_TO_JAEGER_MCP>` with the absolute path to your cloned repository:
448
+ > - **Windows:** `"C:\\path\\to\\jaeger-mcp"` (or `"C:/path/to/jaeger-mcp"`)
449
+ > - **macOS / Linux:** `"/Users/username/jaeger-mcp"` or `"/home/username/jaeger-mcp"`
450
+
451
+ <details open>
452
+ <summary><b>Claude Desktop</b> (<code>claude_desktop_config.json</code>)</summary>
453
+
454
+ - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
455
+ - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
456
+
457
+ ```json
458
+ {
459
+ "mcpServers": {
460
+ "jaeger": {
461
+ "command": "uvx",
462
+ "args": ["mcp-server-jaeger"],
463
+ "env": {
464
+ "SERVICE_API_VERSION": "v3"
465
+ }
466
+ }
467
+ }
468
+ }
469
+ ```
470
+
471
+ *Or for local source development:*
472
+ ```json
473
+ {
474
+ "mcpServers": {
475
+ "jaeger": {
476
+ "command": "uv",
477
+ "args": [
478
+ "run",
479
+ "--directory",
480
+ "<PATH_TO_JAEGER_MCP>",
481
+ "python",
482
+ "src/jaeger_mcp/main.py"
483
+ ],
484
+ "env": {
485
+ "SERVICE_API_VERSION": "v3"
486
+ }
487
+ }
488
+ }
489
+ }
490
+ ```
491
+ </details>
492
+
493
+ <details>
494
+ <summary><b>Cursor</b> (<code>.cursor/mcp.json</code>)</summary>
495
+
496
+ ```json
497
+ {
498
+ "mcpServers": {
499
+ "jaeger": {
500
+ "command": "uvx",
501
+ "args": ["mcp-server-jaeger"]
502
+ }
503
+ }
504
+ }
505
+ ```
506
+
507
+ *Or for local source development:*
508
+ ```json
509
+ {
510
+ "mcpServers": {
511
+ "jaeger": {
512
+ "command": "uv",
513
+ "args": [
514
+ "run",
515
+ "--directory",
516
+ "<PATH_TO_JAEGER_MCP>",
517
+ "python",
518
+ "src/jaeger_mcp/main.py"
519
+ ]
520
+ }
521
+ }
522
+ }
523
+ ```
524
+ </details>
525
+
526
+ <details>
527
+ <summary><b>OpenCode</b> (CLI or <code>opencode.json</code>)</summary>
528
+
529
+ **Via CLI command:**
530
+ ```bash
531
+ # Via published package:
532
+ opencode mcp add jaeger -- uvx mcp-server-jaeger
533
+
534
+ # Or from local source:
535
+ opencode mcp add jaeger -- uv run --directory <PATH_TO_JAEGER_MCP> python src/jaeger_mcp/main.py
536
+ ```
537
+
538
+ **Via `opencode.json`:**
539
+ ```json
540
+ {
541
+ "$schema": "https://opencode.ai/config.json",
542
+ "mcp": {
543
+ "jaeger": {
544
+ "type": "local",
545
+ "command": ["uvx", "mcp-server-jaeger"],
546
+ "enabled": true,
547
+ "environment": {
548
+ "SERVICE_API_VERSION": "v3"
549
+ }
550
+ }
551
+ }
552
+ }
553
+ ```
554
+ </details>
555
+
556
+ <details>
557
+ <summary><b>Antigravity / Windsurf / Cline / Roo Code</b></summary>
558
+
559
+ ```json
560
+ {
561
+ "mcpServers": {
562
+ "jaeger": {
563
+ "command": "uvx",
564
+ "args": ["mcp-server-jaeger"],
565
+ "transport": "stdio"
566
+ }
567
+ }
568
+ }
569
+ ```
570
+ </details>
571
+
572
+ <details>
573
+ <summary><b>Using standard Python / virtualenv instead of <code>uv</code></b></summary>
574
+
575
+ ```json
576
+ {
577
+ "mcpServers": {
578
+ "jaeger": {
579
+ "command": "<PATH_TO_JAEGER_MCP>/.venv/bin/python",
580
+ "args": [
581
+ "<PATH_TO_JAEGER_MCP>/src/jaeger_mcp/main.py"
582
+ ],
583
+ "env": {
584
+ "SERVICE_API_VERSION": "v3"
585
+ }
586
+ }
587
+ }
588
+ }
589
+ ```
590
+ *(On Windows, replace with `<PATH_TO_JAEGER_MCP>\\.venv\\Scripts\\python.exe`)*
591
+ </details>
592
+
593
+ ---
594
+
595
+ ## ๐Ÿ—๏ธ Architecture
596
+
597
+ ```
598
+ jaeger-mcp/
599
+ โ”œโ”€โ”€ src/
600
+ โ”‚ โ””โ”€โ”€ jaeger_mcp/
601
+ โ”‚ โ”œโ”€โ”€ main.py # MCPServer initialization & tool registration
602
+ โ”‚ โ”œโ”€โ”€ tools/
603
+ โ”‚ โ”‚ โ””โ”€โ”€ tools.py # MCP tool handlers & default parameters
604
+ โ”‚ โ”œโ”€โ”€ helper/
605
+ โ”‚ โ”‚ โ””โ”€โ”€ tool_helper.py # Jaeger REST client, metrics calculation & parsing logic
606
+ โ”‚ โ”œโ”€โ”€ schemas/
607
+ โ”‚ โ”‚ โ”œโ”€โ”€ services.py # Pydantic v2 schemas for service and operation models
608
+ โ”‚ โ”‚ โ””โ”€โ”€ traces.py # Pydantic v2 schemas for traces, overviews, spans & errors
609
+ โ”œโ”€โ”€ .agents/
610
+ โ”‚ โ””โ”€โ”€ mcp_config.json # Workspace-level AGY / agent configuration
611
+ โ”œโ”€โ”€ pyproject.toml # Project metadata & dependencies
612
+ โ”œโ”€โ”€ uv.lock # Deterministic dependency lockfile
613
+ โ”œโ”€โ”€ example.env # Template environment variables
614
+ โ”œโ”€โ”€ .env # Local runtime environment file
615
+ โ””โ”€โ”€ README.md # Project documentation
616
+ ```
617
+
618
+ ### Architectural Highlights
619
+ - **Stdio Transport**: Ultra-lightweight, native process communication conforming to MCP specifications.
620
+ - **Pydantic v2 Output Validation**: Strict typing guarantees that LLM tool outputs are validated and structured.
621
+ - **Accurate Wall-Clock Math**: `get_trace_overview` calculates real root-to-leaf span times rather than naive sums of overlapping parallel spans.
622
+ - **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.
623
+
624
+ ---
625
+
626
+ ## ๐Ÿงช Testing & Debugging
627
+
628
+ ```bash
629
+ # 1. Interactive testing in browser with official MCP Inspector:
630
+ npx @modelcontextprotocol/inspector uv run python -m jaeger_mcp.main
631
+
632
+ # 2. Sanity check package & tool loading:
633
+ 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!')"
634
+
635
+ # 3. Format and lint with ruff:
636
+ uvx ruff check .
637
+ uvx ruff format .
638
+ ```
639
+
640
+ ---
641
+
642
+ ## โ“ Troubleshooting
643
+
644
+ <details>
645
+ <summary><b>"cannot connect to jaeger on http://localhost:16686"</b></summary>
646
+
647
+ 1. Ensure Jaeger is running (`docker ps | grep jaeger`).
648
+ 2. If Jaeger runs in Docker or on a remote VM, verify that port `16686` is mapped and exposed.
649
+ 3. Test using `curl http://localhost:16686` in your terminal.
650
+ 4. Pass custom URLs in tool calls: `ping_jaeger(ping_url="http://my-internal-jaeger:16686")`.
651
+ </details>
652
+
653
+ <details>
654
+ <summary><b>"404 Not Found on /api/v3/services"</b></summary>
655
+
656
+ Older Jaeger instances (v1.x without v3 API support) may use `v2`. Update your `.env` file:
657
+ ```env
658
+ SERVICE_API_VERSION=v2
659
+ ```
660
+ Or verify the API endpoints supported by your Jaeger deployment.
661
+ </details>
662
+
663
+ <details>
664
+ <summary><b>LLM says "Tool execution timed out"</b></summary>
665
+
666
+ For huge traces (10,000+ spans), fetching raw trace JSON can take time.
667
+ - Use `get_trace_summaries` first to isolate small, specific traces.
668
+ - Use `get_slowest_spans` with pagination (`limit=10, offset=0`) instead of dumping the whole trace.
669
+ </details>
670
+
671
+ ---
672
+
673
+ <div align="center">
674
+ <sub>Built with โค๏ธ for observability engineers and AI-assisted DevOps workflows.</sub>
675
+ </div>