Skip to content

Commit ab2067d

Browse files
committed
McpClientAutoConfiguration: make handlers registry optional
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
1 parent d26637b commit ab2067d

File tree

2 files changed

+63
-43
lines changed

2 files changed

+63
-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: 45 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,28 @@ 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 -> {
178+
spec.sampling(samplingRequest -> registry.handleSampling(namedTransport.name(), samplingRequest))
179+
.elicitation(elicitationRequest -> registry.handleElicitation(namedTransport.name(),
180+
elicitationRequest))
181+
.loggingConsumer(loggingMessageNotification -> registry.handleLogging(namedTransport.name(),
182+
loggingMessageNotification))
183+
.progressConsumer(progressNotification -> registry.handleProgress(namedTransport.name(),
184+
progressNotification))
185+
.toolsChangeConsumer(
186+
newTools -> registry.handleToolListChanged(namedTransport.name(), newTools))
187+
.promptsChangeConsumer(
188+
newPrompts -> registry.handlePromptListChanged(namedTransport.name(), newPrompts))
189+
.resourcesChangeConsumer(
190+
newResources -> registry.handleResourceListChanged(namedTransport.name(), newResources))
191+
.capabilities(registry.getCapabilities(namedTransport.name()));
192+
});
193+
194+
McpClient.SyncSpec customizedSpec = mcpSyncClientConfigurer.configure(namedTransport.name(), spec);
195+
196+
var client = customizedSpec.build();
195197

196198
if (commonProperties.isInitialized()) {
197199
client.initialize();
@@ -247,7 +249,7 @@ public McpAsyncToolsChangeEventEmmiter mcpAsyncToolChangeEventEmmiter(
247249
public List<McpAsyncClient> mcpAsyncClients(McpAsyncClientConfigurer mcpAsyncClientConfigurer,
248250
McpClientCommonProperties commonProperties,
249251
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider,
250-
ClientMcpAsyncHandlersRegistry clientMcpAsyncHandlersRegistry) {
252+
ObjectProvider<ClientMcpAsyncHandlersRegistry> clientMcpAsyncHandlersRegistry) {
251253

252254
List<McpAsyncClient> mcpAsyncClients = new ArrayList<>();
253255

@@ -259,29 +261,29 @@ public List<McpAsyncClient> mcpAsyncClients(McpAsyncClientConfigurer mcpAsyncCli
259261
McpSchema.Implementation clientInfo = new McpSchema.Implementation(
260262
this.connectedClientName(commonProperties.getName(), namedTransport.name()),
261263
commonProperties.getVersion());
262-
263264
McpClient.AsyncSpec spec = McpClient.async(namedTransport.transport())
264265
.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();
266+
.requestTimeout(commonProperties.getRequestTimeout());
267+
clientMcpAsyncHandlersRegistry.ifAvailable(registry -> {
268+
spec.sampling(samplingRequest -> registry.handleSampling(namedTransport.name(), samplingRequest))
269+
.elicitation(elicitationRequest -> registry.handleElicitation(namedTransport.name(),
270+
elicitationRequest))
271+
.loggingConsumer(loggingMessageNotification -> registry.handleLogging(namedTransport.name(),
272+
loggingMessageNotification))
273+
.progressConsumer(progressNotification -> registry.handleProgress(namedTransport.name(),
274+
progressNotification))
275+
.toolsChangeConsumer(
276+
newTools -> registry.handleToolListChanged(namedTransport.name(), newTools))
277+
.promptsChangeConsumer(
278+
newPrompts -> registry.handlePromptListChanged(namedTransport.name(), newPrompts))
279+
.resourcesChangeConsumer(
280+
newResources -> registry.handleResourceListChanged(namedTransport.name(), newResources))
281+
.capabilities(registry.getCapabilities(namedTransport.name()));
282+
});
283+
284+
McpClient.AsyncSpec customizedSpec = mcpAsyncClientConfigurer.configure(namedTransport.name(), spec);
285+
286+
var client = customizedSpec.build();
285287

286288
if (commonProperties.isInitialized()) {
287289
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)