MCPInstall
mcp-otel logo

mcp-otel

by dylibso 15 stars dylibso/mcp-otel

An example of distributed tracing an MCP enabled agent

READMEmain

MCP Distributed Tracing Example

This is an example project demonstrating how to do distributed tracing with an MCP enabled agent.

The application itself is a simple Claude powered chat agent in src/agent.ts. With multiple MCP Servers in src/servers. These servers are run using the stdio transport but could be run remotely with no code changes.

Every component in the system emits opentelemetry data, so any sink should be supported such as Datadog, Honeycomb, Signoz, etc.

Note: this is not meant to be production code and was thrown together to experiment with trace context propagation

Explanation

For each prompt, we start an otel trace and we collect spans until the "agent" is done processing the response, then we end the trace. This might result in multiple tool calls, responses, errors, etc.

For each component in the system, we label the spans with a "service" name. Like so:

  • Agent: mcp-agent-client
  • Fetch Server: mcp-fetch-server
  • Calc Server: mcp-calculator-server

Note: In a real world application, these service names would be meaningful to your application.

Example

Prompt:

Summarize the article on the top of Hacker News

This will make two tool calls to fetch which you can see in the trace:

mcp otel

Although we are looking at an agent trace, we can dig all the way down into the implementation details of fetch.

Having each span labeled by service also allows us to track on a service level how that MCP Server is performing:

fetch service

Explanation

This requires no changes in the spec or the clients to work. But it creatively reuses the _meta property to shuttle the trace context at the MCP protocol level.

This looks something like this when making the tool call:

const result = await this.client.callTool({
  name: toolUse.name,
  arguments: toolUse.arguments,
  _meta: {
    __traceContext: {
      // span here is the current span
      traceId: span.spanContext().traceId,
      spanId: span.spanContext().spanId,
      traceFlags: span.spanContext().traceFlags,
      isRemote: true
    }
  }
});

And like this when receiving on the server side:

const traceContext = extra._meta?.__traceContext;
// we then tell our SDK to use this trace context as the parent span

Running

For a simple way to collect and explore your otel data locally, run signoz using docker.

git clone -b main https://github.com/SigNoz/signoz.git
cd signoz/deploy/docker
docker compose up --remove-orphans -d

Then run the agent and chat with it:

export ANTHROPIC_API_KEY="sk-ant-******"
npm install
npm run build
npm start

More Monitoring MCP servers

Similar servers from the same category.

VictoriaLogs

victoriametrics-community

Provides a bridge between VictoriaLogs and language models for querying and analyzing log data, enabling DevOps teams to troubleshoot issues and extract insights without writing complex query syntax.

LogText+2

VictoriaMetrics

victoriametrics-community

Provides direct access to VictoriaMetrics monitoring instances for querying metrics, exploring time series data, analyzing alerting rules, and debugging configurations without requiring online access.

TextModel+1

Provides structured access to CloudWatch Logs data for searching, analyzing, and correlating logs across AWS services to help with troubleshooting and pattern identification.

search

Understand how your Worker projects are performing via logs, traces, and other data sources.

Monitoring