|
| 1 | +/* |
| 2 | + * Copyright 2025 the original author or authors. |
| 3 | + */ |
| 4 | +package io.modelcontextprotocol.client; |
| 5 | + |
| 6 | +import java.util.function.Consumer; |
| 7 | + |
| 8 | +import org.slf4j.Logger; |
| 9 | +import org.slf4j.LoggerFactory; |
| 10 | +import org.slf4j.event.Level; |
| 11 | + |
| 12 | +import io.modelcontextprotocol.client.McpClient.SyncSpec; |
| 13 | +import io.modelcontextprotocol.spec.McpSchema; |
| 14 | +import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification; |
| 15 | + |
| 16 | +/** |
| 17 | + * MCP Client-side consumer which logs received messages from MCP Servers using SLF4J. |
| 18 | + * |
| 19 | + * <p> |
| 20 | + * Use this for {@link SyncSpec#loggingConsumer(Consumer)} to log received MCP messages. |
| 21 | + * |
| 22 | + * @author <a href="http://www.vorburger.ch">Michael Vorburger.ch</a> |
| 23 | + */ |
| 24 | +public class Slf4jLoggingConsumer implements Consumer<McpSchema.LoggingMessageNotification> { |
| 25 | + |
| 26 | + // This class originated in |
| 27 | + // https://github.com/enola-dev/enola/blob/ffc004666ea7f71357562ef12464d2b9fdbf9dbd/java/dev/enola/ai/mcp/McpServer.java#L29 |
| 28 | + // where it was used for https://docs.enola.dev/concepts/mcp/. |
| 29 | + // |
| 30 | + // It then found its way into Google's Agent Development Kit (ADK) in |
| 31 | + // https://github.com/google/adk-java/pull/370. It's now been moved here to be useful |
| 32 | + // to others. |
| 33 | + |
| 34 | + @Override |
| 35 | + public void accept(LoggingMessageNotification notif) { |
| 36 | + Logger log = LoggerFactory.getLogger(notif.logger()); |
| 37 | + if (notif.meta().isEmpty()) { |
| 38 | + // If no meta, then just log the data as a message |
| 39 | + log.atLevel(convert(notif.level())).log(notif.data()); |
| 40 | + } |
| 41 | + else { |
| 42 | + // If there is meta, then log it as a structured log message |
| 43 | + var builder = log.atLevel(convert(notif.level())).setMessage(notif.data()); |
| 44 | + notif.meta().forEach((key, value) -> builder.addKeyValue(key, value)); |
| 45 | + builder.log(); |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + private Level convert(McpSchema.LoggingLevel level) { |
| 50 | + return switch (level) { |
| 51 | + case DEBUG -> Level.DEBUG; |
| 52 | + case INFO, NOTICE -> Level.INFO; |
| 53 | + case WARNING -> Level.WARN; |
| 54 | + case ERROR, CRITICAL, ALERT, EMERGENCY -> Level.ERROR; |
| 55 | + }; |
| 56 | + } |
| 57 | + |
| 58 | +} |
0 commit comments