Skip to content

Commit 41c83e3

Browse files
authored
refactor: fix typo in SyncMcpLoggingProvider class name (spring-ai-community#64)
- Rename SyncMcpLogginProvider to SyncMcpLoggingProvider (fix typo: Loggin -> Logging) - Add @deprecated annotation to old class with reference to new class - Update all test references to use the corrected class name - New class maintains identical functionality with corrected naming Signed-off-by: Christian Tzolov <[email protected]>
1 parent 1ab5881 commit 41c83e3

File tree

3 files changed

+118
-4
lines changed

3 files changed

+118
-4
lines changed

mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/logging/SyncMcpLogginProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@
5656
* @see McpLogging
5757
* @see SyncMcpLoggingMethodCallback
5858
* @see LoggingMessageNotification
59+
* @deprecated Use {@link SyncMcpLoggingProvider} instead.
5960
*/
61+
@Deprecated
6062
public class SyncMcpLogginProvider {
6163

6264
private final List<Object> loggingConsumerObjects;
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright 2025-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springaicommunity.mcp.provider.logging;
18+
19+
import java.lang.reflect.Method;
20+
import java.util.List;
21+
import java.util.function.Consumer;
22+
import java.util.stream.Stream;
23+
24+
import org.springaicommunity.mcp.annotation.McpLogging;
25+
import org.springaicommunity.mcp.method.logging.SyncLoggingSpecification;
26+
import org.springaicommunity.mcp.method.logging.SyncMcpLoggingMethodCallback;
27+
28+
import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
29+
import io.modelcontextprotocol.util.Assert;
30+
import reactor.core.publisher.Mono;
31+
32+
/**
33+
* Provider for synchronous logging consumer callbacks.
34+
*
35+
* <p>
36+
* This class scans a list of objects for methods annotated with {@link McpLogging} and
37+
* creates {@link Consumer} callbacks for them. These callbacks can be used to handle
38+
* logging message notifications from MCP servers.
39+
*
40+
* <p>
41+
* Example usage: <pre>{@code
42+
* // Create a provider with a list of objects containing @McpLoggingConsumer methods
43+
* SyncMcpLoggingConsumerProvider provider = new SyncMcpLoggingConsumerProvider(List.of(loggingHandler));
44+
*
45+
* // Get the list of logging consumer callbacks
46+
* List<Consumer<LoggingMessageNotification>> consumers = provider.getLoggingConsumers();
47+
*
48+
* // Add the consumers to the client features
49+
* McpClientFeatures.Sync clientFeatures = new McpClientFeatures.Sync(
50+
* clientInfo, clientCapabilities, roots,
51+
* toolsChangeConsumers, resourcesChangeConsumers, promptsChangeConsumers,
52+
* consumers, samplingHandler);
53+
* }</pre>
54+
*
55+
* @author Christian Tzolov
56+
* @see McpLogging
57+
* @see SyncMcpLoggingMethodCallback
58+
* @see LoggingMessageNotification
59+
*/
60+
public class SyncMcpLoggingProvider {
61+
62+
private final List<Object> loggingConsumerObjects;
63+
64+
/**
65+
* Create a new SyncMcpLoggingConsumerProvider.
66+
* @param loggingConsumerObjects the objects containing methods annotated with
67+
* {@link McpLogging}
68+
*/
69+
public SyncMcpLoggingProvider(List<Object> loggingConsumerObjects) {
70+
Assert.notNull(loggingConsumerObjects, "loggingConsumerObjects cannot be null");
71+
this.loggingConsumerObjects = loggingConsumerObjects;
72+
}
73+
74+
/**
75+
* Get the list of logging consumer callbacks.
76+
* @return the list of logging consumer callbacks
77+
*/
78+
public List<SyncLoggingSpecification> getLoggingSpecifications() {
79+
80+
List<SyncLoggingSpecification> loggingConsumers = this.loggingConsumerObjects.stream()
81+
.map(consumerObject -> Stream.of(doGetClassMethods(consumerObject))
82+
.filter(method -> method.isAnnotationPresent(McpLogging.class))
83+
.filter(method -> !Mono.class.isAssignableFrom(method.getReturnType()))
84+
.sorted((m1, m2) -> m1.getName().compareTo(m2.getName()))
85+
.map(mcpLoggingConsumerMethod -> {
86+
var loggingConsumerAnnotation = mcpLoggingConsumerMethod.getAnnotation(McpLogging.class);
87+
88+
Consumer<LoggingMessageNotification> methodCallback = SyncMcpLoggingMethodCallback.builder()
89+
.method(mcpLoggingConsumerMethod)
90+
.bean(consumerObject)
91+
.loggingConsumer(loggingConsumerAnnotation)
92+
.build();
93+
94+
return new SyncLoggingSpecification(loggingConsumerAnnotation.clients(), methodCallback);
95+
})
96+
.toList())
97+
.flatMap(List::stream)
98+
.toList();
99+
100+
return loggingConsumers;
101+
}
102+
103+
/**
104+
* Returns the methods of the given bean class.
105+
* @param bean the bean instance
106+
* @return the methods of the bean class
107+
*/
108+
protected Method[] doGetClassMethods(Object bean) {
109+
return bean.getClass().getDeclaredMethods();
110+
}
111+
112+
}

mcp-annotations/src/test/java/org/springaicommunity/mcp/provider/logging/SyncMcpLoggingProviderTests.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
1818

1919
/**
20-
* Tests for {@link SyncMcpLogginProvider}.
20+
* Tests for {@link SyncMcpLoggingProvider}.
2121
*
2222
* @author Christian Tzolov
2323
*/
@@ -60,7 +60,7 @@ public void notAnnotatedMethod(LoggingMessageNotification notification) {
6060
@Test
6161
void testGetLoggingConsumers() {
6262
LoggingHandler loggingHandler = new LoggingHandler();
63-
SyncMcpLogginProvider provider = new SyncMcpLogginProvider(List.of(loggingHandler));
63+
SyncMcpLoggingProvider provider = new SyncMcpLoggingProvider(List.of(loggingHandler));
6464

6565
List<SyncLoggingSpecification> specifications = provider.getLoggingSpecifications();
6666
List<Consumer<LoggingMessageNotification>> consumers = specifications.stream()
@@ -89,7 +89,7 @@ void testGetLoggingConsumers() {
8989

9090
@Test
9191
void testEmptyList() {
92-
SyncMcpLogginProvider provider = new SyncMcpLogginProvider(List.of());
92+
SyncMcpLoggingProvider provider = new SyncMcpLoggingProvider(List.of());
9393

9494
List<Consumer<LoggingMessageNotification>> consumers = provider.getLoggingSpecifications()
9595
.stream()
@@ -103,7 +103,7 @@ void testEmptyList() {
103103
void testMultipleObjects() {
104104
LoggingHandler handler1 = new LoggingHandler();
105105
LoggingHandler handler2 = new LoggingHandler();
106-
SyncMcpLogginProvider provider = new SyncMcpLogginProvider(List.of(handler1, handler2));
106+
SyncMcpLoggingProvider provider = new SyncMcpLoggingProvider(List.of(handler1, handler2));
107107

108108
List<Consumer<LoggingMessageNotification>> consumers = provider.getLoggingSpecifications()
109109
.stream()

0 commit comments

Comments
 (0)