DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • LangChain With SQL Databases: Natural Language to SQL Queries
  • Context Rot: Why Your AI Agent Gets Worse the Longer It Works
  • Custom Model Context Protocol (MCP) for NL2SQL: A Rigorous Evaluation Framework on Oracle Database
  • The LLM Selection War Story: Part 4 - Your Production Failure Testing Suite

Trending

  • AI in SRE: What's Actually Coming in 2026
  • Getting Started With RabbitMQ in Spring Boot
  • Building Cross-Team SLO Contracts for Performance Accountability
  • Everything About HTTPS and SSL in Java
  1. DZone
  2. Data Engineering
  3. AI/ML
  4. Tracing the Agentic Loop: Monitoring Multi-Round-Trip MCP Calls With OpenTelemetry

Tracing the Agentic Loop: Monitoring Multi-Round-Trip MCP Calls With OpenTelemetry

The latest MCP spec mandates W3C tracing. Use Quarkus and OpenTelemetry to easily visualize disjointed, multi-round-trip AI agent workflows in production.

By 
Daniel Oh user avatar
Daniel Oh
DZone Core CORE ·
Jul. 22, 26 · Analysis
Likes (1)
Comment
Save
Tweet
Share
280 Views

Join the DZone community and get the full member experience.

Join For Free

The upcoming release of the July 28 Model Context Protocol (MCP) specification completely revolutionized how developers build AI tools. By shifting from stateful, long-lived connections to a streamlined, stateless HTTP engine, we finally gained the ability to run AI tools as scalable, modern microservices.

However, statelessness introduces a massive operational headache: observability.

When you move from a monolithic setup to a decentralized, stateless agentic network, debugging becomes incredibly difficult. A single user prompt might trigger an AI agent to execute multiple tools, coordinate with external APIs, check a database, and ask the user for clarification before finally returning an answer. Without a clear path to trace these calls, debugging a failing agent feels like searching for a needle in a digital haystack.

Fortunately, the July 28 MCP spec natively addresses this by mandating support for W3C Trace Context propagation. By pairing this specification with the robust, cloud-native capabilities of Quarkus and OpenTelemetry, you can easily map, monitor, and master the chaos of complex, multi-round-trip agentic workflows.

The Chaos of the Multi-Round-Trip Agentic Loop

Standard microservice architectures rely on a predictable, linear request-response lifecycle. A user hits a gateway; the gateway calls a backend service; the backend service queries a database; and the result bubbles back up to the client. If a failure occurs, a single Trace ID ties the entire chain together.

AI agents do not behave this way. They operate in highly unpredictable loops.

The most challenging addition to the July 28 spec is the formalization of the InputRequiredResult. This is a mechanism designed for human-in-the-loop interactions. If an AI agent decides it needs to execute a high-risk tool (like initiating a bank transfer or deleting a cloud resource), the MCP server can pause the execution and return  InputRequiredResult to the host model. The host model then stops, prompts the human user for validation, waits for a response, and eventually sends a completely new HTTP request to resume the execution.

Plain Text
 
[Agent Host] ──(1. Run Tool)──> [Quarkus MCP]
[Agent Host] <──(2. Input Required)── [Quarkus MCP] (Execution Halts)
     │
     ▼ (User inputs confirmation manually)
     │
[Agent Host] ──(3. Resume Tool with Input)──> [Quarkus MCP] (New Container Instance)


Because the execution stops and resumes across entirely different HTTP calls — and potentially entirely different container instances in a scaled cloud environment — standard context propagation fails. Without a standardized distributed tracing strategy, your observability backend will treat this single, cohesive workflow as a series of disconnected, anonymous requests.

Enter W3C Trace Context: The Secret to Agent Observability

To solve the fragmented tracking problem, the new MCP specification officially leverages W3C Trace Context. When an AI host or orchestrator initiates a tool call, it is required to inject tracing metadata directly into the JSON-RPC request body inside the _meta object.

The W3C format standardizes how tracing information is passed across boundaries using two key fields:

  • traceparent: A single, hyphen-delimited string containing the trace version, a unique 16-byte Trace ID, a 8-byte parent Span ID, and trace flags.
  • tracestate: An optional header designed to pass system-specific configuration or routing data without breaking compliance.

By forcing the host LLM to pass these values, the MCP server can extract the trace context, bind it to its own local OpenTelemetry context, and continue the span.

Integrating OpenTelemetry Into Your Quarkus MCP Server

Quarkus makes implementing this complex tracing logic exceptionally elegant. Instead of writing verbose tracing boilerplate, you can leverage the quarkus-opentelemetry extension, which provides full integration with the OpenTelemetry SDK out of the box.

First, include the OpenTelemetry dependency in your pom.xml file:

XML
 
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-opentelemetry</artifactId>
</dependency>


Next, configure your tracing export endpoints in application.properties. Quarkus will automatically handle the asynchronous exporting of spans to your collectors (such as Jaeger, Zipkin, or Grafana Tempo):

Properties files
 
quarkus.otel.enabled=true
quarkus.otel.exporter.otlp.endpoint=http://jaeger-collector:4317
quarkus.otel.service.name=mcp-customer-tool-service


Writing the Tracing Interceptor in Java

To automatically extract the W3C context from the incoming JSON payload and link it to our Quarkus OpenTelemetry tracer, we can build a simple interceptor. This ensures that every tool execution is correctly nested under the client’s original execution span:

Java
 
package com.example.mcp.telemetry;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import jakarta.inject.Inject;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.ext.Provider;
import io.vertx.core.json.JsonObject;
import java.io.ByteArrayInputStream;
import java.io.IOException;

@Provider
public class McpTracingFilter implements ContainerRequestFilter {

    @Inject
    Tracer tracer;

    @Inject
    io.opentelemetry.api.OpenTelemetry openTelemetry;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        byte[] bodyBytes = requestContext.getEntityStream().readAllBytes();
        requestContext.setEntityStream(new ByteArrayInputStream(bodyBytes));

        try {
            JsonObject bodyJson = new JsonObject(new String(bodyBytes));
            JsonObject meta = bodyJson.getJsonObject("params").getJsonObject("_meta");

            if (meta != null && meta.containsKey("traceparent")) {
                // Extract the W3C Trace Context using the OpenTelemetry Propagator
                Context extractedContext = openTelemetry.getPropagator().getTextMapPropagator()
                    .extract(Context.current(), meta, new TextMapGetter<JsonObject>() {
                        @Override
                        public Iterable<String> keys(JsonObject carrier) {
                            return carrier.getMap().keySet();
                        }

                        @Override
                        public String get(JsonObject carrier, String key) {
                            return carrier.getString(key);
                        }
                    });

                // Start a new span parented by the extracted context
                Span span = tracer.spanBuilder("mcp_tool_execution")
                        .setParent(extractedContext)
                        .startSpan();

                // Store the span in the request context to close it later
                requestContext.setProperty("mcp-span", span);
                span.makeCurrent();
            }
        } catch (Exception e) {
            // Fallback gracefully if tracing context is missing or corrupted
        }
    }
}


Visualizing the Agentic Waterfall in Production

Once you have configured the interceptor, the benefits are immediate. When an agent initiates a multi-turn session, your OpenTelemetry backend will construct a unified, hierarchical trace.

If you view the trace in Jaeger or Grafana Tempo, you will see a clear, structured waterfall diagram:

  1. Root Span (agent_session_start): Initiated by the AI orchestrator when the user submits their primary prompt.
  2. Child Span (execute_customer_lookup): Spanned when the agent calls your Quarkus MCP service to retrieve database records.
  3. Database Span (SELECT FROM customers): Automatically tracked by Quarkus Hibernate Reactive, showing the exact SQL performance.
  4. Pause Span (InputRequiredResult): Records the latency of the system waiting for the user to click "Confirm."
  5. Resume Span (finalize_transaction): Shows the second stateless container picking up the trace using the same Trace ID to complete the job.

With this level of visibility, you can pinpoint exactly which step of the loop failed, identify which specific tool execution caused the agent to slow down, and trace any downstream database or API issues directly back to the original LLM decision.

Summary

Decentralized, stateless architectures solved our scaling problems, but they threatened our ability to monitor applications. By incorporating W3C Trace Context into the July 28 specification, the creators of MCP have provided the blueprints for enterprise-grade AI observability.

By leveraging the built-in, reactive telemetry capabilities of Quarkus and OpenTelemetry, Java developers can shine a light directly into the black box of autonomous agent execution. This ensures your systems remain secure, fast, and completely auditable.

Database Data Types large language model

Opinions expressed by DZone contributors are their own.

Related

  • LangChain With SQL Databases: Natural Language to SQL Queries
  • Context Rot: Why Your AI Agent Gets Worse the Longer It Works
  • Custom Model Context Protocol (MCP) for NL2SQL: A Rigorous Evaluation Framework on Oracle Database
  • The LLM Selection War Story: Part 4 - Your Production Failure Testing Suite

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook