Skip to content

Commit 1eb0244

Browse files
authored
ClientMcp*HandlersRegistry: support beans with unresolvable types (#4918)
- Fixes gh-4917 Signed-off-by: Daniel Garnier-Moiroux <[email protected]>
1 parent d26637b commit 1eb0244

File tree

3 files changed

+30
-1
lines changed

3 files changed

+30
-1
lines changed

mcp/mcp-annotations-spring/src/main/java/org/springframework/ai/mcp/annotation/spring/AbstractClientMcpHandlerRegistry.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,14 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
7474
// Only process singleton beans, not scoped beans
7575
continue;
7676
}
77-
var foundAnnotations = this.scan(AutoProxyUtils.determineTargetClass(beanFactory, beanName));
77+
Class<?> beanClass = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
78+
if (beanClass == null) {
79+
// If we cannot determine the bean class, we cannot scan it before
80+
// it is really resolved. This is very likely an infrastructure-level
81+
// bean, not a "service" type, skip it entirely.
82+
continue;
83+
}
84+
var foundAnnotations = this.scan(beanClass);
7885
if (!foundAnnotations.isEmpty()) {
7986
this.allAnnotatedBeans.add(beanName);
8087
}

mcp/mcp-annotations-spring/src/test/java/org/springframework/ai/mcp/annotation/spring/ClientMcpAsyncHandlersRegistryTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
3939

4040
import static org.assertj.core.api.Assertions.assertThat;
41+
import static org.assertj.core.api.Assertions.assertThatNoException;
4142
import static org.assertj.core.api.Assertions.assertThatThrownBy;
4243
import static org.assertj.core.api.InstanceOfAssertFactories.type;
4344

@@ -340,6 +341,16 @@ void supportsProxiedClass() {
340341
assertThat(registry.getCapabilities("client-1").elicitation()).isNotNull();
341342
}
342343

344+
@Test
345+
void skipsUnknownBeanClass() {
346+
var registry = new ClientMcpAsyncHandlersRegistry();
347+
var beanFactory = new DefaultListableBeanFactory();
348+
beanFactory.registerBeanDefinition("myConfig",
349+
BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition());
350+
351+
assertThatNoException().isThrownBy(() -> registry.postProcessBeanFactory(beanFactory));
352+
}
353+
343354
static class ClientCapabilitiesConfiguration {
344355

345356
@McpElicitation(clients = { "client-1", "client-2" })

mcp/mcp-annotations-spring/src/test/java/org/springframework/ai/mcp/annotation/spring/ClientMcpSyncHandlersRegistryTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
3838

3939
import static org.assertj.core.api.Assertions.assertThat;
40+
import static org.assertj.core.api.Assertions.assertThatNoException;
4041
import static org.assertj.core.api.Assertions.assertThatThrownBy;
4142
import static org.assertj.core.api.InstanceOfAssertFactories.type;
4243

@@ -332,6 +333,16 @@ void supportsProxiedClass() {
332333
assertThat(registry.getCapabilities("client-1").elicitation()).isNotNull();
333334
}
334335

336+
@Test
337+
void skipsUnknownBeanClass() {
338+
var registry = new ClientMcpAsyncHandlersRegistry();
339+
var beanFactory = new DefaultListableBeanFactory();
340+
beanFactory.registerBeanDefinition("myConfig",
341+
BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition());
342+
343+
assertThatNoException().isThrownBy(() -> registry.postProcessBeanFactory(beanFactory));
344+
}
345+
335346
static class ClientCapabilitiesConfiguration {
336347

337348
@McpElicitation(clients = { "client-1", "client-2" })

0 commit comments

Comments
 (0)