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.
- mcp_server_jaeger-0.1.0/LICENSE +21 -0
- mcp_server_jaeger-0.1.0/PKG-INFO +675 -0
- mcp_server_jaeger-0.1.0/README.md +644 -0
- mcp_server_jaeger-0.1.0/pyproject.toml +74 -0
- mcp_server_jaeger-0.1.0/setup.cfg +4 -0
- mcp_server_jaeger-0.1.0/src/jaeger_mcp/__init__.py +3 -0
- mcp_server_jaeger-0.1.0/src/jaeger_mcp/helper/tool_helper.py +410 -0
- mcp_server_jaeger-0.1.0/src/jaeger_mcp/main.py +55 -0
- mcp_server_jaeger-0.1.0/src/jaeger_mcp/schemas/services.py +18 -0
- mcp_server_jaeger-0.1.0/src/jaeger_mcp/schemas/traces.py +150 -0
- mcp_server_jaeger-0.1.0/src/jaeger_mcp/tools/tools.py +141 -0
- mcp_server_jaeger-0.1.0/src/mcp_server_jaeger.egg-info/PKG-INFO +675 -0
- mcp_server_jaeger-0.1.0/src/mcp_server_jaeger.egg-info/SOURCES.txt +15 -0
- mcp_server_jaeger-0.1.0/src/mcp_server_jaeger.egg-info/dependency_links.txt +1 -0
- mcp_server_jaeger-0.1.0/src/mcp_server_jaeger.egg-info/entry_points.txt +3 -0
- mcp_server_jaeger-0.1.0/src/mcp_server_jaeger.egg-info/requires.txt +4 -0
- mcp_server_jaeger-0.1.0/src/mcp_server_jaeger.egg-info/top_level.txt +1 -0
|
@@ -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
|
+
[](https://pypi.org/project/mcp-server-jaeger/)
|
|
39
|
+
[](https://modelcontextprotocol.io/)
|
|
40
|
+
[](https://python.org)
|
|
41
|
+
[](https://github.com/modelcontextprotocol/python-sdk)
|
|
42
|
+
[](https://www.jaegertracing.io/)
|
|
43
|
+
[](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> — 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> — 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> — 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> — 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> — 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> — 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> — 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> — 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>
|