CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-mcp

Quarkus extension for integrating Model Context Protocol (MCP) client capabilities with LangChain4j

Overview
Eval results
Files

observability.mddocs/

Observability

Health checks, Micrometer metrics, request/response logging, OpenTelemetry tracing, and CDI events for MCP server logs. Comprehensive observability support for monitoring MCP client operations.

Capabilities

Health Checks

MicroProfile health check for verifying MCP client connectivity.

package io.quarkiverse.langchain4j.mcp.runtime;

public class McpClientHealthCheck implements HealthCheck {
    /**
     * Create a health check for all configured MCP clients.
     *
     * @param mcpRuntimeConfig the MCP runtime configuration
     */
    public McpClientHealthCheck(McpRuntimeConfiguration mcpRuntimeConfig) { ... }

    /**
     * Performs health check for all configured MCP clients.
     * Checks readiness by pinging servers or using MicroProfile health endpoints.
     *
     * @return HealthCheckResponse indicating UP or DOWN status
     */
    public HealthCheckResponse call() { ... }
}

Features:

  • Automatically registered as a @Readiness check
  • Checks all configured MCP clients
  • Uses MicroProfile health endpoints if available on HTTP servers
  • Falls back to standard MCP ping for STDIO and non-MicroProfile servers
  • Can be disabled globally or per-client

Configuration:

# Disable health checks globally
quarkus.langchain4j.mcp.mp-health-enabled=false

# Disable for specific client
quarkus.langchain4j.mcp.github.microprofile-health-check=false

# Custom health check path
quarkus.langchain4j.mcp.github.microprofile-health-check-path=/health/ready

Usage:

Health check is automatically available at Quarkus health endpoints:

# Check readiness
curl http://localhost:8080/q/health/ready

# Check liveness
curl http://localhost:8080/q/health/live

Response includes MCP client status:

{
  "status": "UP",
  "checks": [
    {
      "name": "MCP Clients Health Check",
      "status": "UP",
      "data": {
        "github": "UP",
        "filesystem": "UP",
        "database": "UP"
      }
    }
  ]
}

Metrics

Micrometer metrics for MCP operations.

package io.quarkiverse.langchain4j.mcp.runtime;

public class MetricsMcpListener implements McpClientListener {
    /**
     * Create a metrics listener for the specified MCP client.
     *
     * @param mcpClientKey the MCP client name
     */
    public MetricsMcpListener(String mcpClientKey) { ... }

    // Lifecycle methods from McpClientListener interface
    void beforeExecuteTool(McpCallContext context);
    void afterExecuteTool(McpCallContext context, ToolExecutionResult result, Map<String, Object> rawResult);
    void onExecuteToolError(McpCallContext context, Throwable error);
    void beforeResourceGet(McpCallContext context);
    void afterResourceGet(McpCallContext context, McpReadResourceResult result, Map<String, Object> rawResult);
    void onResourceGetError(McpCallContext context, Throwable error);
    void beforePromptGet(McpCallContext context);
    void afterPromptGet(McpCallContext context, McpGetPromptResult result, Map<String, Object> rawResult);
    void onPromptGetError(McpCallContext context, Throwable error);
}

Metrics Published:

  1. Tool Call Duration (mcp.client.tool.call.duration)

    • Type: Timer
    • Tags: mcp_client (client name), outcome (success/failure), tool_name (tool name)
    • Measures: Time taken to execute a tool
  2. Resource Get Duration (mcp.client.resource.get.duration)

    • Type: Timer
    • Tags: mcp_client (client name), outcome (success/failure)
    • Measures: Time taken to retrieve a resource
  3. Prompt Get Duration (mcp.client.prompt.get.duration)

    • Type: Timer
    • Tags: mcp_client (client name), outcome (success/failure)
    • Measures: Time taken to retrieve a prompt

Configuration:

# Enable metrics for specific clients
quarkus.langchain4j.mcp.github.metrics-enabled=true
quarkus.langchain4j.mcp.database.metrics-enabled=true

Accessing Metrics:

Metrics are available through Micrometer endpoints (if quarkus-micrometer is present):

# Prometheus format
curl http://localhost:8080/q/metrics

# Example output:
# mcp_client_tool_call_duration_seconds_count{mcp_client="github",outcome="success",tool_name="list_repos"} 42
# mcp_client_tool_call_duration_seconds_sum{mcp_client="github",outcome="success",tool_name="list_repos"} 2.1

Request/Response Logging

Configurable logging for MCP requests and responses.

Configuration:

# Enable request logging
quarkus.langchain4j.mcp.github.log-requests=true

# Enable response logging
quarkus.langchain4j.mcp.github.log-responses=true

# Enable both
quarkus.langchain4j.mcp.database.log-requests=true
quarkus.langchain4j.mcp.database.log-responses=true

Log Output:

Requests and responses are logged at INFO level:

INFO  [io.qua.lan.mcp.run.htt.McpHttpClientLogger] Request: POST https://api.github.com/mcp
INFO  [io.qua.lan.mcp.run.htt.McpHttpClientLogger] Headers: {Authorization: Bearer ghp_***}
INFO  [io.qua.lan.mcp.run.htt.McpHttpClientLogger] Body: {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_repos"}}
INFO  [io.qua.lan.mcp.run.htt.McpHttpClientLogger] Response: 200 OK
INFO  [io.qua.lan.mcp.run.htt.McpHttpClientLogger] Body: {"jsonrpc":"2.0","id":1,"result":{"content":[...]}}

Server Log Handler

Handler for MCP server log messages.

package io.quarkiverse.langchain4j.mcp.runtime;

public class QuarkusDefaultMcpLogHandler implements McpLogMessageHandler {
    /**
     * Create a log handler for the specified MCP client.
     *
     * @param clientName the MCP client name
     */
    public QuarkusDefaultMcpLogHandler(String clientName) { ... }

    /**
     * Handle log messages from MCP servers.
     * Logs via JBoss logging and fires CDI events.
     *
     * @param message the log message from the MCP server
     */
    void handleLogMessage(McpLogMessage message);
}

Features:

  • Logs messages via JBoss logging
  • Fires CDI events with @McpClientName qualifier
  • Supports all MCP log levels: DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY

Log Levels Mapping:

MCP LevelJava Level
DEBUGDEBUG
INFOINFO
NOTICEINFO
WARNINGWARN
ERRORERROR
CRITICALERROR
ALERTERROR
EMERGENCYERROR

Observing Server Logs via CDI Events:

import io.quarkiverse.langchain4j.mcp.runtime.McpClientName;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import dev.langchain4j.mcp.client.protocol.LoggingLevel;

@ApplicationScoped
public class McpLogObserver {
    // Observe logs from all MCP servers
    public void onLog(@Observes McpLogMessage logMessage) {
        System.out.println("MCP Log: " + logMessage.getMessage());
    }

    // Observe logs from specific MCP server
    public void onGitHubLog(@Observes @McpClientName("github") McpLogMessage logMessage) {
        if (logMessage.getLevel() == LoggingLevel.ERROR) {
            System.err.println("GitHub MCP Error: " + logMessage.getMessage());
        }
    }
}

OpenTelemetry Tracing

Automatic tracing integration for tool executions.

Features:

  • Automatic span creation for tool executions
  • Tool name included in span
  • Integrates with OpenTelemetry if present on classpath
  • No configuration required

Usage:

When OpenTelemetry is on the classpath, tool executions are automatically traced:

@RegisterAiService
public interface TracedAssistant {
    @McpToolBox("github")
    String createIssue(@UserMessage String message);
    // Tool calls automatically create spans in the trace
}

Trace Example:

Trace: request-123
  Span: AI Service Call
    Span: Tool Execution [github:create_issue]
      - tool_name: create_issue
      - mcp_client: github
      - outcome: success
      - duration: 1.2s

MicroProfile Health Check Interface

JAX-RS client interface for MicroProfile health endpoints.

package io.quarkiverse.langchain4j.mcp.runtime.http;

public interface McpMicroProfileHealthCheck {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    String healthCheck();
}

Used internally by McpClientHealthCheck to check HTTP-based MCP servers that expose MicroProfile health endpoints.

Configuration Examples

Complete Observability Setup

# Health checks
quarkus.langchain4j.mcp.mp-health-enabled=true
quarkus.langchain4j.mcp.github.microprofile-health-check=true
quarkus.langchain4j.mcp.github.microprofile-health-check-path=/q/health

# Metrics
quarkus.langchain4j.mcp.github.metrics-enabled=true
quarkus.langchain4j.mcp.filesystem.metrics-enabled=true
quarkus.langchain4j.mcp.database.metrics-enabled=true

# Logging
quarkus.langchain4j.mcp.github.log-requests=true
quarkus.langchain4j.mcp.github.log-responses=true
quarkus.langchain4j.mcp.database.log-requests=true
quarkus.langchain4j.mcp.database.log-responses=true

# Application logging level
quarkus.log.category."io.quarkiverse.langchain4j.mcp".level=INFO

Production Observability

# Health checks enabled
quarkus.langchain4j.mcp.mp-health-enabled=true

# Metrics enabled for critical clients
quarkus.langchain4j.mcp.payment-api.metrics-enabled=true
quarkus.langchain4j.mcp.order-api.metrics-enabled=true

# Request/response logging disabled (use tracing instead)
quarkus.langchain4j.mcp.payment-api.log-requests=false
quarkus.langchain4j.mcp.payment-api.log-responses=false

# OpenTelemetry tracing enabled
quarkus.otel.enabled=true
quarkus.otel.exporter.otlp.endpoint=http://jaeger:4317

Development Observability

# All observability features enabled for debugging
quarkus.langchain4j.mcp.mp-health-enabled=true
quarkus.langchain4j.mcp.github.metrics-enabled=true
quarkus.langchain4j.mcp.github.log-requests=true
quarkus.langchain4j.mcp.github.log-responses=true

# Verbose logging
quarkus.log.category."io.quarkiverse.langchain4j.mcp".level=DEBUG

Selective Logging

# Log only requests for one client
quarkus.langchain4j.mcp.debug-api.log-requests=true
quarkus.langchain4j.mcp.debug-api.log-responses=false

# Log only responses for another client
quarkus.langchain4j.mcp.monitor-api.log-requests=false
quarkus.langchain4j.mcp.monitor-api.log-responses=true

Monitoring Best Practices

Health Checks

  • Enable health checks in production for readiness probes
  • Configure appropriate ping timeouts
  • Monitor health check status for early warning of connectivity issues
  • Use Kubernetes readiness/liveness probes with Quarkus health endpoints

Metrics

  • Enable metrics for critical MCP clients
  • Set up alerting on high tool execution duration
  • Monitor tool failure rates (outcome=failure)
  • Track resource usage and performance trends

Logging

  • Enable request/response logging in development
  • Disable or minimize logging in production (use tracing instead)
  • Use structured logging for better analysis
  • Monitor server log events for errors and warnings

Tracing

  • Enable OpenTelemetry in production
  • Use tracing to debug complex AI service interactions
  • Correlate tool executions with user requests
  • Analyze latency and bottlenecks

Observability Stack Integration

Prometheus + Grafana

quarkus.micrometer.export.prometheus.enabled=true
quarkus.langchain4j.mcp.github.metrics-enabled=true

Expose metrics at /q/metrics and scrape with Prometheus:

scrape_configs:
  - job_name: 'quarkus-mcp'
    static_configs:
      - targets: ['app:8080']
    metrics_path: '/q/metrics'

Jaeger Tracing

quarkus.otel.enabled=true
quarkus.otel.exporter.otlp.endpoint=http://jaeger:4317
quarkus.otel.traces.sampler=always_on

ELK Stack Logging

quarkus.log.console.json=true
quarkus.langchain4j.mcp.github.log-requests=true
quarkus.langchain4j.mcp.github.log-responses=true

Ship logs to Elasticsearch and visualize in Kibana.

Kubernetes Integration

apiVersion: v1
kind: Pod
metadata:
  name: mcp-app
spec:
  containers:
  - name: app
    image: mcp-app:latest
    livenessProbe:
      httpGet:
        path: /q/health/live
        port: 8080
      initialDelaySeconds: 30
      periodSeconds: 10
    readinessProbe:
      httpGet:
        path: /q/health/ready
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 5

Important Notes

  • Health checks are automatically registered when SmallRye Health is present
  • Metrics require Micrometer to be on the classpath
  • OpenTelemetry tracing is automatic when OpenTelemetry is present
  • Request/response logging can impact performance - use selectively
  • CDI events for server logs allow custom log processing and routing
  • All observability features are optional and independently configurable
  • Use health check timeouts to prevent slow startups

Install with Tessl CLI

npx tessl i tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-mcp

docs

ai-service-integration.md

authentication.md

configuration.md

dev-ui.md

index.md

observability.md

registry-client.md

transport.md

tile.json