OTEL MCP Server
# OTEL MCP Server
Agentic: An MCP-native observability surface that lets agents query their own execution history.
Human Centric: Query and analyze distributed traces with AI assistance for debugging and performance optimization.
## Features
- **Service Discovery**: List services and operations in your Jaeger instance
- **Trace Inspection**: Search, filter, and inspect traces with full span details
- **Performance Analysis**: Find slow traces, get latency percentiles, error rates
- **REST API**: FastAPI endpoints with OpenAPI documentation at `/docs`
- **Self-Telemetry**: The server traces itself to Jaeger for debugging
## Installation
### Using uvx (Recommended)
Run directly without installing:
```bash
# Run MCP server
uvx otel-mcp
# Run REST API
uvx --from otel-mcp otel-mcp-api
```
### Using pip
```bash
pip install otel-mcp
# Then run
otel-mcp # MCP server
otel-mcp-api # REST API
```
### From Source
```bash
git clone https://github.com/ryanm101/otel-mcp.git
cd otel-mcp
uv sync
uv run otel-mcp
```
## Quick Start
### 1. Start Jaeger
```bash
docker-compose up -d
# Jaeger UI at http://localhost:16686
```
### 2. Run the MCP Server
```bash
uvx otel-mcp
# Or with environment variables:
JAEGER_URL=http://jaeger:16686 uvx otel-mcp
```
### 3. Or Run the REST API
```bash
uvx --from otel-mcp otel-mcp-api
# OpenAPI docs at http://localhost:8000/docs
```
## MCP Client Configuration
Add to your MCP client config (e.g., Claude Desktop `claude_desktop_config.json`):
```json
{
"mcpServers": {
"otel-mcp": {
"command": "uvx",
"args": ["otel-mcp"],
"env": {
"JAEGER_URL": "http://localhost:16686"
}
}
}
}
```
## Configuration
Create a `.env` file (see `.env.example`):
```env
JAEGER_URL=http://localhost:16686
JAEGER_TIMEOUT=30
LOG_LEVEL=INFO
# Self-telemetry (optional)
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
OTEL_SERVICE_NAME=otel-mcp
# OTEL_SDK_DISABLED=true # Disable self-telemetry
```
## MCP Tools
### Service Discovery
| Tool | Description |
|------|-------------|
| `list_services` | List all services in Jaeger |
| `list_operations` | List operations for a service |
### Trace Inspection
| Tool | Description |
|------|-------------|
| `search_traces` | Search traces with filters (service, operation, duration, errors) |
| `get_trace` | Get complete trace by ID with all spans |
| `find_errors` | Find traces containing errors |
### Performance Analysis
| Tool | Description |
|------|-------------|
| `get_slow_traces` | Find slowest traces |
| `get_operation_stats` | Get latency percentiles (p50/p95/p99) and error rates |
## REST API Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/health` | GET | Health check |
| `/services` | GET | List services |
| `/services/{name}/operations` | GET | List operations |
| `/traces` | GET | Search traces |
| `/traces/{trace_id}` | GET | Get trace by ID |
| `/traces/errors` | GET | Find error traces |
| `/traces/slow` | GET | Find slow traces |
## Development
### Run Tests
```bash
uv run pytest tests/ -v
```
### Run with Coverage
```bash
uv run pytest tests/ --cov=otel_mcp --cov-report=term-missing
```
### Lint and Type Check
```bash
uv run ruff check src/
uv run mypy src/
```
### Adding a New Backend
1. Create `backends/tempo.py` implementing `BaseBackend`
2. Add backend type to `config.py`
3. Update `_create_backend()` in `server.py` and `api.py`
## License
Apache-2.0
TDQS
Scored across 7 tools
find_errors and search_traces with has_error overlap significantly, as do get_slow_traces and search_traces with duration filters. While get_trace, get_operation_stats, list_services, and list_operations are clearly distinct, the overlapping search/filter tools could cause misselection.
All tool names follow a consistent verb_noun pattern (get_, find_, list_, search_). The convention is predictable and readable throughout.
Seven tools are well-scoped for an observability server covering trace retrieval, error finding, performance analysis, and service discovery. Each tool appears to earn its place without excessive overlap or missing essentials.
The surface covers the full trace lifecycle: discovery (list_services, list_operations), retrieval (get_trace, search_traces), error analysis (find_errors), and performance stats (get_operation_stats, get_slow_traces). No obvious gaps for a read-only OTEL/Jaeger server.