Skip to content

Commit d5a3269

Browse files
authored
McpClientAutoConfiguration: make handlers registry optional (#4920)
Signed-off-by: Daniel Garnier-Moiroux <[email protected]>
1 parent 1eb0244 commit d5a3269

File tree

2 files changed

+59
-43
lines changed

2 files changed

+59
-43
lines changed

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-common/src/main/java/org/springframework/ai/mcp/client/common/autoconfigure/McpClientAutoConfiguration.java

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public McpSyncToolsChangeEventEmmiter mcpSyncToolChangeEventEmmiter(
157157
public List<McpSyncClient> mcpSyncClients(McpSyncClientConfigurer mcpSyncClientConfigurer,
158158
McpClientCommonProperties commonProperties,
159159
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider,
160-
ClientMcpSyncHandlersRegistry clientMcpSyncHandlersRegistry) {
160+
ObjectProvider<ClientMcpSyncHandlersRegistry> clientMcpSyncHandlersRegistry) {
161161

162162
List<McpSyncClient> mcpSyncClients = new ArrayList<>();
163163

@@ -172,26 +172,26 @@ public List<McpSyncClient> mcpSyncClients(McpSyncClientConfigurer mcpSyncClientC
172172

173173
McpClient.SyncSpec spec = McpClient.sync(namedTransport.transport())
174174
.clientInfo(clientInfo)
175-
.requestTimeout(commonProperties.getRequestTimeout())
176-
.sampling(samplingRequest -> clientMcpSyncHandlersRegistry.handleSampling(namedTransport.name(),
177-
samplingRequest))
178-
.elicitation(elicitationRequest -> clientMcpSyncHandlersRegistry
179-
.handleElicitation(namedTransport.name(), elicitationRequest))
180-
.loggingConsumer(loggingMessageNotification -> clientMcpSyncHandlersRegistry
181-
.handleLogging(namedTransport.name(), loggingMessageNotification))
182-
.progressConsumer(progressNotification -> clientMcpSyncHandlersRegistry
183-
.handleProgress(namedTransport.name(), progressNotification))
184-
.toolsChangeConsumer(newTools -> clientMcpSyncHandlersRegistry
185-
.handleToolListChanged(namedTransport.name(), newTools))
186-
.promptsChangeConsumer(newPrompts -> clientMcpSyncHandlersRegistry
187-
.handlePromptListChanged(namedTransport.name(), newPrompts))
188-
.resourcesChangeConsumer(newResources -> clientMcpSyncHandlersRegistry
189-
.handleResourceListChanged(namedTransport.name(), newResources))
190-
.capabilities(clientMcpSyncHandlersRegistry.getCapabilities(namedTransport.name()));
191-
192-
spec = mcpSyncClientConfigurer.configure(namedTransport.name(), spec);
193-
194-
var client = spec.build();
175+
.requestTimeout(commonProperties.getRequestTimeout());
176+
177+
clientMcpSyncHandlersRegistry.ifAvailable(registry -> spec
178+
.sampling(samplingRequest -> registry.handleSampling(namedTransport.name(), samplingRequest))
179+
.elicitation(
180+
elicitationRequest -> registry.handleElicitation(namedTransport.name(), elicitationRequest))
181+
.loggingConsumer(loggingMessageNotification -> registry.handleLogging(namedTransport.name(),
182+
loggingMessageNotification))
183+
.progressConsumer(progressNotification -> registry.handleProgress(namedTransport.name(),
184+
progressNotification))
185+
.toolsChangeConsumer(newTools -> registry.handleToolListChanged(namedTransport.name(), newTools))
186+
.promptsChangeConsumer(
187+
newPrompts -> registry.handlePromptListChanged(namedTransport.name(), newPrompts))
188+
.resourcesChangeConsumer(
189+
newResources -> registry.handleResourceListChanged(namedTransport.name(), newResources))
190+
.capabilities(registry.getCapabilities(namedTransport.name())));
191+
192+
McpClient.SyncSpec customizedSpec = mcpSyncClientConfigurer.configure(namedTransport.name(), spec);
193+
194+
var client = customizedSpec.build();
195195

196196
if (commonProperties.isInitialized()) {
197197
client.initialize();
@@ -247,7 +247,7 @@ public McpAsyncToolsChangeEventEmmiter mcpAsyncToolChangeEventEmmiter(
247247
public List<McpAsyncClient> mcpAsyncClients(McpAsyncClientConfigurer mcpAsyncClientConfigurer,
248248
McpClientCommonProperties commonProperties,
249249
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider,
250-
ClientMcpAsyncHandlersRegistry clientMcpAsyncHandlersRegistry) {
250+
ObjectProvider<ClientMcpAsyncHandlersRegistry> clientMcpAsyncHandlersRegistry) {
251251

252252
List<McpAsyncClient> mcpAsyncClients = new ArrayList<>();
253253

@@ -259,29 +259,27 @@ public List<McpAsyncClient> mcpAsyncClients(McpAsyncClientConfigurer mcpAsyncCli
259259
McpSchema.Implementation clientInfo = new McpSchema.Implementation(
260260
this.connectedClientName(commonProperties.getName(), namedTransport.name()),
261261
commonProperties.getVersion());
262-
263262
McpClient.AsyncSpec spec = McpClient.async(namedTransport.transport())
264263
.clientInfo(clientInfo)
265-
.requestTimeout(commonProperties.getRequestTimeout())
266-
.sampling(samplingRequest -> clientMcpAsyncHandlersRegistry.handleSampling(namedTransport.name(),
267-
samplingRequest))
268-
.elicitation(elicitationRequest -> clientMcpAsyncHandlersRegistry
269-
.handleElicitation(namedTransport.name(), elicitationRequest))
270-
.loggingConsumer(loggingMessageNotification -> clientMcpAsyncHandlersRegistry
271-
.handleLogging(namedTransport.name(), loggingMessageNotification))
272-
.progressConsumer(progressNotification -> clientMcpAsyncHandlersRegistry
273-
.handleProgress(namedTransport.name(), progressNotification))
274-
.toolsChangeConsumer(newTools -> clientMcpAsyncHandlersRegistry
275-
.handleToolListChanged(namedTransport.name(), newTools))
276-
.promptsChangeConsumer(newPrompts -> clientMcpAsyncHandlersRegistry
277-
.handlePromptListChanged(namedTransport.name(), newPrompts))
278-
.resourcesChangeConsumer(newResources -> clientMcpAsyncHandlersRegistry
279-
.handleResourceListChanged(namedTransport.name(), newResources))
280-
.capabilities(clientMcpAsyncHandlersRegistry.getCapabilities(namedTransport.name()));
281-
282-
spec = mcpAsyncClientConfigurer.configure(namedTransport.name(), spec);
283-
284-
var client = spec.build();
264+
.requestTimeout(commonProperties.getRequestTimeout());
265+
clientMcpAsyncHandlersRegistry.ifAvailable(registry -> spec
266+
.sampling(samplingRequest -> registry.handleSampling(namedTransport.name(), samplingRequest))
267+
.elicitation(
268+
elicitationRequest -> registry.handleElicitation(namedTransport.name(), elicitationRequest))
269+
.loggingConsumer(loggingMessageNotification -> registry.handleLogging(namedTransport.name(),
270+
loggingMessageNotification))
271+
.progressConsumer(progressNotification -> registry.handleProgress(namedTransport.name(),
272+
progressNotification))
273+
.toolsChangeConsumer(newTools -> registry.handleToolListChanged(namedTransport.name(), newTools))
274+
.promptsChangeConsumer(
275+
newPrompts -> registry.handlePromptListChanged(namedTransport.name(), newPrompts))
276+
.resourcesChangeConsumer(
277+
newResources -> registry.handleResourceListChanged(namedTransport.name(), newResources))
278+
.capabilities(registry.getCapabilities(namedTransport.name())));
279+
280+
McpClient.AsyncSpec customizedSpec = mcpAsyncClientConfigurer.configure(namedTransport.name(), spec);
281+
282+
var client = customizedSpec.build();
285283

286284
if (commonProperties.isInitialized()) {
287285
client.initialize().block();

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-common/src/test/java/org/springframework/ai/mcp/client/common/autoconfigure/McpClientAutoConfigurationIT.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,24 @@ void toolCallbacksCreation() {
209209
});
210210
}
211211

212+
@Test
213+
void missingAnnotationScanner() {
214+
this.contextRunner.withPropertyValues("spring.ai.mcp.client.annotation-scanner.enabled=false").run(context -> {
215+
assertThat(context).hasBean("mcpSyncClients");
216+
List<?> clients = context.getBean("mcpSyncClients", List.class);
217+
assertThat(clients).isNotNull();
218+
});
219+
220+
this.contextRunner
221+
.withPropertyValues("spring.ai.mcp.client.annotation-scanner.enabled=false",
222+
"spring.ai.mcp.client.type=ASYNC")
223+
.run(context -> {
224+
assertThat(context).hasBean("mcpAsyncClients");
225+
List<?> clients = context.getBean("mcpAsyncClients", List.class);
226+
assertThat(clients).isNotNull();
227+
});
228+
}
229+
212230
/**
213231
* Tests that closeable wrapper beans are created properly.
214232
*

0 commit comments

Comments
 (0)