Skip to content

Commit 331837f

Browse files
authored
Merge branch 'spring-projects:main' into main
2 parents 1b3b12d + 84efb6a commit 331837f

File tree

182 files changed

+9262
-966
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

182 files changed

+9262
-966
lines changed

auto-configurations/common/spring-ai-autoconfigure-retry/src/main/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryProperties.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class SpringAiRetryProperties {
4242
* Exponential Backoff properties.
4343
*/
4444
@NestedConfigurationProperty
45-
private Backoff backoff = new Backoff();
45+
private final Backoff backoff = new Backoff();
4646

4747
/**
4848
* If false, throw a NonTransientAiException, and do not attempt retry for 4xx client

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.modelcontextprotocol.client.McpSyncClient;
2323

2424
import org.springframework.ai.mcp.AsyncMcpToolCallbackProvider;
25+
import org.springframework.ai.mcp.DefaultMcpToolNamePrefixGenerator;
2526
import org.springframework.ai.mcp.McpToolFilter;
2627
import org.springframework.ai.mcp.McpToolNamePrefixGenerator;
2728
import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
@@ -30,18 +31,28 @@
3031
import org.springframework.beans.factory.ObjectProvider;
3132
import org.springframework.boot.autoconfigure.AutoConfiguration;
3233
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
34+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3335
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3436
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3537
import org.springframework.context.annotation.Bean;
3638
import org.springframework.context.annotation.Conditional;
3739

3840
/**
41+
* Responsible to convert MCP (sync and async) clients into Spring AI
42+
* ToolCallbacksProviders. These providers are used by Spring AI to discover and execute
43+
* tools.
3944
*/
4045
@AutoConfiguration(after = { McpClientAutoConfiguration.class })
4146
@EnableConfigurationProperties(McpClientCommonProperties.class)
4247
@Conditional(McpToolCallbackAutoConfiguration.McpToolCallbackAutoConfigurationCondition.class)
4348
public class McpToolCallbackAutoConfiguration {
4449

50+
@Bean
51+
@ConditionalOnMissingBean
52+
public McpToolNamePrefixGenerator defaultMcpToolNamePrefixGenerator() {
53+
return new DefaultMcpToolNamePrefixGenerator();
54+
}
55+
4556
/**
4657
* Creates tool callbacks for all configured MCP clients.
4758
*
@@ -61,12 +72,14 @@ public SyncMcpToolCallbackProvider mcpToolCallbacks(ObjectProvider<McpToolFilter
6172
ObjectProvider<List<McpSyncClient>> syncMcpClients,
6273
ObjectProvider<McpToolNamePrefixGenerator> mcpToolNamePrefixGenerator,
6374
ObjectProvider<ToolContextToMcpMetaConverter> toolContextToMcpMetaConverter) {
75+
6476
List<McpSyncClient> mcpClients = syncMcpClients.stream().flatMap(List::stream).toList();
77+
6578
return SyncMcpToolCallbackProvider.builder()
6679
.mcpClients(mcpClients)
6780
.toolFilter(syncClientsToolFilter.getIfUnique((() -> (McpSyncClient, tool) -> true)))
6881
.toolNamePrefixGenerator(
69-
mcpToolNamePrefixGenerator.getIfUnique(() -> McpToolNamePrefixGenerator.defaultGenerator()))
82+
mcpToolNamePrefixGenerator.getIfUnique(() -> McpToolNamePrefixGenerator.noPrefix()))
7083
.toolContextToMcpMetaConverter(
7184
toolContextToMcpMetaConverter.getIfUnique(() -> ToolContextToMcpMetaConverter.defaultConverter()))
7285
.build();
@@ -81,8 +94,7 @@ public AsyncMcpToolCallbackProvider mcpAsyncToolCallbacks(ObjectProvider<McpTool
8194
List<McpAsyncClient> mcpClients = mcpClientsProvider.stream().flatMap(List::stream).toList();
8295
return AsyncMcpToolCallbackProvider.builder()
8396
.toolFilter(asyncClientsToolFilter.getIfUnique(() -> (McpAsyncClient, tool) -> true))
84-
.toolNamePrefixGenerator(
85-
toolNamePrefixGenerator.getIfUnique(() -> McpToolNamePrefixGenerator.defaultGenerator()))
97+
.toolNamePrefixGenerator(toolNamePrefixGenerator.getIfUnique(() -> McpToolNamePrefixGenerator.noPrefix()))
8698
.toolContextToMcpMetaConverter(
8799
toolContextToMcpMetaConverter.getIfUnique(() -> ToolContextToMcpMetaConverter.defaultConverter()))
88100
.mcpClients(mcpClients)

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,30 @@
2424
import org.springaicommunity.mcp.annotation.McpProgress;
2525
import org.springaicommunity.mcp.annotation.McpSampling;
2626

27+
import org.springframework.ai.mcp.annotation.spring.scan.AbstractAnnotatedMethodBeanFactoryInitializationAotProcessor;
2728
import org.springframework.ai.mcp.annotation.spring.scan.AbstractAnnotatedMethodBeanPostProcessor;
2829
import org.springframework.ai.mcp.annotation.spring.scan.AbstractMcpAnnotatedBeans;
30+
import org.springframework.aot.hint.MemberCategory;
31+
import org.springframework.aot.hint.RuntimeHints;
32+
import org.springframework.aot.hint.RuntimeHintsRegistrar;
2933
import org.springframework.boot.autoconfigure.AutoConfiguration;
3034
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3135
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3236
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3337
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3438
import org.springframework.context.annotation.Bean;
39+
import org.springframework.context.annotation.ImportRuntimeHints;
3540

3641
/**
3742
* @author Christian Tzolov
43+
* @author Josh Long
3844
*/
3945
@AutoConfiguration
4046
@ConditionalOnClass(McpLogging.class)
4147
@ConditionalOnProperty(prefix = McpClientAnnotationScannerProperties.CONFIG_PREFIX, name = "enabled",
4248
havingValue = "true", matchIfMissing = true)
4349
@EnableConfigurationProperties(McpClientAnnotationScannerProperties.class)
50+
@ImportRuntimeHints(McpClientAnnotationScannerAutoConfiguration.AnnotationHints.class)
4451
public class McpClientAnnotationScannerAutoConfiguration {
4552

4653
private static final Set<Class<? extends Annotation>> CLIENT_MCP_ANNOTATIONS = Set.of(McpLogging.class,
@@ -54,15 +61,30 @@ public ClientMcpAnnotatedBeans clientAnnotatedBeans() {
5461

5562
@Bean
5663
@ConditionalOnMissingBean
57-
public ClientAnnotatedMethodBeanPostProcessor clientAnnotatedMethodBeanPostProcessor(
64+
public static ClientAnnotatedMethodBeanPostProcessor clientAnnotatedMethodBeanPostProcessor(
5865
ClientMcpAnnotatedBeans clientMcpAnnotatedBeans, McpClientAnnotationScannerProperties properties) {
5966
return new ClientAnnotatedMethodBeanPostProcessor(clientMcpAnnotatedBeans, CLIENT_MCP_ANNOTATIONS);
6067
}
6168

69+
@Bean
70+
static ClientAnnotatedBeanFactoryInitializationAotProcessor clientAnnotatedBeanFactoryInitializationAotProcessor() {
71+
return new ClientAnnotatedBeanFactoryInitializationAotProcessor(CLIENT_MCP_ANNOTATIONS);
72+
}
73+
6274
public static class ClientMcpAnnotatedBeans extends AbstractMcpAnnotatedBeans {
6375

6476
}
6577

78+
public static class ClientAnnotatedBeanFactoryInitializationAotProcessor
79+
extends AbstractAnnotatedMethodBeanFactoryInitializationAotProcessor {
80+
81+
public ClientAnnotatedBeanFactoryInitializationAotProcessor(
82+
Set<Class<? extends Annotation>> targetAnnotations) {
83+
super(targetAnnotations);
84+
}
85+
86+
}
87+
6688
public static class ClientAnnotatedMethodBeanPostProcessor extends AbstractAnnotatedMethodBeanPostProcessor {
6789

6890
public ClientAnnotatedMethodBeanPostProcessor(ClientMcpAnnotatedBeans clientMcpAnnotatedBeans,
@@ -72,4 +94,13 @@ public ClientAnnotatedMethodBeanPostProcessor(ClientMcpAnnotatedBeans clientMcpA
7294

7395
}
7496

97+
static class AnnotationHints implements RuntimeHintsRegistrar {
98+
99+
@Override
100+
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
101+
CLIENT_MCP_ANNOTATIONS.forEach(an -> hints.reflection().registerType(an, MemberCategory.values()));
102+
}
103+
104+
}
105+
75106
}

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient/src/test/java/org/springframework/ai/mcp/client/autoconfigure/SseHttpClientTransportAutoConfigurationIT.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,6 @@ void streamableHttpTest() {
9494

9595
mcpClient.ping();
9696

97-
System.out.println("mcpClient = " + mcpClient.getServerInfo());
98-
9997
ListToolsResult toolsResult = mcpClient.listTools();
10098

10199
assertThat(toolsResult).isNotNull();

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient/src/test/java/org/springframework/ai/mcp/client/autoconfigure/StreamableHttpHttpClientTransportAutoConfigurationIT.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ void streamableHttpTest() {
9595

9696
mcpClient.ping();
9797

98-
System.out.println("mcpClient = " + mcpClient.getServerInfo());
99-
10098
ListToolsResult toolsResult = mcpClient.listTools();
10199

102100
assertThat(toolsResult).isNotNull();

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux/src/test/java/org/springframework/ai/mcp/client/webflux/autoconfigure/SseWebFluxTransportAutoConfigurationIT.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ void streamableHttpTest() {
8181

8282
mcpClient.ping();
8383

84-
System.out.println("mcpClient = " + mcpClient.getServerInfo());
85-
8684
ListToolsResult toolsResult = mcpClient.listTools();
8785

8886
assertThat(toolsResult).isNotNull();

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux/src/test/java/org/springframework/ai/mcp/client/webflux/autoconfigure/StreamableHttpHttpClientTransportAutoConfigurationIT.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@ void streamableHttpTest() {
8282

8383
mcpClient.ping();
8484

85-
System.out.println("mcpClient = " + mcpClient.getServerInfo());
86-
8785
ListToolsResult toolsResult = mcpClient.listTools();
8886

8987
assertThat(toolsResult).isNotNull();

auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfiguration.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,13 @@
7373
* @since 1.0.0
7474
* @see McpServerProperties
7575
*/
76-
@AutoConfiguration(
77-
afterName = { "org.springframework.ai.mcp.server.common.autoconfigure.ToolCallbackConverterAutoConfiguration",
78-
"org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebFluxAutoConfiguration",
79-
"org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebMvcAutoConfiguration",
80-
"org.springframework.ai.mcp.server.autoconfigure.McpServerStreamableHttpWebMvcAutoConfiguration",
81-
"org.springframework.ai.mcp.server.autoconfigure.McpServerStreamableHttpWebFluxAutoConfiguration" })
76+
@AutoConfiguration(afterName = {
77+
"org.springframework.ai.mcp.server.common.autoconfigure.annotations.McpServerSpecificationFactoryAutoConfiguration",
78+
"org.springframework.ai.mcp.server.common.autoconfigure.ToolCallbackConverterAutoConfiguration",
79+
"org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebFluxAutoConfiguration",
80+
"org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebMvcAutoConfiguration",
81+
"org.springframework.ai.mcp.server.autoconfigure.McpServerStreamableHttpWebMvcAutoConfiguration",
82+
"org.springframework.ai.mcp.server.autoconfigure.McpServerStreamableHttpWebFluxAutoConfiguration" })
8283
@ConditionalOnClass({ McpSchema.class })
8384
@EnableConfigurationProperties({ McpServerProperties.class, McpServerChangeNotificationProperties.class })
8485
@ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",

auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerStatelessAutoConfiguration.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
* @author Christian Tzolov
5656
*/
5757
@AutoConfiguration(afterName = {
58+
"org.springframework.ai.mcp.server.common.autoconfigure.annotations.StatelessServerSpecificationFactoryAutoConfiguration",
5859
"org.springframework.ai.mcp.server.common.autoconfigure.StatelessToolCallbackConverterAutoConfiguration",
5960
"org.springframework.ai.mcp.server.autoconfigure.McpServerStatelessWebFluxAutoConfiguration",
6061
"org.springframework.ai.mcp.server.autoconfigure.McpServerStatelessWebMvcAutoConfiguration" })

auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/annotations/McpServerAnnotationScannerAutoConfiguration.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,30 @@
2424
import org.springaicommunity.mcp.annotation.McpResource;
2525
import org.springaicommunity.mcp.annotation.McpTool;
2626

27+
import org.springframework.ai.mcp.annotation.spring.scan.AbstractAnnotatedMethodBeanFactoryInitializationAotProcessor;
2728
import org.springframework.ai.mcp.annotation.spring.scan.AbstractAnnotatedMethodBeanPostProcessor;
2829
import org.springframework.ai.mcp.annotation.spring.scan.AbstractMcpAnnotatedBeans;
30+
import org.springframework.aot.hint.MemberCategory;
31+
import org.springframework.aot.hint.RuntimeHints;
32+
import org.springframework.aot.hint.RuntimeHintsRegistrar;
2933
import org.springframework.boot.autoconfigure.AutoConfiguration;
3034
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
3135
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3236
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3337
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3438
import org.springframework.context.annotation.Bean;
39+
import org.springframework.context.annotation.ImportRuntimeHints;
3540

3641
/**
3742
* @author Christian Tzolov
43+
* @author Josh Long
3844
*/
3945
@AutoConfiguration
4046
@ConditionalOnClass(McpTool.class)
4147
@ConditionalOnProperty(prefix = McpServerAnnotationScannerProperties.CONFIG_PREFIX, name = "enabled",
4248
havingValue = "true", matchIfMissing = true)
4349
@EnableConfigurationProperties(McpServerAnnotationScannerProperties.class)
50+
@ImportRuntimeHints(McpServerAnnotationScannerAutoConfiguration.AnnotationHints.class)
4451
public class McpServerAnnotationScannerAutoConfiguration {
4552

4653
private static final Set<Class<? extends Annotation>> SERVER_MCP_ANNOTATIONS = Set.of(McpTool.class,
@@ -54,15 +61,30 @@ public ServerMcpAnnotatedBeans serverAnnotatedBeanRegistry() {
5461

5562
@Bean
5663
@ConditionalOnMissingBean
57-
public ServerAnnotatedMethodBeanPostProcessor serverAnnotatedMethodBeanPostProcessor(
64+
public static ServerAnnotatedMethodBeanPostProcessor serverAnnotatedMethodBeanPostProcessor(
5865
ServerMcpAnnotatedBeans serverMcpAnnotatedBeans, McpServerAnnotationScannerProperties properties) {
5966
return new ServerAnnotatedMethodBeanPostProcessor(serverMcpAnnotatedBeans, SERVER_MCP_ANNOTATIONS);
6067
}
6168

69+
@Bean
70+
public static ServerAnnotatedBeanFactoryInitializationAotProcessor serverAnnotatedBeanFactoryInitializationAotProcessor() {
71+
return new ServerAnnotatedBeanFactoryInitializationAotProcessor(SERVER_MCP_ANNOTATIONS);
72+
}
73+
6274
public static class ServerMcpAnnotatedBeans extends AbstractMcpAnnotatedBeans {
6375

6476
}
6577

78+
public static class ServerAnnotatedBeanFactoryInitializationAotProcessor
79+
extends AbstractAnnotatedMethodBeanFactoryInitializationAotProcessor {
80+
81+
public ServerAnnotatedBeanFactoryInitializationAotProcessor(
82+
Set<Class<? extends Annotation>> targetAnnotations) {
83+
super(targetAnnotations);
84+
}
85+
86+
}
87+
6688
public static class ServerAnnotatedMethodBeanPostProcessor extends AbstractAnnotatedMethodBeanPostProcessor {
6789

6890
public ServerAnnotatedMethodBeanPostProcessor(ServerMcpAnnotatedBeans serverMcpAnnotatedBeans,
@@ -72,4 +94,13 @@ public ServerAnnotatedMethodBeanPostProcessor(ServerMcpAnnotatedBeans serverMcpA
7294

7395
}
7496

97+
static class AnnotationHints implements RuntimeHintsRegistrar {
98+
99+
@Override
100+
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
101+
SERVER_MCP_ANNOTATIONS.forEach(an -> hints.reflection().registerType(an, MemberCategory.values()));
102+
}
103+
104+
}
105+
75106
}

0 commit comments

Comments
 (0)