Skip to main content
Glama
README.md
# otel-mcp

An MCP server that emits OpenTelemetry **traces, metrics, and logs** to one or
more OTLP endpoints at the same time, in any of the three OTLP wire formats:

- `grpc`          — OTLP/gRPC (protobuf over HTTP/2)
- `http/protobuf` — OTLP/HTTP binary protobuf
- `http/json`     — OTLP/HTTP proto3-JSON (spec-compliant)

It also ships **tool-mimicry profiles** that produce realistic signal bundles
shaped like well-known tools (nginx, postgres, redis, kafka, aws-lambda,
kubernetes pod, generic gRPC service), so you can populate a collector or
backend with traffic that looks like a real environment.

## Install

```bash
uv venv
uv pip install -e .
```

## Run

```bash
otel-mcp           # stdio transport — wire into any MCP client
```

Or via an MCP client config (e.g. Claude Desktop, Claude Code):

```json
{
  "mcpServers": {
    "otel": {
      "command": "otel-mcp"
    }
  }
}
```

### Env bootstrap

If `OTEL_EXPORTER_OTLP_ENDPOINT` is set on launch, an endpoint named `default`
is registered using the standard OTEL env vars:

- `OTEL_EXPORTER_OTLP_ENDPOINT`
- `OTEL_EXPORTER_OTLP_PROTOCOL`  (`grpc` | `http/protobuf` | `http/json`)
- `OTEL_EXPORTER_OTLP_HEADERS`   (comma-separated `k=v` pairs)
- `OTEL_EXPORTER_OTLP_INSECURE`  (gRPC TLS toggle)

## Tools

### Endpoint management

| Tool | Purpose |
| --- | --- |
| `add_endpoint` | Register a named OTLP destination (url, protocol, signals, headers, …). |
| `remove_endpoint` | Drop one endpoint by name. |
| `clear_endpoints` | Drop every endpoint. |
| `list_endpoints` | Enumerate current endpoints. |
| `status` | Endpoints + available mimic profiles. |

Endpoints are selected **per call**: every signal-emitting tool accepts an
`endpoints: [names]` arg. Omit it to fan out to every endpoint that accepts
that signal type.

### Raw signal emission

| Tool | Shape of input |
| --- | --- |
| `send_trace` | `{service_name, spans[]}` — each span has `name`, `kind`, `attributes`, `duration_ms`, `status`, `events[]`, optional `parent_name` for nesting. |
| `send_metric` | `{service_name, metrics[]}` — each metric has `name`, `kind` (`counter`/`up_down_counter`/`gauge`/`histogram`), `unit`, `description`, `points[]`. Histograms accept a list of samples per point. |
| `send_log` | `{service_name, records[]}` — each record has `body`, `severity`, `severity_text`, `attributes`, `timestamp_ns`. |

### Mimicry

| Tool | Purpose |
| --- | --- |
| `list_mimic_profiles` | Show every profile with its parameters. |
| `mimic_tool` | Run one profile and send its bundle once. |
| `generate_load` | Run a profile on a loop to simulate sustained traffic. |

Built-in profiles:

| Profile | What it looks like |
| --- | --- |
| `nginx` / `http-server` | Server spans with HTTP semconv, access logs, request counters & latency histograms. |
| `postgres` | DB client spans with `db.system=postgresql` + connection pool metrics. |
| `redis`    | DB client spans with `db.system=redis`. |
| `kafka`    | Producer/consumer spans with messaging semconv. |
| `aws-lambda` | Server spans with `faas.*` + `cloud.*` resource attrs, Lambda access logs, invocation metrics. |
| `k8s-pod`  | Resource = full `k8s.*` attributes, container cpu/memory/network metrics, `Started` event log. |
| `grpc`     | Server spans with `rpc.system=grpc`. |

## Example session

```text
> add_endpoint name="otel-collector" url="http://localhost:4318" protocol="http/protobuf"
> add_endpoint name="jaeger-json"    url="http://localhost:4318" protocol="http/json" signals=["traces"]
> mimic_tool profile="nginx" options={"count": 50, "error_rate": 0.1}
> mimic_tool profile="postgres"
> generate_load profile="kafka" iterations=10 interval_seconds=2
> send_trace service_name="checkout" spans=[
    {"name": "POST /checkout", "kind": "server", "duration_ms": 42, "attributes": {"http.response.status_code": 200}},
    {"name": "charge_card",    "kind": "client", "parent_name": "POST /checkout", "duration_ms": 18,
     "attributes": {"peer.service": "stripe"}}
  ]
```

## Adding a new mimic profile

1. Write a function returning a `MimicBundle` in `src/otel_mcp/mimics.py`.
2. Register it in the `PROFILES` dict at the bottom of that file.
3. Call `list_mimic_profiles` to confirm it picked up the parameters.

Profiles stay declarative: each returns span/metric/log specs that flow through
the same generator pipeline, so they inherit correct resource merging, wire
format support, and fan-out automatically.

TDQS

A3.7/5.0

Scored across 11 tools

Disambiguation5/5

Every tool has a clearly distinct purpose with no ambiguity. Tools like add_endpoint, remove_endpoint, and clear_endpoints handle endpoint management, while send_log, send_metric, and send_trace target specific telemetry signals. Mimic_tool and generate_load are for simulation, and list_endpoints/list_mimic_profiles/status are for querying, all with non-overlapping functions.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern using snake_case, such as add_endpoint, list_endpoints, send_log, and mimic_tool. This uniformity makes the set predictable and easy to understand, with no deviations in naming conventions.

Tool Count5/5

With 11 tools, this server is well-scoped for OpenTelemetry management and simulation. It covers endpoint configuration, telemetry emission, mimicry, and status reporting without being overly sparse or bloated, with each tool serving a clear and necessary role.

Completeness5/5

The tool set provides complete coverage for the OpenTelemetry domain, including CRUD operations for endpoints (add, remove, clear, list), sending all signal types (logs, metrics, traces), simulation capabilities (mimic, generate_load), and querying (status, list profiles). There are no obvious gaps that would hinder agent workflows.

Maintenance

ActivityInactive
ResponsivenessNo issues