Metadata-Version: 2.4
Name: opentelemetry-mcp
Version: 0.1.0
Summary: MCP server for querying OpenTelemetry traces from LLM applications with Opentelemetry support
Project-URL: Homepage, https://github.com/traceloop/opentelemetry-mcp-server
Project-URL: Documentation, https://github.com/traceloop/opentelemetry-mcp-server#readme
Project-URL: Repository, https://github.com/traceloop/opentelemetry-mcp-server
Project-URL: Issues, https://github.com/traceloop/opentelemetry-mcp-server/issues
Project-URL: Changelog, https://github.com/traceloop/opentelemetry-mcp-server/blob/main/CHANGELOG.md
Author-email: Doron Kopit <doron@traceloop.com>, Gal Klienman <gal@traceloop.com>, Nir Gazit <nir@traceloop.com>
License: Apache-2.0
License-File: LICENSE
Keywords: debugging,jaeger,llm,mcp,model-context-protocol,observability,opentelemetry,telemetry,tempo,traceloop,tracing
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.11
Requires-Dist: click~=8.3.0
Requires-Dist: fastmcp~=2.13.0
Requires-Dist: httpx~=0.28.0
Requires-Dist: mcp~=1.20.0
Requires-Dist: opentelemetry-semantic-conventions-ai>=0.4.0
Requires-Dist: opentelemetry-semantic-conventions>=0.48b0
Requires-Dist: pydantic~=2.12.0
Requires-Dist: python-dotenv~=1.2.0
Requires-Dist: starlette~=0.50.0
Requires-Dist: uvicorn~=0.38.0
Description-Content-Type: text/markdown

# OpenTelemetry-MCP-Server

Unified MCP server for querying OpenTelemetry traces across multiple backends (Jaeger, Tempo, Traceloop, etc.), enabling AI agents to analyze distributed traces for automated debugging and observability.

An MCP (Model Context Protocol) server for querying OpenTelemetry traces from LLM applications, with specialized support for OpenLLMetry semantic conventions.


## Features

- **Multiple Backend Support**: Query traces from Jaeger, Grafana Tempo, or Traceloop
- **OpenLLMetry Integration**: Automatic parsing of `gen_ai.*` semantic conventions
- **5 Powerful Tools**:
  - `search_traces` - Search traces with advanced filters
  - `get_trace` - Get complete trace details
  - `get_llm_usage` - Aggregate token usage metrics
  - `list_services` - List available services
  - `find_errors` - Find traces with errors
- **Token Usage Tracking**: Aggregate prompt/completion tokens across models and services
- **CLI Overrides**: Configure via environment or command-line arguments
- **Type-Safe**: Built with Pydantic for robust data validation

## Installation

### Prerequisites

- Python 3.11 or higher
- [pipx](https://pipx.pypa.io/) (recommended for end users) or pip
- [UV package manager](https://github.com/astral-sh/uv) (recommended for development)

### For End Users (Recommended)

The easiest way to install is using **pipx**, which installs the package in an isolated environment and makes the `opentelemetry-mcp` command available globally:

```bash
# Install with pipx (recommended)
pipx install opentelemetry-mcp

# Verify installation
opentelemetry-mcp --help

# Upgrade to latest version
pipx upgrade opentelemetry-mcp
```

Alternatively, you can install with pip:

```bash
# Install with pip
pip install opentelemetry-mcp

# Verify installation
opentelemetry-mcp --help
```

### For Developers

If you're contributing to the project or want to make local modifications:

```bash
# Clone the repository
git clone https://github.com/traceloop/opentelemetry-mcp-server.git
cd opentelemetry-mcp-server

# Install dependencies with UV
uv sync

# Or install in development mode with editable install
uv pip install -e ".[dev]"
```

## Quick Start

1. **Install the package** (see [Installation](#installation))
2. **Configure your backend** (see [Configuration](#configuration))
3. **Set up your client** (see [Getting Started](#getting-started))

**Supported Backends:**

- **Jaeger** (local): `http://localhost:16686`
- **Traceloop** (cloud): `https://api.traceloop.com` (requires API key)
- **Tempo** (local): `http://localhost:3200`

**Running the server:**

```bash
# If installed with pipx/pip
opentelemetry-mcp --backend jaeger --url http://localhost:16686

# If developing locally (cloned repository)
./start_locally.sh
```

For detailed client-specific setup instructions, see the [Getting Started](#getting-started) section.

## Configuration

### Environment Variables

Create a `.env` file (see `.env.example`):

```bash
# Backend type: jaeger, tempo, or traceloop
BACKEND_TYPE=jaeger

# Backend URL
BACKEND_URL=http://localhost:16686

# Optional: API key (mainly for Traceloop)
BACKEND_API_KEY=

# Optional: Request timeout (default: 30s)
BACKEND_TIMEOUT=30

# Optional: Logging level
LOG_LEVEL=INFO

# Optional: Max traces per query (default: 100)
MAX_TRACES_PER_QUERY=100
```

### Backend-Specific Configuration

#### Jaeger

```bash
BACKEND_TYPE=jaeger
BACKEND_URL=http://localhost:16686
```

#### Grafana Tempo

```bash
BACKEND_TYPE=tempo
BACKEND_URL=http://localhost:3200
```

#### Traceloop

```bash
BACKEND_TYPE=traceloop
BACKEND_URL=https://api.traceloop.com/v2
BACKEND_API_KEY=your_api_key_here
```

**Note**: The API key contains the project information. The backend uses a hardcoded project slug of `"default"` and Traceloop resolves the actual project and environment from the API key.

### CLI Overrides

You can override environment variables with CLI arguments:

```bash
opentelemetry-mcp --backend jaeger --url http://localhost:16686
opentelemetry-mcp --backend traceloop --url https://api.traceloop.com --api-key YOUR_KEY
```

## Getting Started

Choose your client below to see specific setup instructions:

- [Claude Desktop](#claude-desktop) - AI assistant with MCP support
- [Claude Code](#claude-code) - CLI interface for Claude
- [Codeium (Windsurf)](#codeium-windsurf) - AI-powered IDE
- [Cursor](#cursor) - AI-first code editor
- [Gemini CLI](#gemini-cli) - Google's AI command-line tool

### Claude Desktop

Configure the MCP server in your Claude Desktop config file:

- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

**If you installed with pipx (recommended):**

```json
{
  "mcpServers": {
    "opentelemetry-mcp": {
      "command": "opentelemetry-mcp",
      "env": {
        "BACKEND_TYPE": "jaeger",
        "BACKEND_URL": "http://localhost:16686"
      }
    }
  }
}
```

For Traceloop:

```json
{
  "mcpServers": {
    "opentelemetry-mcp": {
      "command": "opentelemetry-mcp",
      "env": {
        "BACKEND_TYPE": "traceloop",
        "BACKEND_URL": "https://api.traceloop.com",
        "BACKEND_API_KEY": "your_traceloop_api_key_here"
      }
    }
  }
}
```

**If you're developing locally with the repository:**

Using the wrapper script (easy backend switching):

```json
{
  "mcpServers": {
    "opentelemetry-mcp": {
      "command": "/absolute/path/to/opentelemetry-mcp-server/start_locally.sh"
    }
  }
}
```

Or using UV directly (for multiple backends):

```json
{
  "mcpServers": {
    "opentelemetry-mcp-jaeger": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/opentelemetry-mcp-server",
        "run",
        "opentelemetry-mcp"
      ],
      "env": {
        "BACKEND_TYPE": "jaeger",
        "BACKEND_URL": "http://localhost:16686"
      }
    }
  }
}
```

### Claude Code

Claude Code works with MCP servers configured in your Claude Desktop config. Once configured above, you can use the server with Claude Code CLI:

```bash
# Verify the server is available
claude-code mcp list

# Use Claude Code with access to your OpenTelemetry traces
claude-code "Show me traces with errors from the last hour"
```

### Codeium (Windsurf)

1. Open Windsurf
2. Navigate to **Settings → MCP Servers**
3. Click **Add New MCP Server**
4. Add the following configuration:

**If installed with pipx:**

```json
{
  "opentelemetry-mcp": {
    "command": "opentelemetry-mcp",
    "env": {
      "BACKEND_TYPE": "jaeger",
      "BACKEND_URL": "http://localhost:16686"
    }
  }
}
```

**If using the repository:**

```json
{
  "opentelemetry-mcp": {
    "command": "uv",
    "args": [
      "--directory",
      "/absolute/path/to/opentelemetry-mcp-server",
      "run",
      "opentelemetry-mcp"
    ],
    "env": {
      "BACKEND_TYPE": "jaeger",
      "BACKEND_URL": "http://localhost:16686"
    }
  }
}
```

### Cursor

1. Open Cursor
2. Navigate to **Settings → MCP**
3. Click **Add new MCP Server**
4. Add the following configuration:

**If installed with pipx:**

```json
{
  "opentelemetry-mcp": {
    "command": "opentelemetry-mcp",
    "env": {
      "BACKEND_TYPE": "jaeger",
      "BACKEND_URL": "http://localhost:16686"
    }
  }
}
```

**If using the repository:**

```json
{
  "opentelemetry-mcp": {
    "command": "uv",
    "args": [
      "--directory",
      "/absolute/path/to/opentelemetry-mcp-server",
      "run",
      "opentelemetry-mcp"
    ],
    "env": {
      "BACKEND_TYPE": "jaeger",
      "BACKEND_URL": "http://localhost:16686"
    }
  }
}
```

### Gemini CLI

Configure the MCP server in your Gemini CLI config file (`~/.gemini/config.json`):

**If installed with pipx:**

```json
{
  "mcpServers": {
    "opentelemetry-mcp": {
      "command": "opentelemetry-mcp",
      "env": {
        "BACKEND_TYPE": "jaeger",
        "BACKEND_URL": "http://localhost:16686"
      }
    }
  }
}
```

**If using the repository:**

```json
{
  "mcpServers": {
    "opentelemetry-mcp": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/opentelemetry-mcp-server",
        "run",
        "opentelemetry-mcp"
      ],
      "env": {
        "BACKEND_TYPE": "jaeger",
        "BACKEND_URL": "http://localhost:16686"
      }
    }
  }
}
```

Then use Gemini CLI with your traces:

```bash
gemini "Analyze token usage for gpt-4 requests today"
```

## Usage

### Quick Start with start_locally.sh (Recommended)

The easiest way to run the server:

```bash
./start_locally.sh
```

This script handles all configuration and starts the server in stdio mode (perfect for Claude Desktop integration). To switch backends, simply edit the script and uncomment your preferred backend.

### Manual Running

For advanced use cases or custom configurations, you can run the server manually.

#### stdio Transport (for Claude Desktop)

Start the MCP server with stdio transport for local/Claude Desktop integration:

```bash
# If installed with pipx/pip
opentelemetry-mcp

# If running from cloned repository with UV
uv run opentelemetry-mcp

# With backend override (pipx/pip)
opentelemetry-mcp --backend jaeger --url http://localhost:16686

# With backend override (UV)
uv run opentelemetry-mcp --backend jaeger --url http://localhost:16686
```

#### HTTP Transport (for Network Access)

Start the MCP server with HTTP/SSE transport for remote access:

```bash
# If installed with pipx/pip
opentelemetry-mcp --transport http

# If running from cloned repository with UV
uv run opentelemetry-mcp --transport http

# Specify custom host and port (pipx/pip)
opentelemetry-mcp --transport http --host 127.0.0.1 --port 9000

# With UV
uv run opentelemetry-mcp --transport http --host 127.0.0.1 --port 9000
```

The HTTP server will be accessible at `http://localhost:8000/sse` by default.

**Transport Use Cases:**

- **stdio transport**: Local use, Claude Desktop integration, single process
- **HTTP transport**: Remote access, multiple clients, network deployment, sample applications

## Tools Reference

### 1. search_traces

Search for traces with flexible filtering:

```python
{
  "service_name": "my-app",
  "start_time": "2024-01-01T00:00:00Z",
  "end_time": "2024-01-01T23:59:59Z",
  "gen_ai_system": "openai",
  "gen_ai_model": "gpt-4",
  "min_duration_ms": 1000,
  "has_error": false,
  "limit": 50
}
```

**Parameters:**

- `service_name` - Filter by service
- `operation_name` - Filter by operation
- `start_time` / `end_time` - ISO 8601 timestamps
- `min_duration_ms` / `max_duration_ms` - Duration filters
- `gen_ai_system` - LLM provider (openai, anthropic, etc.)
- `gen_ai_model` - Model name (gpt-4, claude-3-opus, etc.)
- `has_error` - Filter by error status
- `tags` - Custom tag filters
- `limit` - Max results (1-1000, default: 100)

**Returns:** List of trace summaries with token counts

### 2. get_trace

Get complete trace details including all spans and OpenLLMetry attributes:

```python
{
  "trace_id": "abc123def456"
}
```

**Returns:** Full trace tree with:

- All spans with attributes
- Parsed OpenLLMetry data for LLM spans
- Token usage per span
- Error information

### 3. get_llm_usage

Get aggregated token usage metrics:

```python
{
  "start_time": "2024-01-01T00:00:00Z",
  "end_time": "2024-01-01T23:59:59Z",
  "service_name": "my-app",
  "gen_ai_system": "openai",
  "limit": 1000
}
```

**Returns:** Aggregated metrics with:

- Total prompt/completion/total tokens
- Breakdown by model
- Breakdown by service
- Request counts

### 4. list_services

List all available services:

```python
{}
```

**Returns:** List of service names

### 5. find_errors

Find traces with errors:

```python
{
  "start_time": "2024-01-01T00:00:00Z",
  "service_name": "my-app",
  "limit": 50
}
```

**Returns:** Error traces with:

- Error messages and types
- Stack traces (truncated)
- LLM-specific error info
- Error span details

## Example Queries

### Find expensive LLM operations

```
Use search_traces to find traces from the last hour where:
- gen_ai_system is "openai"
- min_duration_ms is 5000
```

### Analyze token usage by model

```
Use get_llm_usage for the last 24 hours to see token usage breakdown by model
```

### Debug recent errors

```
Use find_errors to show all error traces from the last hour
```

### Investigate a specific trace

```
Use get_trace with trace_id "abc123" to see all spans and LLM attributes
```

## OpenLLMetry Semantic Conventions

This server automatically parses OpenLLMetry semantic conventions:

### Supported Attributes

- `gen_ai.system` - Provider (openai, anthropic, cohere, etc.)
- `gen_ai.request.model` - Requested model
- `gen_ai.response.model` - Actual model used
- `gen_ai.operation.name` - Operation type (chat, completion, embedding)
- `gen_ai.request.temperature` - Temperature parameter
- `gen_ai.request.top_p` - Top-p parameter
- `gen_ai.request.max_tokens` - Max tokens
- `gen_ai.usage.prompt_tokens` - Input tokens (also supports `input_tokens` for Anthropic)
- `gen_ai.usage.completion_tokens` - Output tokens (also supports `output_tokens` for Anthropic)
- `gen_ai.usage.total_tokens` - Total tokens

### Provider Compatibility

The server handles different token naming conventions:

- **OpenAI**: `prompt_tokens`, `completion_tokens`
- **Anthropic**: `input_tokens`, `output_tokens`
- **Others**: Falls back to standard OpenLLMetry names

## Development

### Running Tests

```bash
# With UV
uv run pytest

# With coverage
uv run pytest --cov=openllmetry_mcp --cov-report=html

# With pip
pytest
```

### Code Quality

```bash
# Format code
uv run ruff format .

# Lint
uv run ruff check .

# Type checking
uv run mypy src/
```

## Troubleshooting

### Backend Connection Issues

```bash
# Test backend connectivity
curl http://localhost:16686/api/services  # Jaeger
curl http://localhost:3200/api/search/tags  # Tempo
```

### Authentication Errors

Make sure your API key is set correctly:

```bash
export BACKEND_API_KEY=your_key_here
# Or use --api-key CLI flag
opentelemetry-mcp --api-key your_key_here
```

### No Traces Found

- Check time range (use recent timestamps)
- Verify service names with `list_services`
- Check backend has traces: `curl http://localhost:16686/api/services`
- Try searching without filters first

### Token Usage Shows Zero

- Ensure your traces have OpenLLMetry instrumentation
- Check that `gen_ai.usage.*` attributes exist in spans
- Verify with `get_trace` to see raw span attributes

## Future Enhancements

- [ ] Cost calculation with built-in pricing tables
- [ ] Model performance comparison tools
- [ ] Prompt pattern analysis
- [ ] MCP resources for common queries
- [ ] Caching layer for frequent queries
- [ ] Support for additional backends (SigNoz, ClickHouse)

## Contributing

Contributions are welcome! Please ensure:

1. All tests pass: `pytest`
2. Code is formatted: `ruff format .`
3. No linting errors: `ruff check .`
4. Type checking passes: `mypy src/`

## License

Apache 2.0 License - see LICENSE file for details

## Related Projects

- [OpenLLMetry](https://github.com/traceloop/openllmetry) - OpenTelemetry instrumentation for LLMs
- [Model Context Protocol](https://modelcontextprotocol.io/) - MCP specification
- [Claude Desktop](https://claude.ai/download) - AI assistant with MCP support

## Support

For issues and questions:

- GitHub Issues: https://github.com/traceloop/opentelemetry-mcp-server/issues
- PyPI Package: https://pypi.org/project/opentelemetry-mcp/
- Traceloop Community: https://traceloop.com/slack
