otel-mcp
# 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
Scored across 11 tools
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.
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.
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.
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.