OTEL MCP Server
Query and analyze distributed traces from Jaeger, supporting service discovery, trace inspection, performance analysis, and error finding.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@OTEL MCP Servershow me the slowest traces from the payment service"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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
/docsSelf-Telemetry: The server traces itself to Jaeger for debugging
Related MCP server: poly-observability-mcp
Installation
Using uvx (Recommended)
Run directly without installing:
# Run MCP server
uvx otel-mcp
# Run REST API
uvx --from otel-mcp otel-mcp-apiUsing pip
pip install otel-mcp
# Then run
otel-mcp # MCP server
otel-mcp-api # REST APIFrom Source
git clone https://github.com/ryanm101/otel-mcp.git
cd otel-mcp
uv sync
uv run otel-mcpQuick Start
1. Start Jaeger
docker-compose up -d
# Jaeger UI at http://localhost:166862. Run the MCP Server
uvx otel-mcp
# Or with environment variables:
JAEGER_URL=http://jaeger:16686 uvx otel-mcp3. Or Run the REST API
uvx --from otel-mcp otel-mcp-api
# OpenAPI docs at http://localhost:8000/docsMCP Client Configuration
Add to your MCP client config (e.g., Claude Desktop claude_desktop_config.json):
{
"mcpServers": {
"otel-mcp": {
"command": "uvx",
"args": ["otel-mcp"],
"env": {
"JAEGER_URL": "http://localhost:16686"
}
}
}
}Configuration
Create a .env file (see .env.example):
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-telemetryMCP Tools
Service Discovery
Tool | Description |
| List all services in Jaeger |
| List operations for a service |
Trace Inspection
Tool | Description |
| Search traces with filters (service, operation, duration, errors) |
| Get complete trace by ID with all spans |
| Find traces containing errors |
Performance Analysis
Tool | Description |
| Find slowest traces |
| Get latency percentiles (p50/p95/p99) and error rates |
REST API Endpoints
Endpoint | Method | Description |
| GET | Health check |
| GET | List services |
| GET | List operations |
| GET | Search traces |
| GET | Get trace by ID |
| GET | Find error traces |
| GET | Find slow traces |
Development
Run Tests
uv run pytest tests/ -vRun with Coverage
uv run pytest tests/ --cov=otel_mcp --cov-report=term-missingLint and Type Check
uv run ruff check src/
uv run mypy src/Adding a New Backend
Create
backends/tempo.pyimplementingBaseBackendAdd backend type to
config.pyUpdate
_create_backend()inserver.pyandapi.py
License
Apache-2.0
Available Tools
7 toolsfind_errorsB
Find traces containing errors.
Args: service_name: Service name (required for Jaeger) start_time: Start time in ISO 8601 format end_time: End time in ISO 8601 format limit: Maximum error traces to return (default: 20)
Returns: JSON string with error traces and error details
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| end_time | No | ||
| start_time | No | ||
| service_name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It adds useful context — the Jaeger-specific required service_name, the ISO 8601 time format, and the default/return shape — but says nothing about permissions, rate limits, pagination, or what happens when timestamps are omitted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded one-line purpose followed by compact Args and Returns sections. Every line is short and informative; the Returns section is mildly redundant given an output schema exists, but not wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a four-parameter read tool with an output schema, the description covers all inputs and names the return type. Complete enough to call correctly; only the missing sibling routing guidance keeps it from being fully self-contained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: all four parameters are explained (service_name required for Jaeger, start/end in ISO 8601, limit default 20). It doesn't clarify whether null start/end means unbounded or a server default, which is a minor residual gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: find traces containing errors. An agent can tell it apart from get_slow_traces and search_traces by the error filter, but the description never explicitly contrasts itself with those siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this versus search_traces or get_trace, no mention of prerequisites or when-to-avoid conditions. The only contextual hint is that service_name is required for Jaeger, which is a backend note rather than usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_operation_statsB
Get performance statistics for a service or operation.
Args: service_name: Service name (required for Jaeger) operation_name: Filter by specific operation start_time: Start time in ISO 8601 format end_time: End time in ISO 8601 format
Returns: JSON string with latency percentiles and error rates
| Name | Required | Description | Default |
|---|---|---|---|
| end_time | No | ||
| start_time | No | ||
| service_name | Yes | ||
| operation_name | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It implies a read operation via 'Get' and mentions a backend (Jaeger) for service_name, but discloses nothing about permissions, rate limits, or read-only guarantees. The 'Returns' line is largely redundant given the output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose and then cleanly separates Args and Returns sections with no filler. The Args block duplicates parameter names the schema already lists, a minor redundancy, but the overall structure is efficient and easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be spelled out; parameters are fully documented despite 0% schema coverage; and the tool's read nature is inferable from 'Get'. The main gap is the missing routing guidance against the many overlapping siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: it documents all four parameters, marks service_name as required (noting it is required specifically for Jaeger), explains operation_name as a filter, and gives ISO 8601 as the time format. This meaningfully exceeds the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get performance statistics for a service or operation'), which is clear and distinct from trace-retrieval siblings. However, it does not explicitly contrast itself with siblings like search_traces or get_slow_traces, leaving the agent to infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no when-to-use guidance, no prerequisites, and no mention of alternatives despite six sibling tools that overlap in domain (find_errors, get_slow_traces, search_traces). The agent must guess when aggregate stats are preferable to raw traces.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_slow_tracesA
Find slowest traces for a service.
Args: service_name: Service name (required for Jaeger) operation_name: Filter by operation name min_duration_ms: Minimum duration threshold (default: 1000ms) limit: Maximum traces to return (default: 10)
Returns: JSON string with slowest traces sorted by duration
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| service_name | Yes | ||
| operation_name | No | ||
| min_duration_ms | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses defaults (min_duration_ms=1000, limit=10), the return format ('JSON string with slowest traces sorted by duration'), and the Jaeger requirement. However, it does not state read-only behavior, auth needs, rate limits, or error behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose, then uses compact Args and Returns sections. Every line adds needed information given the zero schema description coverage, with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple trace-query tool with no annotations, the description covers all parameters, defaults, required context, and return shape. It is nearly complete, though it still lacks routing guidance against sibling tools and any safety or read-only confirmation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry all parameter meaning. It documents all four parameters with clear semantics: service_name is required for Jaeger, operation_name filters, min_duration_ms is a threshold defaulting to 1000ms, and limit caps returned traces at 10.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Find slowest traces for a service.' The 'slowest' qualifier distinguishes it from generic trace search, but it does not explicitly name or contrast with siblings like search_traces or get_trace.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no guidance on when to use this tool versus alternatives such as search_traces, get_trace, or find_errors. It only implies usage through the verb 'Find slowest traces' and adds a Jaeger requirement note, which is a constraint rather than usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_traceB
Get complete trace details by ID.
Args: trace_id: Trace identifier
Returns: JSON string with full trace data including all spans
| Name | Required | Description | Default |
|---|---|---|---|
| trace_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It discloses the return shape ('full trace data including all spans'), which is useful, and 'Get' implies a read, but it says nothing about permissions, rate limits, or behavior when the ID is missing or unknown.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose in one sentence, then uses a compact Args/Returns structure. No filler, though the Args line adds little beyond the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be explained, yet the description still largely covers them. For a single-parameter read tool it is adequate, but the absence of any usage routing to sibling search_traces leaves a gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the single parameter is documented only as 'trace_id: Trace identifier', which merely restates the parameter name. No format, source, or example of a valid trace ID is given, so the description does not compensate for the schema gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Get) and resource (complete trace details) scoped by ID, and the mention of 'full trace data including all spans' clarifies the granularity. It does not explicitly differentiate from sibling search_traces, but the 'by ID' scoping makes the resource clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'by ID' phrasing implies a trace identifier is required, which loosely separates it from search_traces, but there is no explicit when-to-use, when-not, or alternative guidance. An agent has to infer that this is the retrieval step after a search.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_operationsC
List all operations for a specific service.
Args: service_name: Name of the service
Returns: JSON string with list of operations
| Name | Required | Description | Default |
|---|---|---|---|
| service_name | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden, yet it only states the return type ('JSON string with list of operations'). Nothing is said about pagination, ordering, auth requirements, or behavior for an unknown service.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Very short and the purpose is front-loaded in the first sentence. The trailing Args/Returns block is mildly redundant since an output schema exists, but it costs little.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Because an output schema exists, return values need not be explained. Still, with no annotations and no usage guidance, the definition leaves the agent guessing about ordering, pagination, and errors for what appears to be a straightforward list tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and there is one required parameter. 'service_name: Name of the service' merely restates the parameter name, adding no format, example, or expected value set over what the schema already shows.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a clear verb+resource and a scoping constraint ('for a specific service'), so an agent knows this returns operations rather than traces or services. It does not, however, distinguish itself from siblings like get_operation_stats or list_services.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this versus list_services or get_operation_stats, nor any stated prerequisites. The agent must infer usage entirely from the name and param.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_servicesB
List all available services in Jaeger.
Returns: JSON string with list of services
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It implies a read-only listing but does not explicitly state read-only status, side effects, authentication needs, or pagination behavior. The 'Returns' line duplicates the output schema and adds little.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short lines and front-loads the purpose effectively. However, the 'Returns' line is redundant given that an output schema exists, so it does not fully earn its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple, parameterless list tool with an output schema, the description adequately conveys what the tool does. It could mention read-only behavior since no annotations cover safety, but overall it is sufficient for correct selection.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. The schema description coverage is 100% (trivially), and there is nothing further to clarify.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'List' and resource 'services' with the context 'in Jaeger', making the purpose immediately clear. It does not explicitly differentiate itself from sibling tools such as list_operations or search_traces, so it lacks explicit sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided on when to use this tool versus alternatives like list_operations or search_traces. There are no prerequisites or conditions mentioned, leaving the agent to infer usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_tracesB
Search for traces with filters.
Args: service_name: Service name (required for Jaeger) operation_name: Filter by operation name start_time: Start time in ISO 8601 format end_time: End time in ISO 8601 format min_duration_ms: Minimum trace duration in milliseconds max_duration_ms: Maximum trace duration in milliseconds has_error: Filter traces with errors limit: Maximum traces to return (default: 20, max: 100)
Returns: JSON string with trace summaries
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| end_time | No | ||
| has_error | No | ||
| start_time | No | ||
| service_name | Yes | ||
| operation_name | No | ||
| max_duration_ms | No | ||
| min_duration_ms | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden, and it falls short: it does not say whether this is read-only, whether pagination or result caps apply beyond `limit`, what ordering results come in, or what happens when 100+ traces match. The 'Returns: JSON string with trace summaries' line is the only behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The Args/Returns layout is front-loaded and scannable, with no filler prose. It is slightly long only because it is compensating for a completely undescribed schema, which is justified.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the description need not explain the return shape — the brief Returns line suffices. What is missing for an 8-parameter search tool with zero annotation coverage is any behavioral or routing context, so the definition is adequate but leaves real gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate, and it largely does: it documents every one of the 8 parameters, gives ISO 8601 format for timestamps, milliseconds units for durations, the Jaeger-specific requiredness of service_name, and the default/max for limit. It loses a point for not clarifying whether min/max_duration and start/end pairs are inclusive or how they interact.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Search for traces') plus the scoping mechanism ('with filters'), so the core purpose is unambiguous. However, it never distinguishes itself from siblings like find_errors or get_slow_traces, which are also filtered trace queries, so an agent gets no help disambiguating.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance at all — no conditions, no exclusions, and no mention of the alternatives (get_trace, find_errors, get_slow_traces) that overlap heavily with this tool. The one contextual note ('required for Jaeger') is a backend quirk, not usage routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
7 tool updates
v0.1.0- First observed
find_errors - First observed
get_operation_stats - First observed
get_slow_traces - First observed
get_trace - First observed
list_operations - First observed
list_services - First observed
search_traces
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.
Maintenance
Related MCP Connectors
Cloud hosted Okahu MCP server that helps you manage genAI trace data
- SpanlyOAuthcom.spanly
MCP observability. Query live traffic, errors, duration, and alerts from your AI agent.
Governed data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
Query application logs, traces, and metrics from your AI coding assistant via Foam's MCP server.
Related MCP Servers
- AlicenseAqualityAmaintenanceProvides read-only access to Jaeger distributed tracing data through the Model Context Protocol. Enables Claude and other MCP-capable agents to search traces, inspect spans, and analyze service dependencies directly within conversations.1541 PyPI1MIT
- AlicenseNot gradedqualityDmaintenanceUnified MCP server for observability and monitoring, providing tools to query metrics, logs, and traces through Prometheus, Grafana, Loki, and Jaeger.2Mozilla Public 2.0
- AlicenseAqualityCmaintenanceEnables querying logs, traces, and metrics from multiple OpenObserve instances via MCP tools, with parallel execution, batching, and caching.624 npm9MIT
- AlicenseNot gradedqualityCmaintenanceEnables to interact with Jaeger distributed tracing system through the MCP protocol. Supports querying traces, services, and operations via natural language.60 npm18MIT