Skip to content

Commit 7266b7a

Browse files
authored
refactor(mcp-annotations): migrate client/server samples to annotation-based auto-registration (#69)
- Removed explicit dependency on from client and server modules; now rely on auto-registration via Spring AI MCP core. - Deleted manual customizer/configuration classes (, ) from client. - Refactored handler/provider classes: renamed and moved to reflect annotation-based usage. - Simplified application classes to remove explicit bean registration for MCP handlers/providers. - Updated documentation to describe the new annotation-driven approach, project structure, and removed boilerplate. - Adjusted properties and configuration for clarity and to match the new structure. - Ensure the proper clients paramter is set to all client mcp annotations, - Update READMEs This refactor streamlines the MCP annotation samples, leveraging automatic handler and tool registration for reduced boilerplate and improved maintainability. Signed-off-by: Christian Tzolov <[email protected]>
1 parent 07c7f8a commit 7266b7a

File tree

25 files changed

+389
-723
lines changed

25 files changed

+389
-723
lines changed

model-context-protocol/mcp-annotations/README.md

Lines changed: 50 additions & 127 deletions
Large diffs are not rendered by default.

model-context-protocol/mcp-annotations/mcp-annotations-client/pom.xml

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,10 @@
3434

3535
<dependencies>
3636

37-
<dependency>
38-
<groupId>org.springaicommunity</groupId>
39-
<artifactId>spring-ai-mcp-annotations</artifactId>
40-
<version>0.2.0-SNAPSHOT</version>
41-
</dependency>
42-
4337
<dependency>
4438
<groupId>org.springframework.ai</groupId>
4539
<artifactId>spring-ai-starter-mcp-client</artifactId>
4640
</dependency>
47-
48-
<dependency>
49-
<groupId>org.springframework.ai</groupId>
50-
<artifactId>spring-ai-starter-model-openai</artifactId>
51-
</dependency>
52-
53-
<dependency>
54-
<groupId>org.springframework.ai</groupId>
55-
<artifactId>spring-ai-starter-model-anthropic</artifactId>
56-
</dependency>
57-
5841
</dependencies>
5942

6043
<build>

model-context-protocol/mcp-annotations/mcp-annotations-client/src/main/java/org/springframework/ai/mcp/samples/client/McpClientApplication.java

Lines changed: 13 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,6 @@
1818
import java.util.List;
1919
import java.util.Map;
2020

21-
import org.springaicommunity.mcp.method.elicitation.SyncElicitationSpecification;
22-
import org.springaicommunity.mcp.method.logging.SyncLoggingSpecification;
23-
import org.springaicommunity.mcp.method.progress.SyncProgressSpecification;
24-
import org.springaicommunity.mcp.method.sampling.SyncSamplingSpecification;
25-
import org.springaicommunity.mcp.spring.SyncMcpAnnotationProviders;
26-
import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
27-
import org.springframework.ai.mcp.samples.client.customizers.AnnotationSyncClientCustomizer;
28-
import org.springframework.ai.openai.OpenAiChatModel;
2921
import org.springframework.boot.CommandLineRunner;
3022
import org.springframework.boot.SpringApplication;
3123
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -43,49 +35,25 @@ public static void main(String[] args) {
4335
}
4436

4537
@Bean
46-
public CommandLineRunner predefinedQuestions(OpenAiChatModel openAiChatModel,
38+
public CommandLineRunner predefinedQuestions(
4739
List<McpSyncClient> mcpClients) {
4840

4941
return args -> {
50-
McpSyncClient mcpClient = mcpClients.get(0);
5142

52-
// Call a tool that sends progress notifications
53-
CallToolRequest toolRequest = CallToolRequest.builder()
54-
.name("tool1")
55-
.arguments(Map.of("input", "test input"))
56-
.progressToken("test-progress-token")
57-
.build();
43+
for (McpSyncClient mcpClient : mcpClients) {
44+
System.out.println(">>> MCP Client: " + mcpClient.getClientInfo());
5845

59-
CallToolResult response = mcpClient.callTool(toolRequest);
46+
// Call a tool that sends progress notifications
47+
CallToolRequest toolRequest = CallToolRequest.builder()
48+
.name("tool1")
49+
.arguments(Map.of("input", "test input"))
50+
.progressToken("test-progress-token")
51+
.build();
6052

61-
System.out.println("Tool response: " + response);
62-
};
63-
}
64-
65-
@Bean
66-
List<SyncLoggingSpecification> loggingSpecs(McpClientHandlers clientMcpHandlers) {
67-
return SyncMcpAnnotationProviders.loggingSpecifications(List.of(clientMcpHandlers));
68-
}
69-
70-
@Bean
71-
List<SyncSamplingSpecification> samplingSpecs(McpClientHandlers clientMcpHandlers) {
72-
return SyncMcpAnnotationProviders.samplingSpecifications(List.of(clientMcpHandlers));
73-
}
53+
CallToolResult response = mcpClient.callTool(toolRequest);
7454

75-
@Bean
76-
List<SyncElicitationSpecification> elicitationSpecs(McpClientHandlers clientMcpHandlers) {
77-
return SyncMcpAnnotationProviders.elicitationSpecifications(List.of(clientMcpHandlers));
78-
}
79-
80-
@Bean
81-
List<SyncProgressSpecification> progressSpecs(McpClientHandlers clientMcpHandlers) {
82-
return SyncMcpAnnotationProviders.progressSpecifications(List.of(clientMcpHandlers));
83-
}
84-
85-
@Bean
86-
McpSyncClientCustomizer annotationMcpSyncClientCustomizer(List<SyncLoggingSpecification> loggingSpecs,
87-
List<SyncSamplingSpecification> samplingSpecs, List<SyncElicitationSpecification> elicitationSpecs,
88-
List<SyncProgressSpecification> progressSpecs) {
89-
return new AnnotationSyncClientCustomizer(samplingSpecs, loggingSpecs, elicitationSpecs, progressSpecs);
55+
System.out.println("Tool response: " + response);
56+
}
57+
};
9058
}
9159
}
Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,36 @@
1818
import io.modelcontextprotocol.spec.McpSchema.ProgressNotification;
1919

2020
@Service
21-
public class McpClientHandlers {
21+
public class McpClientHandlerProviders {
2222

23-
private static final Logger logger = LoggerFactory.getLogger(McpClientHandlers.class);
23+
private static final Logger logger = LoggerFactory.getLogger(McpClientHandlerProviders.class);
2424

25-
@McpProgress(clientId = "server1")
25+
/**
26+
* Handles progress notifications for the client identified by {@code clientId = "server1"}.
27+
* <br>
28+
* The {@code clientId} is configured via application properties, for example:
29+
* <ul>
30+
* <li>{@code spring.ai.mcp.client.sse.connections.server1.url=...}</li>
31+
* <li>{@code spring.ai.mcp.client.streamable-http.connections.server1.url=...}</li>
32+
* </ul>
33+
*
34+
* The handler is assigned only to the client with ID "server1".
35+
*
36+
* @param progressNotification the progress notification received from the server
37+
*/
38+
@McpProgress(clients = "server1")
2639
public void progressHandler(ProgressNotification progressNotification) {
2740
logger.info("MCP PROGRESS: [{}] progress: {} total: {} message: {}",
2841
progressNotification.progressToken(), progressNotification.progress(),
2942
progressNotification.total(), progressNotification.message());
3043
}
3144

32-
@McpLogging
45+
@McpLogging(clients = "server1")
3346
public void loggingHandler(LoggingMessageNotification loggingMessage) {
3447
logger.info("MCP LOGGING: [{}] {}", loggingMessage.level(), loggingMessage.data());
3548
}
3649

37-
@McpSampling
50+
@McpSampling(clients = "server1")
3851
public CreateMessageResult samplingHandler(CreateMessageRequest llmRequest) {
3952
logger.info("MCP SAMPLING: {}", llmRequest);
4053

@@ -46,7 +59,7 @@ public CreateMessageResult samplingHandler(CreateMessageRequest llmRequest) {
4659
.build();
4760
}
4861

49-
@McpElicitation
62+
@McpElicitation(clients = "server1")
5063
public ElicitResult elicitationHandler(McpSchema.ElicitRequest request) {
5164
logger.info("MCP ELICITATION: {}", request);
5265
return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));

model-context-protocol/mcp-annotations/mcp-annotations-client/src/main/java/org/springframework/ai/mcp/samples/client/customizers/AnnotationSyncClientCustomizer.java

Lines changed: 0 additions & 78 deletions
This file was deleted.
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
spring.application.name=mcp
22
spring.main.web-application-type=none
33

4-
# Disable the chat client auto-configuration because we are using multiple chat models
5-
spring.ai.chat.client.enabled=false
64

7-
spring.ai.openai.api-key=${OPENAI_API_KEY}
8-
spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY}
5+
# spring.ai.mcp.client.sse.connections.server1.url=http://localhost:8080
6+
spring.ai.mcp.client.streamable-http.connections.server1.url=http://localhost:8080
7+
# spring.ai.mcp.client.streamable-http.connections.server2.url=http://localhost:8081
98

10-
spring.ai.mcp.client.sse.connections.server1.url=http://localhost:8080
119
spring.ai.mcp.client.request-timeout=5m
1210

1311
logging.level.io.modelcontextprotocol.client=WARN
1412
logging.level.io.modelcontextprotocol.spec=WARN
1513

1614

17-
spring.ai.mcp.client.toolcallback.enabled=false
15+
# spring.ai.mcp.client.toolcallback.enabled=false

0 commit comments

Comments
 (0)