diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java index 4eaee01fb..bf5dac201 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java @@ -133,10 +133,20 @@ public class McpStatelessAsyncServer { this.protocolVersions = new ArrayList<>(mcpTransport.protocolVersions()); - McpStatelessServerHandler handler = new DefaultMcpStatelessServerHandler(requestHandlers, Map.of()); + Map notificationHandlers = prepareNotificationHandlers(); + McpStatelessServerHandler handler = new DefaultMcpStatelessServerHandler(requestHandlers, notificationHandlers); mcpTransport.setMcpHandler(handler); } + private Map prepareNotificationHandlers() { + Map notificationHandlers = new HashMap<>(); + + notificationHandlers.put(McpSchema.METHOD_NOTIFICATION_INITIALIZED, (exchange, params) -> Mono.empty()); + notificationHandlers.put(McpSchema.METHOD_NOTIFICATION_ROOTS_LIST_CHANGED, (exchange, params) -> Mono.empty()); + + return notificationHandlers; + } + // --------------------------------------- // Lifecycle Management // --------------------------------------- diff --git a/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStatelessIntegrationTests.java b/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStatelessIntegrationTests.java index a792ff5e0..42aa51200 100644 --- a/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStatelessIntegrationTests.java +++ b/mcp-test/src/test/java/io/modelcontextprotocol/server/HttpServletStatelessIntegrationTests.java @@ -10,6 +10,12 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; import io.modelcontextprotocol.client.McpClient; import io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport; import io.modelcontextprotocol.common.McpTransportContext; @@ -41,7 +47,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; - import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.web.client.RestClient; @@ -765,6 +770,68 @@ void testThrownMcpErrorAndJsonRpcError() throws Exception { mcpServer.close(); } + @Test + void testInitializedNotificationDoesNotLogWarn() { + Logger handlerLogger = (Logger) LoggerFactory + .getLogger("io.modelcontextprotocol.server.DefaultMcpStatelessServerHandler"); + ListAppender logAppender = new ListAppender<>(); + logAppender.start(); + handlerLogger.addAppender(logAppender); + + try { + var mcpServer = McpServer.sync(mcpStatelessServerTransport) + .serverInfo("test-server", "1.0.0") + .capabilities(ServerCapabilities.builder().build()) + .build(); + + try (var mcpClient = clientBuilder.build()) { + mcpClient.initialize(); // automatically sends notifications/initialized + } + finally { + mcpServer.close(); + } + } + finally { + handlerLogger.detachAppender(logAppender); + logAppender.stop(); + } + + assertThat(logAppender.list).noneMatch(event -> event.getLevel() == Level.WARN + && (event.getFormattedMessage().contains(McpSchema.METHOD_NOTIFICATION_INITIALIZED) + || event.getFormattedMessage().contains("Missing handler for request type"))); + } + + @Test + void testRootsListChangedNotificationDoesNotLogWarn() { + Logger handlerLogger = (Logger) LoggerFactory.getLogger(DefaultMcpStatelessServerHandler.class); + ListAppender logAppender = new ListAppender<>(); + logAppender.start(); + handlerLogger.addAppender(logAppender); + + try { + var mcpServer = McpServer.sync(mcpStatelessServerTransport) + .serverInfo("test-server", "1.0.0") + .capabilities(ServerCapabilities.builder().build()) + .build(); + + try (var mcpClient = clientBuilder.build()) { + mcpClient.initialize(); + mcpClient.rootsListChangedNotification(); + } + finally { + mcpServer.close(); + } + } + finally { + handlerLogger.detachAppender(logAppender); + logAppender.stop(); + } + + assertThat(logAppender.list).noneMatch(event -> event.getLevel() == Level.WARN + && (event.getFormattedMessage().contains(McpSchema.METHOD_NOTIFICATION_ROOTS_LIST_CHANGED) + || event.getFormattedMessage().contains("Missing handler for request type"))); + } + private double evaluateExpression(String expression) { // Simple expression evaluator for testing return switch (expression) {