diff --git a/README.md b/README.md index 55510ce..b2b077d 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ The Spring integration module provides seamless integration with Spring AI and S ### Annotations #### Client -- **`@McpLogging`** - Annotates methods that handle logging message notifications from MCP servers +- **`@McpLogging`** - Annotates methods that handle logging message notifications from MCP servers (requires `clientId` parameter) - **`@McpSampling`** - Annotates methods that handle sampling requests from MCP servers - **`@McpElicitation`** - Annotates methods that handle elicitation requests to gather additional information from users - **`@McpProgress`** - Annotates methods that handle progress notifications for long-running operations @@ -931,9 +931,10 @@ public class LoggingHandler { /** * Handle logging message notifications with a single parameter. + * Note: clientId is now required for all @McpLogging annotations. * @param notification The logging message notification */ - @McpLogging + @McpLogging(clientId = "default-client") public void handleLoggingMessage(LoggingMessageNotification notification) { System.out.println("Received logging message: " + notification.level() + " - " + notification.logger() + " - " + notification.data()); @@ -941,11 +942,12 @@ public class LoggingHandler { /** * Handle logging message notifications with individual parameters. + * Note: clientId is now required for all @McpLogging annotations. * @param level The logging level * @param logger The logger name * @param data The log message data */ - @McpLogging + @McpLogging(clientId = "default-client") public void handleLoggingMessageWithParams(LoggingLevel level, String logger, String data) { System.out.println("Received logging message with params: " + level + " - " + logger + " - " + data); } diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpLogging.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpLogging.java index f4a4c53..3d07fb9 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpLogging.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpLogging.java @@ -52,9 +52,9 @@ public @interface McpLogging { /** - * Used as connection or client identifier to select the MCP client, the logging - * consumer is associated with. If not specified, is applied to all clients. + * Used as connection or client identifier to select the MCP clients, the logging + * consumer is associated with. At least one client ID must be specified. */ - String clientId() default ""; + String clientId(); } diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/logging/AsyncLoggingSpecification.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/logging/AsyncLoggingSpecification.java index a6fd933..d19412a 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/logging/AsyncLoggingSpecification.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/logging/AsyncLoggingSpecification.java @@ -4,6 +4,7 @@ package org.springaicommunity.mcp.method.logging; +import java.util.Objects; import java.util.function.Function; import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification; @@ -11,4 +12,13 @@ public record AsyncLoggingSpecification(String clientId, Function> loggingHandler) { + + public AsyncLoggingSpecification { + Objects.requireNonNull(clientId, "clientId must not be null"); + if (clientId.trim().isEmpty()) { + throw new IllegalArgumentException("clientId must not be empty"); + } + Objects.requireNonNull(loggingHandler, "loggingHandler must not be null"); + } + } \ No newline at end of file diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/logging/SyncLoggingSpecification.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/logging/SyncLoggingSpecification.java index ce9647a..96b1b3c 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/logging/SyncLoggingSpecification.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/logging/SyncLoggingSpecification.java @@ -4,9 +4,18 @@ package org.springaicommunity.mcp.method.logging; +import java.util.Objects; import java.util.function.Consumer; import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification; public record SyncLoggingSpecification(String clientId, Consumer loggingHandler) { -} \ No newline at end of file + + public SyncLoggingSpecification { + Objects.requireNonNull(clientId, "clientId must not be null"); + if (clientId.trim().isEmpty()) { + throw new IllegalArgumentException("clientId must not be empty"); + } + Objects.requireNonNull(loggingHandler, "loggingHandler must not be null"); + } +} diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/AsyncMcpLoggingMethodCallbackExample.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/AsyncMcpLoggingMethodCallbackExample.java index b4e3541..9fc613e 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/AsyncMcpLoggingMethodCallbackExample.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/AsyncMcpLoggingMethodCallbackExample.java @@ -29,7 +29,7 @@ public class AsyncMcpLoggingMethodCallbackExample { * @param notification The logging message notification * @return A Mono that completes when the processing is done */ - @McpLogging + @McpLogging(clientId = "test-client") public Mono handleLoggingMessage(LoggingMessageNotification notification) { return Mono.fromRunnable(() -> { System.out.println("Received logging message: " + notification.level() + " - " + notification.logger() @@ -45,7 +45,7 @@ public Mono handleLoggingMessage(LoggingMessageNotification notification) * @param data The log message data * @return A Mono that completes when the processing is done */ - @McpLogging + @McpLogging(clientId = "test-client") public Mono handleLoggingMessageWithParams(LoggingLevel level, String logger, String data) { return Mono.fromRunnable(() -> { System.out.println("Received logging message with params: " + level + " - " + logger + " - " + data); @@ -56,7 +56,7 @@ public Mono handleLoggingMessageWithParams(LoggingLevel level, String logg * Example method that accepts a LoggingMessageNotification with void return type. * @param notification The logging message notification */ - @McpLogging + @McpLogging(clientId = "test-client") public void handleLoggingMessageVoid(LoggingMessageNotification notification) { System.out.println("Received logging message (void): " + notification.level() + " - " + notification.logger() + " - " + notification.data()); diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/AsyncMcpLoggingMethodCallbackTests.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/AsyncMcpLoggingMethodCallbackTests.java index 34a768a..03e6e4a 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/AsyncMcpLoggingMethodCallbackTests.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/AsyncMcpLoggingMethodCallbackTests.java @@ -41,14 +41,14 @@ static class ValidMethods { private String lastData; - @McpLogging + @McpLogging(clientId = "test-client") public Mono handleLoggingMessage(LoggingMessageNotification notification) { return Mono.fromRunnable(() -> { this.lastNotification = notification; }); } - @McpLogging + @McpLogging(clientId = "test-client") public Mono handleLoggingMessageWithParams(LoggingLevel level, String logger, String data) { return Mono.fromRunnable(() -> { this.lastLevel = level; @@ -57,7 +57,7 @@ public Mono handleLoggingMessageWithParams(LoggingLevel level, String logg }); } - @McpLogging + @McpLogging(clientId = "test-client") public void handleLoggingMessageVoid(LoggingMessageNotification notification) { this.lastNotification = notification; } @@ -69,27 +69,27 @@ public void handleLoggingMessageVoid(LoggingMessageNotification notification) { */ static class InvalidMethods { - @McpLogging + @McpLogging(clientId = "test-client") public String invalidReturnType(LoggingMessageNotification notification) { return "Invalid"; } - @McpLogging + @McpLogging(clientId = "test-client") public Mono invalidMonoReturnType(LoggingMessageNotification notification) { return Mono.just("Invalid"); } - @McpLogging + @McpLogging(clientId = "test-client") public Mono invalidParameterCount(LoggingMessageNotification notification, String extra) { return Mono.empty(); } - @McpLogging + @McpLogging(clientId = "test-client") public Mono invalidParameterType(String invalidType) { return Mono.empty(); } - @McpLogging + @McpLogging(clientId = "test-client") public Mono invalidParameterTypes(String level, int logger, boolean data) { return Mono.empty(); } diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/SyncMcpLoggingMethodCallbackExample.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/SyncMcpLoggingMethodCallbackExample.java index d6c42a1..c5d3c3f 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/SyncMcpLoggingMethodCallbackExample.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/SyncMcpLoggingMethodCallbackExample.java @@ -27,7 +27,7 @@ public class SyncMcpLoggingMethodCallbackExample { * Example method that accepts a LoggingMessageNotification. * @param notification The logging message notification */ - @McpLogging + @McpLogging(clientId = "test-client") public void handleLoggingMessage(LoggingMessageNotification notification) { System.out.println("Received logging message: " + notification.level() + " - " + notification.logger() + " - " + notification.data()); @@ -39,7 +39,7 @@ public void handleLoggingMessage(LoggingMessageNotification notification) { * @param logger The logger name * @param data The log message data */ - @McpLogging + @McpLogging(clientId = "test-client") public void handleLoggingMessageWithParams(LoggingLevel level, String logger, String data) { System.out.println("Received logging message with params: " + level + " - " + logger + " - " + data); } diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/SyncMcpLoggingMethodCallbackTests.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/SyncMcpLoggingMethodCallbackTests.java index 953759a..6a3a67e 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/SyncMcpLoggingMethodCallbackTests.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/method/logging/SyncMcpLoggingMethodCallbackTests.java @@ -39,12 +39,12 @@ static class ValidMethods { private String lastData; - @McpLogging + @McpLogging(clientId = "test-client") public void handleLoggingMessage(LoggingMessageNotification notification) { this.lastNotification = notification; } - @McpLogging + @McpLogging(clientId = "test-client") public void handleLoggingMessageWithParams(LoggingLevel level, String logger, String data) { this.lastLevel = level; this.lastLogger = logger; @@ -58,22 +58,22 @@ public void handleLoggingMessageWithParams(LoggingLevel level, String logger, St */ static class InvalidMethods { - @McpLogging + @McpLogging(clientId = "test-client") public String invalidReturnType(LoggingMessageNotification notification) { return "Invalid"; } - @McpLogging + @McpLogging(clientId = "test-client") public void invalidParameterCount(LoggingMessageNotification notification, String extra) { // Invalid parameter count } - @McpLogging + @McpLogging(clientId = "test-client") public void invalidParameterType(String invalidType) { // Invalid parameter type } - @McpLogging + @McpLogging(clientId = "test-client") public void invalidParameterTypes(String level, int logger, boolean data) { // Invalid parameter types } diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/logging/AsyncMcpLoggingProviderTests.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/logging/AsyncMcpLoggingProviderTests.java index 0a0f892..688c0bc 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/logging/AsyncMcpLoggingProviderTests.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/logging/AsyncMcpLoggingProviderTests.java @@ -38,14 +38,14 @@ static class TestAsyncLoggingProvider { private String lastData; - @McpLogging + @McpLogging(clientId = "test-client") public Mono handleLoggingMessage(LoggingMessageNotification notification) { return Mono.fromRunnable(() -> { this.lastNotification = notification; }); } - @McpLogging + @McpLogging(clientId = "test-client") public Mono handleLoggingMessageWithParams(LoggingLevel level, String logger, String data) { return Mono.fromRunnable(() -> { this.lastLevel = level; @@ -54,7 +54,7 @@ public Mono handleLoggingMessageWithParams(LoggingLevel level, String logg }); } - @McpLogging + @McpLogging(clientId = "test-client") public void handleLoggingMessageVoid(LoggingMessageNotification notification) { this.lastNotification = notification; } diff --git a/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/logging/SyncMcpLoggingProviderTests.java b/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/logging/SyncMcpLoggingProviderTests.java index c36d147..cf49400 100644 --- a/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/logging/SyncMcpLoggingProviderTests.java +++ b/mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/logging/SyncMcpLoggingProviderTests.java @@ -36,12 +36,12 @@ static class LoggingHandler { private String lastData; - @McpLogging + @McpLogging(clientId = "test-client") public void handleLoggingMessage(LoggingMessageNotification notification) { this.lastNotification = notification; } - @McpLogging + @McpLogging(clientId = "test-client") public void handleLoggingMessageWithParams(LoggingLevel level, String logger, String data) { this.lastLevel = level; this.lastLogger = logger;