From f4b90881fab14474ecf84de51745febdd7018687 Mon Sep 17 00:00:00 2001 From: Christian Tzolov Date: Thu, 21 Aug 2025 11:37:29 +0200 Subject: [PATCH 1/2] refactor(mcp): consolidate MCP server auto-configuration modules and introduce protocol-based configuration - Consolidate multiple MCP server modules into unified webmvc/webflux modules - Move properties classes from separate module into mcp-server-common - Merge stateless auto-configuration into common module - Replace transport-specific modules with protocol-based configuration - Add ServerProtocol enum (SSE, STREAMABLE, STATELESS) for protocol selection - Rename ServerType to ApiType for clarity - Update conditional configuration to use protocol-based conditions - Remove separate streamable/stateless starter modules - Update documentation to reflect unified protocol-based approach - Simplify module structure while maintaining backward compatibility through configuration This refactoring reduces complexity by consolidating 7+ modules into 3 main modules (common, webmvc, webflux) while providing the same functionality through the spring.ai.mcp.server.protocol configuration property. Signed-off-by: Christian Tzolov Co-authored-by: yinh --- .../pom.xml | 6 - .../McpServerAutoConfiguration.java | 65 +++- .../McpServerStatelessAutoConfiguration.java | 37 ++- ...olCallbackConverterAutoConfiguration.java} | 8 +- ...oolCallbackConverterAutoConfiguration.java | 4 +- ...McpServerChangeNotificationProperties.java | 0 .../properties/McpServerProperties.java | 27 +- .../properties}/McpServerSseProperties.java | 2 +- .../McpServerStreamableHttpProperties.java | 0 ...ot.autoconfigure.AutoConfiguration.imports | 2 + .../McpServerAutoConfigurationIT.java | 4 +- ...McpStatelessServerAutoConfigurationIT.java | 10 +- ...lCallbackConverterAutoConfigurationIT.java | 302 ++++++++++++++++++ ...lCallbackConverterAutoConfigurationIT.java | 6 +- .../pom.xml | 74 ----- .../pom.xml | 74 ----- .../pom.xml | 100 ------ ...ot.autoconfigure.AutoConfiguration.imports | 17 - .../pom.xml | 74 ----- ...ot.autoconfigure.AutoConfiguration.imports | 16 - .../pom.xml | 100 ------ ...ot.autoconfigure.AutoConfiguration.imports | 17 - ...ot.autoconfigure.AutoConfiguration.imports | 17 - .../pom.xml | 12 +- .../McpServerSseWebFluxAutoConfiguration.java | 5 +- ...rverStatelessWebFluxAutoConfiguration.java | 8 +- ...treamableHttpWebFluxAutoConfiguration.java | 8 +- ...ot.autoconfigure.AutoConfiguration.imports | 6 +- ...pServerSseWebFluxAutoConfigurationIT.java} | 3 +- ...rverSseWebFluxAutoConfigurationTests.java} | 2 +- ...rStatelessWebFluxAutoConfigurationIT.java} | 5 +- ...StreamableWebFluxAutoConfigurationIT.java} | 5 +- .../SseWebClientWebFluxServerIT.java} | 4 +- .../StatelessWebClientWebFluxServerIT.java} | 12 +- .../StreamableWebClientWebFluxServerIT.java} | 7 +- .../pom.xml | 9 +- .../McpServerSseWebMvcAutoConfiguration.java | 4 +- ...erverStatelessWebMvcAutoConfiguration.java | 8 +- ...StreamableHttpWebMvcAutoConfiguration.java | 8 +- ...ot.autoconfigure.AutoConfiguration.imports | 3 +- ...cpServerSseWebMvcAutoConfigurationIT.java} | 3 +- ...erStatelessWebMvcAutoConfigurationIT.java} | 5 +- ...rStreamableWebMvcAutoConfigurationIT.java} | 5 +- pom.xml | 14 +- spring-ai-bom/pom.xml | 60 +--- .../api/mcp/mcp-server-boot-starter-docs.adoc | 57 ++-- ...cp-stateless-server-boot-starter-docs.adoc | 20 +- ...eamable-http-server-boot-starter-docs.adoc | 21 +- .../pom.xml | 72 ----- .../pom.xml | 66 ---- .../pom.xml | 72 ----- .../pom.xml | 66 ---- .../pom.xml | 2 +- .../pom.xml | 2 +- 54 files changed, 568 insertions(+), 968 deletions(-) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-stateless-common/src/main/java/org/springframework/ai/mcp/server/stateless => spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common}/autoconfigure/McpServerStatelessAutoConfiguration.java (87%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-stateless-common/src/main/java/org/springframework/ai/mcp/server/stateless/autoconfigure/ToolCallbackConverterAutoConfiguration.java => spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/StatelessToolCallbackConverterAutoConfiguration.java} (94%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-properties => spring-ai-autoconfigure-mcp-server-common}/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerChangeNotificationProperties.java (100%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-properties => spring-ai-autoconfigure-mcp-server-common}/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerProperties.java (91%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-sse/src/main/java/org/springframework/ai/mcp/server/autoconfigure => spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties}/McpServerSseProperties.java (96%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-properties => spring-ai-autoconfigure-mcp-server-common}/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerStreamableHttpProperties.java (100%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-stateless-common/src/test/java/org/springframework/ai/mcp/server/stateless => spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common}/autoconfigure/McpStatelessServerAutoConfigurationIT.java (98%) create mode 100644 auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/StatelessToolCallbackConverterAutoConfigurationIT.java rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-stateless-common/src/test/java/org/springframework/ai/mcp/server/stateless => spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common}/autoconfigure/ToolCallbackConverterAutoConfigurationIT.java (98%) delete mode 100644 auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/pom.xml delete mode 100644 auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/pom.xml delete mode 100644 auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/pom.xml delete mode 100644 auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports delete mode 100644 auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/pom.xml delete mode 100644 auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports delete mode 100644 auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/pom.xml delete mode 100644 auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports delete mode 100644 auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-sse => spring-ai-autoconfigure-mcp-server-webflux}/pom.xml (88%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-sse => spring-ai-autoconfigure-mcp-server-webflux}/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfiguration.java (93%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-stateless-webflux/src/main/java/org/springframework/ai/mcp/server/stateless/webflux => spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server}/autoconfigure/McpServerStatelessWebFluxAutoConfiguration.java (84%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-streamable-webflux/src/main/java/org/springframework/ai/mcp/server/streamable/webflux => spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server}/autoconfigure/McpServerStreamableHttpWebFluxAutoConfiguration.java (89%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-stateless-common => spring-ai-autoconfigure-mcp-server-webflux}/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (69%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationIT.java => spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationIT.java} (96%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationTests.java => spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationTests.java} (98%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-stateless-webflux/src/test/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/McpStatelessServerWebFluxAutoConfigurationIT.java => spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebFluxAutoConfigurationIT.java} (97%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-streamable-webflux/src/test/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/McpStreamableServerWebFluxAutoConfigurationIT.java => spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableWebFluxAutoConfigurationIT.java} (97%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/SseWebClientAndWebFluxServerIT.java => spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/SseWebClientWebFluxServerIT.java} (99%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-stateless-webflux/src/test/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/StatelessWebClientAndWebFluxServerIT.java => spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StatelessWebClientWebFluxServerIT.java} (96%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-streamable-webflux/src/test/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/StreamableWebClientAndWebFluxServerIT.java => spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StreamableWebClientWebFluxServerIT.java} (99%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-streamable-webmvc => spring-ai-autoconfigure-mcp-server-webmvc}/pom.xml (90%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-sse => spring-ai-autoconfigure-mcp-server-webmvc}/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfiguration.java (94%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/main/java/org/springframework/ai/mcp/server/stateless/webmvc => spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server}/autoconfigure/McpServerStatelessWebMvcAutoConfiguration.java (84%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/main/java/org/springframework/ai/mcp/server/streamable/webmvc => spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server}/autoconfigure/McpServerStreamableHttpWebMvcAutoConfiguration.java (89%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-sse => spring-ai-autoconfigure-mcp-server-webmvc}/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (78%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebMvcServerAutoConfigurationIT.java => spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfigurationIT.java} (97%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/test/java/org/springframework/ai/mcp/server/stateless/webmvc/autoconfigure/McpStatelessServerWebMvcAutoConfigurationIT.java => spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebMvcAutoConfigurationIT.java} (97%) rename auto-configurations/mcp/{spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/test/java/org/springframework/ai/mcp/server/streamable/webmvc/autoconfigure/McpStreamableServerWebMvcAutoConfigurationIT.java => spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableWebMvcAutoConfigurationIT.java} (97%) delete mode 100644 spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-stateless-webflux/pom.xml delete mode 100644 spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-stateless-webmvc/pom.xml delete mode 100644 spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-streamable-webflux/pom.xml delete mode 100644 spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-streamable-webmvc/pom.xml diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/pom.xml b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/pom.xml index 3fa8d2f3b3c..81339cfaded 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/pom.xml +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/pom.xml @@ -23,12 +23,6 @@ - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-properties - ${project.parent.version} - - org.springframework.boot spring-boot-starter diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfiguration.java index 0d7c7ece21f..99a09940148 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfiguration.java @@ -23,11 +23,11 @@ import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerChangeNotificationProperties; import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerProperties; -import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerStreamableHttpProperties; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.AllNestedConditions; +import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -71,23 +71,64 @@ * @since 1.0.0 * @see McpServerProperties */ -@AutoConfiguration(afterName = { - "org.springframework.ai.mcp.server.common.autoconfigure.ToolCallbackConverterAutoConfiguration", - "org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebFluxAutoConfiguration", - "org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebMvcAutoConfiguration", - "org.springframework.ai.mcp.server.streamable.webflux.autoconfigure.McpServerStreamableHttpWebMvcAutoConfiguration", - "org.springframework.ai.mcp.server.streamable.webflux.autoconfigure.McpServerStreamableHttpWebFluxAutoConfiguration" }) +@AutoConfiguration( + afterName = { "org.springframework.ai.mcp.server.common.autoconfigure.ToolCallbackConverterAutoConfiguration", + "org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebFluxAutoConfiguration", + "org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebMvcAutoConfiguration", + "org.springframework.ai.mcp.server.autoconfigure.McpServerStreamableHttpWebMvcAutoConfiguration", + "org.springframework.ai.mcp.server.autoconfigure.McpServerStreamableHttpWebFluxAutoConfiguration" }) @ConditionalOnClass({ McpSchema.class, McpSyncServer.class }) @EnableConfigurationProperties({ McpServerProperties.class, McpServerChangeNotificationProperties.class }) @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) +@Conditional(McpServerAutoConfiguration.NonStatlessServerCondition.class) public class McpServerAutoConfiguration { private static final LogAccessor logger = new LogAccessor(McpServerAutoConfiguration.class); - public static class EnabledNonStatlessServerCondition extends AllNestedConditions { + public static class NonStatlessServerCondition extends AnyNestedCondition { - public EnabledNonStatlessServerCondition() { + public NonStatlessServerCondition() { + super(ConfigurationPhase.PARSE_CONFIGURATION); + } + + @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "protocol", havingValue = "SSE", + matchIfMissing = true) + static class SseEnabledCondition { + + } + + @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "protocol", + havingValue = "STREAMABLE", matchIfMissing = false) + static class StreamableEnabledCondition { + + } + + } + + public static class EnabledSseServerCondition extends AllNestedConditions { + + public EnabledSseServerCondition() { + super(ConfigurationPhase.PARSE_CONFIGURATION); + } + + @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", + matchIfMissing = true) + static class McpServerEnabledCondition { + + } + + @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "protocol", havingValue = "SSE", + matchIfMissing = true) + static class SseEnabledCondition { + + } + + } + + public static class EnabledStreamableServerCondition extends AllNestedConditions { + + public EnabledStreamableServerCondition() { super(ConfigurationPhase.PARSE_CONFIGURATION); } @@ -97,9 +138,9 @@ static class McpServerEnabledCondition { } - @ConditionalOnProperty(prefix = McpServerStreamableHttpProperties.CONFIG_PREFIX, name = "stateless", - havingValue = "false", matchIfMissing = true) - static class StatelessEnabledCondition { + @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "protocol", + havingValue = "STREAMABLE", matchIfMissing = false) + static class StreamableEnabledCondition { } diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/main/java/org/springframework/ai/mcp/server/stateless/autoconfigure/McpServerStatelessAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerStatelessAutoConfiguration.java similarity index 87% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/main/java/org/springframework/ai/mcp/server/stateless/autoconfigure/McpServerStatelessAutoConfiguration.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerStatelessAutoConfiguration.java index 69e0ce48f6b..93bc5e01a52 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/main/java/org/springframework/ai/mcp/server/stateless/autoconfigure/McpServerStatelessAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerStatelessAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.stateless.autoconfigure; +package org.springframework.ai.mcp.server.common.autoconfigure; import java.util.ArrayList; import java.util.List; @@ -22,11 +22,14 @@ import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerProperties; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.AllNestedConditions; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase; import org.springframework.core.env.Environment; import org.springframework.core.log.LogAccessor; import org.springframework.util.CollectionUtils; @@ -52,18 +55,38 @@ /** * @author Christian Tzolov */ -@AutoConfiguration(afterName = { - "org.springframework.ai.mcp.server.stateless.autoconfigure.ToolCallbackConverterAutoConfiguration", - "org.springframework.ai.mcp.server.stateless.webflux.autoconfigure.McpServerStatelessWebFluxAutoConfiguration", - "org.springframework.ai.mcp.server.stateless.webmvc.autoconfigure.McpServerStatelessWebMvcAutoConfiguration" }) +@AutoConfiguration( + afterName = { "org.springframework.ai.mcp.server.autoconfigure.StatelessToolCallbackConverterAutoConfiguration", + "org.springframework.ai.mcp.server.autoconfigure.McpServerStatelessWebFluxAutoConfiguration", + "org.springframework.ai.mcp.server.autoconfigure.McpServerStatelessWebMvcAutoConfiguration" }) @ConditionalOnClass({ McpSchema.class }) @EnableConfigurationProperties(McpServerProperties.class) -@ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", - matchIfMissing = true) +@Conditional({ McpServerStdioDisabledCondition.class, + McpServerStatelessAutoConfiguration.EnabledStatelessServerCondition.class }) public class McpServerStatelessAutoConfiguration { private static final LogAccessor logger = new LogAccessor(McpServerStatelessAutoConfiguration.class); + public static class EnabledStatelessServerCondition extends AllNestedConditions { + + public EnabledStatelessServerCondition() { + super(ConfigurationPhase.PARSE_CONFIGURATION); + } + + @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", + matchIfMissing = true) + static class McpServerEnabledCondition { + + } + + @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "protocol", havingValue = "STATELESS", + matchIfMissing = false) + static class StatelessEnabledCondition { + + } + + } + @Bean @ConditionalOnMissingBean public McpSchema.ServerCapabilities.Builder capabilitiesBuilder() { diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/main/java/org/springframework/ai/mcp/server/stateless/autoconfigure/ToolCallbackConverterAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/StatelessToolCallbackConverterAutoConfiguration.java similarity index 94% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/main/java/org/springframework/ai/mcp/server/stateless/autoconfigure/ToolCallbackConverterAutoConfiguration.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/StatelessToolCallbackConverterAutoConfiguration.java index e3eccbbc872..1a19417db37 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/main/java/org/springframework/ai/mcp/server/stateless/autoconfigure/ToolCallbackConverterAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/StatelessToolCallbackConverterAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.stateless.autoconfigure; +package org.springframework.ai.mcp.server.common.autoconfigure; import java.util.ArrayList; import java.util.List; @@ -41,8 +41,10 @@ */ @AutoConfiguration @EnableConfigurationProperties(McpServerProperties.class) -@Conditional(ToolCallbackConverterAutoConfiguration.ToolCallbackConverterCondition.class) -public class ToolCallbackConverterAutoConfiguration { +@Conditional({ McpServerStdioDisabledCondition.class, + McpServerStatelessAutoConfiguration.EnabledStatelessServerCondition.class, + StatelessToolCallbackConverterAutoConfiguration.ToolCallbackConverterCondition.class }) +public class StatelessToolCallbackConverterAutoConfiguration { public static class ToolCallbackConverterCondition extends AllNestedConditions { diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/ToolCallbackConverterAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/ToolCallbackConverterAutoConfiguration.java index ef0b551e75e..e61982bcaf9 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/ToolCallbackConverterAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/ToolCallbackConverterAutoConfiguration.java @@ -31,7 +31,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase; import org.springframework.util.CollectionUtils; import org.springframework.util.MimeType; @@ -42,7 +41,8 @@ */ @AutoConfiguration @EnableConfigurationProperties(McpServerProperties.class) -@Conditional(ToolCallbackConverterAutoConfiguration.ToolCallbackConverterCondition.class) +@Conditional({ ToolCallbackConverterAutoConfiguration.ToolCallbackConverterCondition.class, + McpServerAutoConfiguration.NonStatlessServerCondition.class }) public class ToolCallbackConverterAutoConfiguration { public static class ToolCallbackConverterCondition extends AllNestedConditions { diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerChangeNotificationProperties.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerChangeNotificationProperties.java similarity index 100% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerChangeNotificationProperties.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerChangeNotificationProperties.java diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerProperties.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerProperties.java similarity index 91% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerProperties.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerProperties.java index da3def86766..4baf1641f04 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerProperties.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerProperties.java @@ -88,10 +88,12 @@ public class McpServerProperties { *
  • ASYNC - Asynchronous server
  • * */ - private ServerType type = ServerType.SYNC; + private ApiType type = ApiType.SYNC; private Capabilities capabilities = new Capabilities(); + private ServerProtocol protocol = ServerProtocol.SSE; + /** * Sets the duration to wait for server responses before timing out requests. This * timeout applies to all requests made through the client, including tool calls, @@ -112,10 +114,16 @@ public Capabilities getCapabilities() { return this.capabilities; } + public enum ServerProtocol { + + SSE, STREAMABLE, STATELESS + + } + /** - * Server types supported by the MCP server. + * API types supported by the MCP server. */ - public enum ServerType { + public enum ApiType { /** * Synchronous (McpSyncServer) server @@ -176,11 +184,11 @@ public void setInstructions(String instructions) { this.instructions = instructions; } - public ServerType getType() { + public ApiType getType() { return this.type; } - public void setType(ServerType serverType) { + public void setType(ApiType serverType) { Assert.notNull(serverType, "Server type must not be null"); this.type = serverType; } @@ -189,6 +197,15 @@ public Map getToolResponseMimeType() { return this.toolResponseMimeType; } + public ServerProtocol getProtocol() { + return this.protocol; + } + + public void setProtocol(ServerProtocol serverMode) { + Assert.notNull(serverMode, "Server mode must not be null"); + this.protocol = serverMode; + } + public static class Capabilities { private boolean resource = true; diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseProperties.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerSseProperties.java similarity index 96% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseProperties.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerSseProperties.java index 59fc1d5df60..2aff7b023a2 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseProperties.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerSseProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.autoconfigure; +package org.springframework.ai.mcp.server.common.autoconfigure.properties; import java.time.Duration; diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerStreamableHttpProperties.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerStreamableHttpProperties.java similarity index 100% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerStreamableHttpProperties.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/properties/McpServerStreamableHttpProperties.java diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 8bc8f6b5482..bb1dd362071 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -15,3 +15,5 @@ # org.springframework.ai.mcp.server.common.autoconfigure.McpServerAutoConfiguration org.springframework.ai.mcp.server.common.autoconfigure.ToolCallbackConverterAutoConfiguration +org.springframework.ai.mcp.server.common.autoconfigure.McpServerStatelessAutoConfiguration +org.springframework.ai.mcp.server.common.autoconfigure.StatelessToolCallbackConverterAutoConfiguration diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfigurationIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfigurationIT.java index 1685f089ed7..f894735f4bc 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfigurationIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfigurationIT.java @@ -70,7 +70,7 @@ void defaultConfiguration() { McpServerProperties properties = context.getBean(McpServerProperties.class); assertThat(properties.getName()).isEqualTo("mcp-server"); assertThat(properties.getVersion()).isEqualTo("1.0.0"); - assertThat(properties.getType()).isEqualTo(McpServerProperties.ServerType.SYNC); + assertThat(properties.getType()).isEqualTo(McpServerProperties.ApiType.SYNC); assertThat(properties.getRequestTimeout().getSeconds()).isEqualTo(20); // Check capabilities @@ -102,7 +102,7 @@ void asyncConfiguration() { assertThat(properties.getName()).isEqualTo("test-server"); assertThat(properties.getVersion()).isEqualTo("2.0.0"); assertThat(properties.getInstructions()).isEqualTo("My MCP Server"); - assertThat(properties.getType()).isEqualTo(McpServerProperties.ServerType.ASYNC); + assertThat(properties.getType()).isEqualTo(McpServerProperties.ApiType.ASYNC); assertThat(properties.getRequestTimeout().getSeconds()).isEqualTo(30); }); } diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/test/java/org/springframework/ai/mcp/server/stateless/autoconfigure/McpStatelessServerAutoConfigurationIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/McpStatelessServerAutoConfigurationIT.java similarity index 98% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/test/java/org/springframework/ai/mcp/server/stateless/autoconfigure/McpStatelessServerAutoConfigurationIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/McpStatelessServerAutoConfigurationIT.java index 6070e13edba..874913f4059 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/test/java/org/springframework/ai/mcp/server/stateless/autoconfigure/McpStatelessServerAutoConfigurationIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/McpStatelessServerAutoConfigurationIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.stateless.autoconfigure; +package org.springframework.ai.mcp.server.common.autoconfigure; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; @@ -54,9 +54,9 @@ public class McpStatelessServerAutoConfigurationIT { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - + .withPropertyValues("spring.ai.mcp.server.protocol=STATELESS") .withConfiguration(AutoConfigurations.of(McpServerStatelessAutoConfiguration.class, - ToolCallbackConverterAutoConfiguration.class)) + StatelessToolCallbackConverterAutoConfiguration.class)) .withUserConfiguration(TestStatelessTransportConfiguration.class); @Test @@ -68,7 +68,7 @@ void defaultConfiguration() { McpServerProperties properties = context.getBean(McpServerProperties.class); assertThat(properties.getName()).isEqualTo("mcp-server"); assertThat(properties.getVersion()).isEqualTo("1.0.0"); - assertThat(properties.getType()).isEqualTo(McpServerProperties.ServerType.SYNC); + assertThat(properties.getType()).isEqualTo(McpServerProperties.ApiType.SYNC); assertThat(properties.getRequestTimeout().getSeconds()).isEqualTo(20); // assertThat(properties.getMcpEndpoint()).isEqualTo("/mcp"); @@ -94,7 +94,7 @@ void asyncConfiguration() { assertThat(properties.getName()).isEqualTo("test-server"); assertThat(properties.getVersion()).isEqualTo("2.0.0"); assertThat(properties.getInstructions()).isEqualTo("My MCP Server"); - assertThat(properties.getType()).isEqualTo(McpServerProperties.ServerType.ASYNC); + assertThat(properties.getType()).isEqualTo(McpServerProperties.ApiType.ASYNC); assertThat(properties.getRequestTimeout().getSeconds()).isEqualTo(30); }); } diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/StatelessToolCallbackConverterAutoConfigurationIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/StatelessToolCallbackConverterAutoConfigurationIT.java new file mode 100644 index 00000000000..2d7047e7977 --- /dev/null +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/StatelessToolCallbackConverterAutoConfigurationIT.java @@ -0,0 +1,302 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.mcp.server.common.autoconfigure; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.ai.mcp.SyncMcpToolCallback; +import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerProperties; +import org.springframework.ai.tool.ToolCallback; +import org.springframework.ai.tool.ToolCallbackProvider; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import io.modelcontextprotocol.client.McpSyncClient; +import io.modelcontextprotocol.server.McpStatelessServerFeatures.AsyncToolSpecification; +import io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncToolSpecification; +import io.modelcontextprotocol.spec.McpSchema; + +/** + * Integration tests for {@link StatelessToolCallbackConverterAutoConfiguration} and + * {@link ToolCallbackConverterCondition}. + * + * @author Christian Tzolov + */ +public class StatelessToolCallbackConverterAutoConfigurationIT { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(StatelessToolCallbackConverterAutoConfiguration.class)) + .withPropertyValues("spring.ai.mcp.server.enabled=true", "spring.ai.mcp.server.protocol=STATELESS"); + + @Test + void defaultSyncToolsConfiguration() { + this.contextRunner.withUserConfiguration(TestToolConfiguration.class).run(context -> { + assertThat(context).hasSingleBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).hasBean("syncTools"); + + @SuppressWarnings("unchecked") + List syncTools = (List) context.getBean("syncTools"); + assertThat(syncTools).hasSize(1); + assertThat(syncTools.get(0)).isNotNull(); + }); + } + + @Test + void asyncToolsConfiguration() { + this.contextRunner.withPropertyValues("spring.ai.mcp.server.type=ASYNC") + .withUserConfiguration(TestToolConfiguration.class) + .run(context -> { + assertThat(context).hasSingleBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).hasBean("asyncTools"); + assertThat(context).doesNotHaveBean("syncTools"); + + @SuppressWarnings("unchecked") + List asyncTools = (List) context.getBean("asyncTools"); + assertThat(asyncTools).hasSize(1); + assertThat(asyncTools.get(0)).isNotNull(); + }); + } + + @Test + void toolCallbackProviderConfiguration() { + this.contextRunner.withUserConfiguration(TestToolCallbackProviderConfiguration.class).run(context -> { + assertThat(context).hasSingleBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).hasBean("syncTools"); + + @SuppressWarnings("unchecked") + List syncTools = (List) context.getBean("syncTools"); + assertThat(syncTools).hasSize(1); + }); + } + + @Test + void multipleToolCallbacksConfiguration() { + this.contextRunner.withUserConfiguration(TestMultipleToolsConfiguration.class).run(context -> { + assertThat(context).hasSingleBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).hasBean("syncTools"); + + @SuppressWarnings("unchecked") + List syncTools = (List) context.getBean("syncTools"); + assertThat(syncTools).hasSize(2); + }); + } + + @Test + void toolResponseMimeTypeConfiguration() { + this.contextRunner.withPropertyValues("spring.ai.mcp.server.tool-response-mime-type.test-tool=application/json") + .withUserConfiguration(TestToolConfiguration.class) + .run(context -> { + assertThat(context).hasSingleBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).hasBean("syncTools"); + + @SuppressWarnings("unchecked") + List syncTools = (List) context.getBean("syncTools"); + assertThat(syncTools).hasSize(1); + + McpServerProperties properties = context.getBean(McpServerProperties.class); + assertThat(properties.getToolResponseMimeType()).containsEntry("test-tool", "application/json"); + }); + } + + @Test + void duplicateToolNamesDeduplication() { + this.contextRunner.withUserConfiguration(TestDuplicateToolsConfiguration.class).run(context -> { + assertThat(context).hasSingleBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).hasBean("syncTools"); + + @SuppressWarnings("unchecked") + List syncTools = (List) context.getBean("syncTools"); + // Tools have different client prefixes, so both should be present + assertThat(syncTools).hasSize(2); + }); + } + + @Test + void conditionDisabledWhenServerDisabled() { + this.contextRunner.withPropertyValues("spring.ai.mcp.server.enabled=false") + .withUserConfiguration(TestToolConfiguration.class) + .run(context -> { + assertThat(context).doesNotHaveBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).doesNotHaveBean("syncTools"); + assertThat(context).doesNotHaveBean("asyncTools"); + }); + } + + @Test + void conditionDisabledWhenToolCallbackConvertDisabled() { + this.contextRunner.withPropertyValues("spring.ai.mcp.server.tool-callback-converter=false") + .withUserConfiguration(TestToolConfiguration.class) + .run(context -> { + assertThat(context).doesNotHaveBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).doesNotHaveBean("syncTools"); + assertThat(context).doesNotHaveBean("asyncTools"); + }); + } + + @Test + void conditionEnabledByDefault() { + this.contextRunner.withUserConfiguration(TestToolConfiguration.class).run(context -> { + assertThat(context).hasSingleBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).hasBean("syncTools"); + }); + } + + @Test + void conditionEnabledExplicitly() { + this.contextRunner + .withPropertyValues("spring.ai.mcp.server.enabled=true", + "spring.ai.mcp.server.tool-callback-converter=true") + .withUserConfiguration(TestToolConfiguration.class) + .run(context -> { + assertThat(context).hasSingleBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).hasBean("syncTools"); + }); + } + + @Test + void emptyToolCallbacksConfiguration() { + this.contextRunner.run(context -> { + assertThat(context).hasSingleBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).hasBean("syncTools"); + + @SuppressWarnings("unchecked") + List syncTools = (List) context.getBean("syncTools"); + assertThat(syncTools).isEmpty(); + }); + } + + @Test + void mixedToolCallbacksAndProvidersConfiguration() { + this.contextRunner + .withUserConfiguration(TestToolConfiguration.class, TestToolCallbackProviderConfiguration.class) + .run(context -> { + assertThat(context).hasSingleBean(StatelessToolCallbackConverterAutoConfiguration.class); + assertThat(context).hasBean("syncTools"); + + @SuppressWarnings("unchecked") + List syncTools = (List) context.getBean("syncTools"); + assertThat(syncTools).hasSize(2); // One from direct callback, one from + // provider + }); + } + + @Configuration + static class TestToolConfiguration { + + @Bean + List testToolCallbacks() { + McpSyncClient mockClient = Mockito.mock(McpSyncClient.class); + McpSchema.Tool mockTool = Mockito.mock(McpSchema.Tool.class); + McpSchema.CallToolResult mockResult = Mockito.mock(McpSchema.CallToolResult.class); + + Mockito.when(mockTool.name()).thenReturn("test-tool"); + Mockito.when(mockTool.description()).thenReturn("Test Tool"); + Mockito.when(mockClient.callTool(Mockito.any(McpSchema.CallToolRequest.class))).thenReturn(mockResult); + when(mockClient.getClientInfo()).thenReturn(new McpSchema.Implementation("testClient", "1.0.0")); + + return List.of(new SyncMcpToolCallback(mockClient, mockTool)); + } + + } + + @Configuration + static class TestMultipleToolsConfiguration { + + @Bean + List testMultipleToolCallbacks() { + McpSyncClient mockClient1 = Mockito.mock(McpSyncClient.class); + McpSchema.Tool mockTool1 = Mockito.mock(McpSchema.Tool.class); + McpSchema.CallToolResult mockResult1 = Mockito.mock(McpSchema.CallToolResult.class); + + Mockito.when(mockTool1.name()).thenReturn("test-tool-1"); + Mockito.when(mockTool1.description()).thenReturn("Test Tool 1"); + Mockito.when(mockClient1.callTool(Mockito.any(McpSchema.CallToolRequest.class))).thenReturn(mockResult1); + when(mockClient1.getClientInfo()).thenReturn(new McpSchema.Implementation("testClient1", "1.0.0")); + + McpSyncClient mockClient2 = Mockito.mock(McpSyncClient.class); + McpSchema.Tool mockTool2 = Mockito.mock(McpSchema.Tool.class); + McpSchema.CallToolResult mockResult2 = Mockito.mock(McpSchema.CallToolResult.class); + + Mockito.when(mockTool2.name()).thenReturn("test-tool-2"); + Mockito.when(mockTool2.description()).thenReturn("Test Tool 2"); + Mockito.when(mockClient2.callTool(Mockito.any(McpSchema.CallToolRequest.class))).thenReturn(mockResult2); + when(mockClient2.getClientInfo()).thenReturn(new McpSchema.Implementation("testClient2", "1.0.0")); + + return List.of(new SyncMcpToolCallback(mockClient1, mockTool1), + new SyncMcpToolCallback(mockClient2, mockTool2)); + } + + } + + @Configuration + static class TestDuplicateToolsConfiguration { + + @Bean + List testDuplicateToolCallbacks() { + McpSyncClient mockClient1 = Mockito.mock(McpSyncClient.class); + McpSchema.Tool mockTool1 = Mockito.mock(McpSchema.Tool.class); + McpSchema.CallToolResult mockResult1 = Mockito.mock(McpSchema.CallToolResult.class); + + Mockito.when(mockTool1.name()).thenReturn("duplicate-tool"); + Mockito.when(mockTool1.description()).thenReturn("First Tool"); + Mockito.when(mockClient1.callTool(Mockito.any(McpSchema.CallToolRequest.class))).thenReturn(mockResult1); + when(mockClient1.getClientInfo()).thenReturn(new McpSchema.Implementation("testClient1", "1.0.0")); + + McpSyncClient mockClient2 = Mockito.mock(McpSyncClient.class); + McpSchema.Tool mockTool2 = Mockito.mock(McpSchema.Tool.class); + McpSchema.CallToolResult mockResult2 = Mockito.mock(McpSchema.CallToolResult.class); + + Mockito.when(mockTool2.name()).thenReturn("duplicate-tool"); + Mockito.when(mockTool2.description()).thenReturn("Second Tool"); + Mockito.when(mockClient2.callTool(Mockito.any(McpSchema.CallToolRequest.class))).thenReturn(mockResult2); + when(mockClient2.getClientInfo()).thenReturn(new McpSchema.Implementation("testClient2", "1.0.0")); + + return List.of(new SyncMcpToolCallback(mockClient1, mockTool1), + new SyncMcpToolCallback(mockClient2, mockTool2)); + } + + } + + @Configuration + static class TestToolCallbackProviderConfiguration { + + @Bean + ToolCallbackProvider testToolCallbackProvider() { + return () -> { + McpSyncClient mockClient = Mockito.mock(McpSyncClient.class); + McpSchema.Tool mockTool = Mockito.mock(McpSchema.Tool.class); + McpSchema.CallToolResult mockResult = Mockito.mock(McpSchema.CallToolResult.class); + + Mockito.when(mockTool.name()).thenReturn("provider-tool"); + Mockito.when(mockTool.description()).thenReturn("Provider Tool"); + Mockito.when(mockClient.callTool(Mockito.any(McpSchema.CallToolRequest.class))).thenReturn(mockResult); + when(mockClient.getClientInfo()).thenReturn(new McpSchema.Implementation("testClient", "1.0.0")); + + return new ToolCallback[] { new SyncMcpToolCallback(mockClient, mockTool) }; + }; + } + + } + +} diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/test/java/org/springframework/ai/mcp/server/stateless/autoconfigure/ToolCallbackConverterAutoConfigurationIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/ToolCallbackConverterAutoConfigurationIT.java similarity index 98% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/test/java/org/springframework/ai/mcp/server/stateless/autoconfigure/ToolCallbackConverterAutoConfigurationIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/ToolCallbackConverterAutoConfigurationIT.java index 30f8cf9dd33..2f65dbf7d03 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/test/java/org/springframework/ai/mcp/server/stateless/autoconfigure/ToolCallbackConverterAutoConfigurationIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/test/java/org/springframework/ai/mcp/server/common/autoconfigure/ToolCallbackConverterAutoConfigurationIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.stateless.autoconfigure; +package org.springframework.ai.mcp.server.common.autoconfigure; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; @@ -33,8 +33,8 @@ import org.springframework.context.annotation.Configuration; import io.modelcontextprotocol.client.McpSyncClient; -import io.modelcontextprotocol.server.McpStatelessServerFeatures.AsyncToolSpecification; -import io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncToolSpecification; +import io.modelcontextprotocol.server.McpServerFeatures.AsyncToolSpecification; +import io.modelcontextprotocol.server.McpServerFeatures.SyncToolSpecification; import io.modelcontextprotocol.spec.McpSchema; /** diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/pom.xml b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/pom.xml deleted file mode 100644 index ef71ee15b27..00000000000 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - 4.0.0 - - org.springframework.ai - spring-ai-parent - 1.1.0-SNAPSHOT - ../../../pom.xml - - spring-ai-autoconfigure-mcp-server-properties - jar - Spring AI MCP Server Properties Auto Configuration - Spring AI MCP Server Properties Auto Configuration - https://github.com/spring-projects/spring-ai - - - https://github.com/spring-projects/spring-ai - git://github.com/spring-projects/spring-ai.git - git@github.com:spring-projects/spring-ai.git - - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.ai - spring-ai-mcp - ${project.parent.version} - true - - - - org.springframework - spring-web - true - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - - - - org.springframework.ai - spring-ai-test - ${project.parent.version} - test - - - - net.javacrumbs.json-unit - json-unit-assertj - ${json-unit-assertj.version} - test - - - - - diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/pom.xml b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/pom.xml deleted file mode 100644 index e6cb8a9eb1d..00000000000 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - 4.0.0 - - org.springframework.ai - spring-ai-parent - 1.1.0-SNAPSHOT - ../../../pom.xml - - spring-ai-autoconfigure-mcp-server-stateless-common - jar - Spring AI MCP Stateless Server Common Auto Configuration - Spring AI MCP Stateless Server Common Auto Configuration - https://github.com/spring-projects/spring-ai - - - https://github.com/spring-projects/spring-ai - git://github.com/spring-projects/spring-ai.git - git@github.com:spring-projects/spring-ai.git - - - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-properties - ${project.parent.version} - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.ai - spring-ai-mcp - ${project.parent.version} - true - - - - io.modelcontextprotocol.sdk - mcp-spring-webmvc - true - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - - - - org.springframework.ai - spring-ai-test - ${project.parent.version} - test - - - - - - diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/pom.xml b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/pom.xml deleted file mode 100644 index fec35f12c65..00000000000 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/pom.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - 4.0.0 - - org.springframework.ai - spring-ai-parent - 1.1.0-SNAPSHOT - ../../../pom.xml - - spring-ai-autoconfigure-mcp-server-stateless-webflux - jar - Spring AI MCP Stateless Server WebFlux Auto Configuration - Spring AI MCP Stateless Server WebFlux Auto Configuration - https://github.com/spring-projects/spring-ai - - - https://github.com/spring-projects/spring-ai - git://github.com/spring-projects/spring-ai.git - git@github.com:spring-projects/spring-ai.git - - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.ai - spring-ai-mcp - ${project.parent.version} - true - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-stateless-common - ${project.parent.version} - - - - io.modelcontextprotocol.sdk - mcp-spring-webflux - true - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - - - - org.springframework.ai - spring-ai-test - ${project.parent.version} - test - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-client-webflux - ${project.parent.version} - test - - - - org.springframework.boot - spring-boot-starter-webflux - test - - - - org.springframework.boot - spring-boot-starter-test - test - - - - net.javacrumbs.json-unit - json-unit-assertj - ${json-unit-assertj.version} - test - - - - - - diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 228aa5cb63f..00000000000 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright 2025-2025 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -org.springframework.ai.mcp.server.stateless.webflux.autoconfigure.McpServerStatelessWebFluxAutoConfiguration - diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/pom.xml b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/pom.xml deleted file mode 100644 index 770d489b644..00000000000 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/pom.xml +++ /dev/null @@ -1,74 +0,0 @@ - - - 4.0.0 - - org.springframework.ai - spring-ai-parent - 1.1.0-SNAPSHOT - ../../../pom.xml - - spring-ai-autoconfigure-mcp-server-stateless-webmvc - jar - Spring AI MCP Stateless Server WebMVC Auto Configuration - Spring AI MCP Stateless Server WebMVC Auto Configuration - https://github.com/spring-projects/spring-ai - - - https://github.com/spring-projects/spring-ai - git://github.com/spring-projects/spring-ai.git - git@github.com:spring-projects/spring-ai.git - - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.ai - spring-ai-mcp - ${project.parent.version} - true - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-stateless-common - ${project.parent.version} - - - - io.modelcontextprotocol.sdk - mcp-spring-webmvc - true - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - - - - org.springframework.ai - spring-ai-test - ${project.parent.version} - test - - - - - - diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 993c16c56a9..00000000000 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright 2025-2025 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -package org.springframework.ai.mcp.server.stateless.webmvc.autoconfigure.McpServerStatelessWebMvcAutoConfiguration \ No newline at end of file diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/pom.xml b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/pom.xml deleted file mode 100644 index c408b2665e8..00000000000 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/pom.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - 4.0.0 - - org.springframework.ai - spring-ai-parent - 1.1.0-SNAPSHOT - ../../../pom.xml - - spring-ai-autoconfigure-mcp-server-streamable-webflux - jar - Spring AI MCP Streamable Server WebFlux Auto Configuration - Spring AI MCP Streamable Server WebFlux Auto Configuration - https://github.com/spring-projects/spring-ai - - - https://github.com/spring-projects/spring-ai - git://github.com/spring-projects/spring-ai.git - git@github.com:spring-projects/spring-ai.git - - - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-common - ${project.parent.version} - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.ai - spring-ai-mcp - ${project.parent.version} - true - - - - io.modelcontextprotocol.sdk - mcp-spring-webflux - true - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - org.springframework.boot - spring-boot-autoconfigure-processor - true - - - - - - org.springframework.ai - spring-ai-test - ${project.parent.version} - test - - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-client-webflux - ${project.parent.version} - test - - - - org.springframework.boot - spring-boot-starter-webflux - test - - - - org.springframework.boot - spring-boot-starter-test - test - - - - net.javacrumbs.json-unit - json-unit-assertj - ${json-unit-assertj.version} - test - - - - - diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index 488a5af0793..00000000000 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright 2025-2025 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -org.springframework.ai.mcp.server.streamable.webflux.autoconfigure.McpServerStreamableHttpWebFluxAutoConfiguration - diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index e62a4964ae5..00000000000 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ /dev/null @@ -1,17 +0,0 @@ -# -# Copyright 2025-2025 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -org.springframework.ai.mcp.server.streamable.webmvc.autoconfigure.McpServerStreamableHttpWebMvcAutoConfiguration - diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/pom.xml b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/pom.xml similarity index 88% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/pom.xml rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/pom.xml index 46257d9bc46..55e85ef8143 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/pom.xml +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/pom.xml @@ -9,10 +9,10 @@ 1.1.0-SNAPSHOT ../../../pom.xml - spring-ai-autoconfigure-mcp-server-sse + spring-ai-autoconfigure-mcp-server-webflux jar - Spring AI MCP Server Auto Configuration - Spring AI MCP Server Auto Configuration + Spring AI MCP Server WebFlux Auto Configuration + Spring AI MCP Server WebFlux Auto Configuration https://github.com/spring-projects/spring-ai @@ -47,12 +47,6 @@ true
    - - io.modelcontextprotocol.sdk - mcp-spring-webmvc - true - - org.springframework.boot spring-boot-configuration-processor diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfiguration.java similarity index 93% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfiguration.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfiguration.java index adfb3070c88..b41563b7a42 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfiguration.java @@ -22,6 +22,8 @@ import org.springframework.ai.mcp.server.common.autoconfigure.McpServerAutoConfiguration; import org.springframework.ai.mcp.server.common.autoconfigure.McpServerStdioDisabledCondition; +import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerProperties; +import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerSseProperties; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -75,8 +77,7 @@ @EnableConfigurationProperties({ McpServerSseProperties.class }) @ConditionalOnClass({ WebFluxSseServerTransportProvider.class }) @ConditionalOnMissingBean(McpServerTransportProvider.class) -@Conditional({ McpServerStdioDisabledCondition.class, - McpServerAutoConfiguration.EnabledNonStatlessServerCondition.class }) +@Conditional({ McpServerStdioDisabledCondition.class, McpServerAutoConfiguration.EnabledSseServerCondition.class }) public class McpServerSseWebFluxAutoConfiguration { @Bean diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/main/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/McpServerStatelessWebFluxAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebFluxAutoConfiguration.java similarity index 84% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/main/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/McpServerStatelessWebFluxAutoConfiguration.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebFluxAutoConfiguration.java index a1eb0dd1480..248ac9fc7e7 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/main/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/McpServerStatelessWebFluxAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebFluxAutoConfiguration.java @@ -14,16 +14,18 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.stateless.webflux.autoconfigure; +package org.springframework.ai.mcp.server.autoconfigure; +import org.springframework.ai.mcp.server.common.autoconfigure.McpServerStatelessAutoConfiguration; +import org.springframework.ai.mcp.server.common.autoconfigure.McpServerStdioDisabledCondition; import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerStreamableHttpProperties; -import org.springframework.ai.mcp.server.stateless.autoconfigure.McpServerStatelessAutoConfiguration; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.web.reactive.function.server.RouterFunction; import com.fasterxml.jackson.databind.ObjectMapper; @@ -37,6 +39,8 @@ @AutoConfiguration(before = McpServerStatelessAutoConfiguration.class) @ConditionalOnClass({ McpSchema.class }) @EnableConfigurationProperties(McpServerStreamableHttpProperties.class) +@Conditional({ McpServerStdioDisabledCondition.class, + McpServerStatelessAutoConfiguration.EnabledStatelessServerCondition.class }) public class McpServerStatelessWebFluxAutoConfiguration { @Bean diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/main/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/McpServerStreamableHttpWebFluxAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableHttpWebFluxAutoConfiguration.java similarity index 89% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/main/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/McpServerStreamableHttpWebFluxAutoConfiguration.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableHttpWebFluxAutoConfiguration.java index 559c1fa25f8..cddc10965b5 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/main/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/McpServerStreamableHttpWebFluxAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableHttpWebFluxAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.streamable.webflux.autoconfigure; +package org.springframework.ai.mcp.server.autoconfigure; import org.springframework.ai.mcp.server.common.autoconfigure.McpServerAutoConfiguration; import org.springframework.ai.mcp.server.common.autoconfigure.McpServerStdioDisabledCondition; @@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; @@ -41,9 +40,8 @@ @AutoConfiguration(before = McpServerAutoConfiguration.class) @ConditionalOnClass({ McpSchema.class }) @EnableConfigurationProperties({ McpServerProperties.class, McpServerStreamableHttpProperties.class }) -@Conditional(McpServerStdioDisabledCondition.class) -@ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", - matchIfMissing = true) +@Conditional({ McpServerStdioDisabledCondition.class, + McpServerAutoConfiguration.EnabledStreamableServerCondition.class }) public class McpServerStreamableHttpWebFluxAutoConfiguration { @Bean diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports similarity index 69% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 12f3fd0dc59..9096ca77c62 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -13,6 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -org.springframework.ai.mcp.server.stateless.autoconfigure.McpStatelessServerAutoConfiguration -org.springframework.ai.mcp.server.stateless.autoconfigure.ToolCallbackConverterAutoConfiguration - +org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebFluxAutoConfiguration +org.springframework.ai.mcp.server.autoconfigure.McpServerStreamableHttpWebFluxAutoConfiguration +org.springframework.ai.mcp.server.autoconfigure.McpServerStatelessWebFluxAutoConfiguration diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationIT.java similarity index 96% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationIT.java index 03453258fca..71254f9ed7b 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationIT.java @@ -22,13 +22,14 @@ import io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider; import org.junit.jupiter.api.Test; import org.springframework.ai.mcp.server.common.autoconfigure.McpServerAutoConfiguration; +import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerSseProperties; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.web.reactive.function.server.RouterFunction; import static org.assertj.core.api.Assertions.assertThat; -class McpWebFluxServerAutoConfigurationIT { +class McpServerSseWebFluxAutoConfigurationIT { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( AutoConfigurations.of(McpServerSseWebFluxAutoConfiguration.class, McpServerAutoConfiguration.class)); diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationTests.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationTests.java similarity index 98% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationTests.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationTests.java index f7fe0e26d17..a3f10b58de6 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxServerAutoConfigurationTests.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebFluxAutoConfigurationTests.java @@ -29,7 +29,7 @@ import static org.assertj.core.api.Assertions.assertThat; -class McpWebFluxServerAutoConfigurationTests { +class McpServerSseWebFluxAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(McpServerSseWebFluxAutoConfiguration.class, diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/test/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/McpStatelessServerWebFluxAutoConfigurationIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebFluxAutoConfigurationIT.java similarity index 97% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/test/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/McpStatelessServerWebFluxAutoConfigurationIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebFluxAutoConfigurationIT.java index 5f2d22ec2ee..2f7d002e0fb 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/test/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/McpStatelessServerWebFluxAutoConfigurationIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebFluxAutoConfigurationIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.stateless.webflux.autoconfigure; +package org.springframework.ai.mcp.server.autoconfigure; import com.fasterxml.jackson.databind.ObjectMapper; @@ -28,9 +28,10 @@ import static org.assertj.core.api.Assertions.assertThat; -class McpStatelessServerWebFluxAutoConfigurationIT { +class McpServerStatelessWebFluxAutoConfigurationIT { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.ai.mcp.server.protocol=STATELESS") .withConfiguration(AutoConfigurations.of(McpServerStatelessWebFluxAutoConfiguration.class)); @Test diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/test/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/McpStreamableServerWebFluxAutoConfigurationIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableWebFluxAutoConfigurationIT.java similarity index 97% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/test/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/McpStreamableServerWebFluxAutoConfigurationIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableWebFluxAutoConfigurationIT.java index 45abc9826b3..5b7a54b61e2 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/test/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/McpStreamableServerWebFluxAutoConfigurationIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableWebFluxAutoConfigurationIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.streamable.webflux.autoconfigure; +package org.springframework.ai.mcp.server.autoconfigure; import com.fasterxml.jackson.databind.ObjectMapper; import io.modelcontextprotocol.server.transport.WebFluxStreamableServerTransportProvider; @@ -27,9 +27,10 @@ import static org.assertj.core.api.Assertions.assertThat; -class McpStreamableServerWebFluxAutoConfigurationIT { +class McpServerStreamableWebFluxAutoConfigurationIT { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.ai.mcp.server.protocol=STREAMABLE") .withConfiguration(AutoConfigurations.of(McpServerStreamableHttpWebFluxAutoConfiguration.class)); @Test diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/SseWebClientAndWebFluxServerIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/SseWebClientWebFluxServerIT.java similarity index 99% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/SseWebClientAndWebFluxServerIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/SseWebClientWebFluxServerIT.java index 0fecce14ae8..7a3d6fb9082 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/SseWebClientAndWebFluxServerIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/SseWebClientWebFluxServerIT.java @@ -83,9 +83,9 @@ import reactor.netty.DisposableServer; import reactor.netty.http.server.HttpServer; -public class SseWebClientAndWebFluxServerIT { +public class SseWebClientWebFluxServerIT { - private static final Logger logger = LoggerFactory.getLogger(SseWebClientAndWebFluxServerIT.class); + private static final Logger logger = LoggerFactory.getLogger(SseWebClientWebFluxServerIT.class); private final ApplicationContextRunner serverContextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(McpServerAutoConfiguration.class, diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/test/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/StatelessWebClientAndWebFluxServerIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StatelessWebClientWebFluxServerIT.java similarity index 96% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/test/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/StatelessWebClientAndWebFluxServerIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StatelessWebClientWebFluxServerIT.java index ffbefeaf8f3..47e573152a4 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux/src/test/java/org/springframework/ai/mcp/server/stateless/webflux/autoconfigure/StatelessWebClientAndWebFluxServerIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StatelessWebClientWebFluxServerIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.stateless.webflux.autoconfigure; +package org.springframework.ai.mcp.server.autoconfigure; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json; @@ -31,8 +31,8 @@ import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer; import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerProperties; import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerStreamableHttpProperties; -import org.springframework.ai.mcp.server.stateless.autoconfigure.McpServerStatelessAutoConfiguration; -import org.springframework.ai.mcp.server.stateless.autoconfigure.ToolCallbackConverterAutoConfiguration; +import org.springframework.ai.mcp.server.common.autoconfigure.McpServerStatelessAutoConfiguration; +import org.springframework.ai.mcp.server.common.autoconfigure.StatelessToolCallbackConverterAutoConfiguration; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; @@ -69,11 +69,13 @@ import reactor.netty.DisposableServer; import reactor.netty.http.server.HttpServer; -public class StatelessWebClientAndWebFluxServerIT { +public class StatelessWebClientWebFluxServerIT { private final ApplicationContextRunner serverContextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.ai.mcp.server.protocol=STATELESS") .withConfiguration(AutoConfigurations.of(McpServerStatelessAutoConfiguration.class, - ToolCallbackConverterAutoConfiguration.class, McpServerStatelessWebFluxAutoConfiguration.class)); + StatelessToolCallbackConverterAutoConfiguration.class, + McpServerStatelessWebFluxAutoConfiguration.class)); private final ApplicationContextRunner clientApplicationContext = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(McpToolCallbackAutoConfiguration.class, diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/test/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/StreamableWebClientAndWebFluxServerIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StreamableWebClientWebFluxServerIT.java similarity index 99% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/test/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/StreamableWebClientAndWebFluxServerIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StreamableWebClientWebFluxServerIT.java index c767892db1b..09b4243f9cc 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux/src/test/java/org/springframework/ai/mcp/server/streamable/webflux/autoconfigure/StreamableWebClientAndWebFluxServerIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StreamableWebClientWebFluxServerIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.streamable.webflux.autoconfigure; +package org.springframework.ai.mcp.server.autoconfigure; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.json; @@ -85,11 +85,12 @@ import reactor.netty.DisposableServer; import reactor.netty.http.server.HttpServer; -public class StreamableWebClientAndWebFluxServerIT { +public class StreamableWebClientWebFluxServerIT { - private static final Logger logger = LoggerFactory.getLogger(StreamableWebClientAndWebFluxServerIT.class); + private static final Logger logger = LoggerFactory.getLogger(StreamableWebClientWebFluxServerIT.class); private final ApplicationContextRunner serverContextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.ai.mcp.server.protocol=STREAMABLE") .withConfiguration(AutoConfigurations.of(McpServerAutoConfiguration.class, ToolCallbackConverterAutoConfiguration.class, McpServerStreamableHttpWebFluxAutoConfiguration.class)); diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/pom.xml b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/pom.xml similarity index 90% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/pom.xml rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/pom.xml index e4d48e65648..4a9f31bbf6a 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/pom.xml +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/pom.xml @@ -9,10 +9,10 @@ 1.1.0-SNAPSHOT ../../../pom.xml - spring-ai-autoconfigure-mcp-server-streamable-webmvc + spring-ai-autoconfigure-mcp-server-webmvc jar - Spring AI MCP Streamable Server WebMvc Auto Configuration - Spring AI MCP Streamable Server WebMvc Auto Configuration + Spring AI MCP Server WebMVC Auto Configuration + Spring AI MCP Server WebMVC Auto Configuration https://github.com/spring-projects/spring-ai @@ -28,7 +28,7 @@ spring-ai-autoconfigure-mcp-server-common ${project.parent.version} - + org.springframework.boot spring-boot-starter @@ -60,6 +60,7 @@ + org.springframework.ai spring-ai-test diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfiguration.java similarity index 94% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfiguration.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfiguration.java index b452b40e0ec..bc3db979813 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfiguration.java @@ -23,6 +23,7 @@ import org.springframework.ai.mcp.server.common.autoconfigure.McpServerAutoConfiguration; import org.springframework.ai.mcp.server.common.autoconfigure.McpServerStdioDisabledCondition; import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerProperties; +import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerSseProperties; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -69,8 +70,7 @@ @EnableConfigurationProperties({ McpServerSseProperties.class }) @ConditionalOnClass({ WebMvcSseServerTransportProvider.class }) @ConditionalOnMissingBean(McpServerTransportProvider.class) -@Conditional({ McpServerStdioDisabledCondition.class, - McpServerAutoConfiguration.EnabledNonStatlessServerCondition.class }) +@Conditional({ McpServerStdioDisabledCondition.class, McpServerAutoConfiguration.EnabledSseServerCondition.class }) public class McpServerSseWebMvcAutoConfiguration { @Bean diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/main/java/org/springframework/ai/mcp/server/stateless/webmvc/autoconfigure/McpServerStatelessWebMvcAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebMvcAutoConfiguration.java similarity index 84% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/main/java/org/springframework/ai/mcp/server/stateless/webmvc/autoconfigure/McpServerStatelessWebMvcAutoConfiguration.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebMvcAutoConfiguration.java index 0f980dcfee0..b3bd1985f50 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/main/java/org/springframework/ai/mcp/server/stateless/webmvc/autoconfigure/McpServerStatelessWebMvcAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebMvcAutoConfiguration.java @@ -14,16 +14,18 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.stateless.webmvc.autoconfigure; +package org.springframework.ai.mcp.server.autoconfigure; +import org.springframework.ai.mcp.server.common.autoconfigure.McpServerStatelessAutoConfiguration; +import org.springframework.ai.mcp.server.common.autoconfigure.McpServerStdioDisabledCondition; import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerStreamableHttpProperties; -import org.springframework.ai.mcp.server.stateless.autoconfigure.McpServerStatelessAutoConfiguration; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; import org.springframework.web.servlet.function.RouterFunction; import com.fasterxml.jackson.databind.ObjectMapper; @@ -37,6 +39,8 @@ @AutoConfiguration(before = McpServerStatelessAutoConfiguration.class) @ConditionalOnClass({ McpSchema.class }) @EnableConfigurationProperties(McpServerStreamableHttpProperties.class) +@Conditional({ McpServerStdioDisabledCondition.class, + McpServerStatelessAutoConfiguration.EnabledStatelessServerCondition.class }) public class McpServerStatelessWebMvcAutoConfiguration { @Bean diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/main/java/org/springframework/ai/mcp/server/streamable/webmvc/autoconfigure/McpServerStreamableHttpWebMvcAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableHttpWebMvcAutoConfiguration.java similarity index 89% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/main/java/org/springframework/ai/mcp/server/streamable/webmvc/autoconfigure/McpServerStreamableHttpWebMvcAutoConfiguration.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableHttpWebMvcAutoConfiguration.java index 44a780d8d68..c6abeb10b18 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/main/java/org/springframework/ai/mcp/server/streamable/webmvc/autoconfigure/McpServerStreamableHttpWebMvcAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableHttpWebMvcAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.streamable.webmvc.autoconfigure; +package org.springframework.ai.mcp.server.autoconfigure; import org.springframework.ai.mcp.server.common.autoconfigure.McpServerAutoConfiguration; import org.springframework.ai.mcp.server.common.autoconfigure.McpServerStdioDisabledCondition; @@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; @@ -41,9 +40,8 @@ @AutoConfiguration(before = McpServerAutoConfiguration.class) @ConditionalOnClass({ McpSchema.class }) @EnableConfigurationProperties({ McpServerProperties.class, McpServerStreamableHttpProperties.class }) -@Conditional(McpServerStdioDisabledCondition.class) -@ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", - matchIfMissing = true) +@Conditional({ McpServerStdioDisabledCondition.class, + McpServerAutoConfiguration.EnabledStreamableServerCondition.class }) public class McpServerStreamableHttpWebMvcAutoConfiguration { @Bean diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports similarity index 78% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index b1047c899c9..6cf0fceec11 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -13,5 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebFluxAutoConfiguration org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebMvcAutoConfiguration +org.springframework.ai.mcp.server.autoconfigure.McpServerStreamableHttpWebMvcAutoConfiguration +org.springframework.ai.mcp.server.autoconfigure.McpServerStatelessWebMvcAutoConfiguration diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebMvcServerAutoConfigurationIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfigurationIT.java similarity index 97% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebMvcServerAutoConfigurationIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfigurationIT.java index 76862859f1c..e1a3d3c5291 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpWebMvcServerAutoConfigurationIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerSseWebMvcAutoConfigurationIT.java @@ -21,6 +21,7 @@ import io.modelcontextprotocol.server.transport.WebMvcSseServerTransportProvider; import org.junit.jupiter.api.Test; import org.springframework.ai.mcp.server.common.autoconfigure.McpServerAutoConfiguration; +import org.springframework.ai.mcp.server.common.autoconfigure.properties.McpServerSseProperties; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -31,7 +32,7 @@ import static org.assertj.core.api.Assertions.assertThat; -class McpWebMvcServerAutoConfigurationIT { +class McpServerSseWebMvcAutoConfigurationIT { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( AutoConfigurations.of(McpServerSseWebMvcAutoConfiguration.class, McpServerAutoConfiguration.class)); diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/test/java/org/springframework/ai/mcp/server/stateless/webmvc/autoconfigure/McpStatelessServerWebMvcAutoConfigurationIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebMvcAutoConfigurationIT.java similarity index 97% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/test/java/org/springframework/ai/mcp/server/stateless/webmvc/autoconfigure/McpStatelessServerWebMvcAutoConfigurationIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebMvcAutoConfigurationIT.java index 5f3423efba5..8f0dfdd3f49 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc/src/test/java/org/springframework/ai/mcp/server/stateless/webmvc/autoconfigure/McpStatelessServerWebMvcAutoConfigurationIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStatelessWebMvcAutoConfigurationIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.stateless.webmvc.autoconfigure; +package org.springframework.ai.mcp.server.autoconfigure; import com.fasterxml.jackson.databind.ObjectMapper; @@ -28,9 +28,10 @@ import static org.assertj.core.api.Assertions.assertThat; -class McpStatelessServerWebMvcAutoConfigurationIT { +class McpServerStatelessWebMvcAutoConfigurationIT { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.ai.mcp.server.protocol=STATELESS") .withConfiguration(AutoConfigurations.of(McpServerStatelessWebMvcAutoConfiguration.class)); @Test diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/test/java/org/springframework/ai/mcp/server/streamable/webmvc/autoconfigure/McpStreamableServerWebMvcAutoConfigurationIT.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableWebMvcAutoConfigurationIT.java similarity index 97% rename from auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/test/java/org/springframework/ai/mcp/server/streamable/webmvc/autoconfigure/McpStreamableServerWebMvcAutoConfigurationIT.java rename to auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableWebMvcAutoConfigurationIT.java index a297d9ae002..28dcd24d96f 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc/src/test/java/org/springframework/ai/mcp/server/streamable/webmvc/autoconfigure/McpStreamableServerWebMvcAutoConfigurationIT.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc/src/test/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableWebMvcAutoConfigurationIT.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.mcp.server.streamable.webmvc.autoconfigure; +package org.springframework.ai.mcp.server.autoconfigure; import com.fasterxml.jackson.databind.ObjectMapper; import io.modelcontextprotocol.server.transport.WebMvcStreamableServerTransportProvider; @@ -27,9 +27,10 @@ import static org.assertj.core.api.Assertions.assertThat; -class McpStreamableServerWebMvcAutoConfigurationIT { +class McpServerStreamableWebMvcAutoConfigurationIT { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.ai.mcp.server.protocol=STREAMABLE") .withConfiguration(AutoConfigurations.of(McpServerStreamableHttpWebMvcAutoConfiguration.class)); @Test diff --git a/pom.xml b/pom.xml index a1d409acfc5..a44fcae64bb 100644 --- a/pom.xml +++ b/pom.xml @@ -119,14 +119,9 @@ auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux - auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-properties auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common - auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-sse - auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webflux - auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-streamable-webmvc - auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-common - auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webflux - auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-stateless-webmvc + auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webmvc + auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure auto-configurations/vector-stores/spring-ai-autoconfigure-vector-store-azure-cosmos-db @@ -223,11 +218,6 @@ spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-webflux spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-webmvc - spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-streamable-webflux - spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-streamable-webmvc - spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-stateless-webflux - spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-stateless-webmvc - spring-ai-integration-tests mcp/common diff --git a/spring-ai-bom/pom.xml b/spring-ai-bom/pom.xml index 7f3a0fa44fd..54969e6c314 100644 --- a/spring-ai-bom/pom.xml +++ b/spring-ai-bom/pom.xml @@ -551,43 +551,13 @@ org.springframework.ai - spring-ai-autoconfigure-mcp-server-sse + spring-ai-autoconfigure-mcp-server-webmvc ${project.version} org.springframework.ai - spring-ai-autoconfigure-mcp-server-properties - ${project.version} - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-streamable-webflux - ${project.version} - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-streamable-webmvc - ${project.version} - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-stateless-common - ${project.version} - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-stateless-webflux - ${project.version} - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-stateless-webmvc + spring-ai-autoconfigure-mcp-server-webflux ${project.version} @@ -1092,32 +1062,6 @@ ${project.version} - - org.springframework.ai - spring-ai-starter-mcp-server-streamable-webflux - ${project.version} - - - - - org.springframework.ai - spring-ai-starter-mcp-server-streamable-webmvc - ${project.version} - - - - org.springframework.ai - spring-ai-starter-mcp-server-stateless-webflux - ${project.version} - - - - - org.springframework.ai - spring-ai-starter-mcp-server-stateless-webmvc - ${project.version} - - diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-server-boot-starter-docs.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-server-boot-starter-docs.adoc index f1120f7e55d..d73679c0b08 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-server-boot-starter-docs.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-server-boot-starter-docs.adoc @@ -15,16 +15,22 @@ The MCP Server Boot Starters offer: * Flexible tool, resource, and prompt specification * Change notification capabilities -== Sync/Async Server API Options - -* **Synchronous Server** - The default server type implemented using `McpSyncServer`. -It is designed for straightforward request-response patterns in your applications. -To enable this server type, set `spring.ai.mcp.server.type=SYNC` in your configuration. -When activated, it automatically handles the configuration of synchronous tool specifications. - -* **Asynchronous Server** - The asynchronous server implementation uses `McpAsyncServer` and is optimized for non-blocking operations. -To enable this server type, configure your application with `spring.ai.mcp.server.type=ASYNC`. -This server type automatically sets up asynchronous tool specifications with built-in Project Reactor support. +== MCP Server Boot Starters + +MCP Servers support multiple protocol and transport mechanisms. +Use the dedicated starter and the correct `spring.ai.mcp.server.protocol` property to configure your server: + +[options="header"] +|=== +|Server Type | Dependency | Property +| xref:api/mcp/mcp-stdio-sse-server-boot-starter-docs.adoc[Standard Input/Output (STDIO)] | `spring-ai-starter-mcp-server` | `spring.ai.mcp.server.stdio=true` +| xref:api/mcp/mcp-stdio-sse-server-boot-starter-docs.adoc#_sse_webmvc_serve[SSE Spring MVC] | `spring-ai-starter-mcp-server-webmvc` | `spring.ai.mcp.server.protocol=SSE` or empty +| xref:api/mcp/mcp-stdio-sse-server-boot-starter-docs.adoc#_sse_webflux_serve[SSE Spring WebFlux (Reactive)] | `spring-ai-starter-mcp-server-webflux` | `spring.ai.mcp.server.protocol=SSE` or empty +| xref:api/mcp/mcp-streamable-http-server-boot-starter-docs.adoc#_streamable_http_webmvc_server[Streamable-HTTP Spring MVC] | `spring-ai-starter-mcp-server-webmvc` | `spring.ai.mcp.server.protocol=STREAMABLE` +| xref:api/mcp/mcp-streamable-http-server-boot-starter-docs.adoc#_streamable_http_webflux_server[Streamable-HTTP Spring WebFlux (Reactive)] | `spring-ai-starter-mcp-server-webflux` | `spring.ai.mcp.server.protocol=STREAMABLE` +| xref:api/mcp/mcp-stateless-server-boot-starter-docs.adoc#_stateless_webmvc_server[Stateless Spring MVC] | `spring-ai-starter-mcp-server-webmvc` | `spring.ai.mcp.server.protocol=STATLESS` +| xref:api/mcp/mcp-stateless-server-boot-starter-docs.adoc#_stateless_webflux_server[Stateless Spring WebFlux (Reactive)] | `spring-ai-starter-mcp-server-webflux` | `spring.ai.mcp.server.protocol=STATLESS` +|=== == Server Capabilities @@ -40,23 +46,28 @@ Depending on the server and transport types, MCP Servers can support various cap All capabilities are enabled by default. Disabling a capability will prevent the server from registering and exposing the corresponding features to clients. -== Transport Options +== Server Protocols -MCP Servers support multiple transport mechanisms, each with its dedicated starter: +MCP provides several protocol types including: -* Standard Input/Output (STDIO) - `spring-ai-starter-mcp-server` -* SSE Spring MVC - `spring-ai-starter-mcp-server-webmvc` -* SSE Spring WebFlux (Reactive) - `spring-ai-starter-mcp-server-webflux` -* Streamable-HTTP Spring MVC - `spring-ai-starter-mcp-server-streamable-webmvc` -* Streamable-HTTP Spring WebFlux (Reactive) - `spring-ai-starter-mcp-server-streamable-webflux` -* Stateless Spring MVC - `spring-ai-starter-mcp-server-stateless-webmvc` -* Stateless Spring WebFlux (Reactive) - `spring-ai-starter-mcp-server-stateless-webflux` +* xref:api/mcp/mcp-stdio-sse-server-boot-starter-docs.adoc[**STDIO**] - In process (e.g. server runs inside the host application) protocol. Communication is over standard in and standard out. To enable the `STDIO` set `spring.ai.mcp.server.stdio=true`. +* xref:api/mcp/mcp-stdio-sse-server-boot-starter-docs.adoc#_sse_webmvc_server[**SSE**] - Server-sent events protocol for real-time updates. The server operates as an independent process that can handle multiple client connections. +* xref:api/mcp/mcp-streamable-http-server-boot-starter-docs.adoc[**Streamable-HTTP**] - The link:https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http[Streamable HTTP transport] allows MCP servers to operate as independent processes that can handle multiple client connections using HTTP POST and GET requests, with optional Server-Sent Events (SSE) streaming for multiple server messages. It replaces the SSE transport. To enable the `STREAMABLE` protocol, set `spring.ai.mcp.server.protocol=STREAMABLE`. +* xref:api/mcp/mcp-stateless-server-boot-starter-docs.adoc[**Stateless**] - Stateless MCP servers are designed for simplified deployments where session state is not maintained between requests. +They are ideal for microservices architectures and cloud-native deployments. To enable the `STATELESS` protocol, set `spring.ai.mcp.server.protocol=STATELESS`. -Choose one of the following starters based on your transport and feature requirements: +== Sync/Async Server API Options + +The MCP Server API supports imperative (e.g. synchronous) and reactive (e.g. asynchronous) programming models. + +* **Synchronous Server** - The default server type implemented using `McpSyncServer`. +It is designed for straightforward request-response patterns in your applications. +To enable this server type, set `spring.ai.mcp.server.type=SYNC` in your configuration. +When activated, it automatically handles the configuration of synchronous tool specifications. -- xref:api/mcp/mcp-stdio-sse-server-boot-starter-docs.adoc[STDIO and SSE MCP Servers] -- xref:api/mcp/mcp-streamable-http-server-boot-starter-docs.adoc[Streamable-HTTP MCP Servers] -- xref:api/mcp/mcp-stateless-server-boot-starter-docs.adoc[Stateless MCP Servers] +* **Asynchronous Server** - The asynchronous server implementation uses `McpAsyncServer` and is optimized for non-blocking operations. +To enable this server type, configure your application with `spring.ai.mcp.server.type=ASYNC`. +This server type automatically sets up asynchronous tool specifications with built-in Project Reactor support. == Example Applications diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-stateless-server-boot-starter-docs.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-stateless-server-boot-starter-docs.adoc index eab8dae49c5..a0017ef326e 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-stateless-server-boot-starter-docs.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-stateless-server-boot-starter-docs.adoc @@ -4,20 +4,30 @@ Stateless MCP servers are designed for simplified deployments where session state is not maintained between requests. These servers are ideal for microservices architectures and cloud-native deployments. +TIP: Set the `spring.ai.mcp.server.protocol=STATELESS` property + TIP: Use the xref:api/mcp/mcp-client-boot-starter-docs#_streamable_http_transport_properties[Streamable-HTTP clients] to connect to the stateless servers. NOTE: The stateless servers don't support message requests to the MCP client (e.g., elicitation, sampling, ping). === Stateless WebMVC Server +Use the `spring-ai-starter-mcp-server-webmvc` dependency: + [source,xml] ---- org.springframework.ai - spring-ai-starter-mcp-server-stateless-webmvc + spring-ai-starter-mcp-server-webmvc ---- +and set the `spring.ai.mcp.server.protocol` property to `STATLESS`. + +---- +spring.ai.mcp.server.protocol=STATLESS +---- + - Stateless operation with Spring MVC transport - No session state management - Simplified deployment model @@ -25,14 +35,18 @@ NOTE: The stateless servers don't support message requests to the MCP client (e. === Stateless WebFlux Server +Use the `spring-ai-starter-mcp-server-webflux` dependency: + [source,xml] ---- org.springframework.ai - spring-ai-starter-mcp-server-stateless-webflux + spring-ai-starter-mcp-server-webflux ---- +and set the `spring.ai.mcp.server.protocol` property to `STATLESS`. + - Reactive stateless operation with WebFlux transport - No session state management - Non-blocking request processing @@ -48,6 +62,7 @@ All Common properties are prefixed with `spring.ai.mcp.server`: |=== |Property |Description |Default |`enabled` |Enable/disable the stateless MCP server |`true` +|`protocol` |MCP server protocol | Must be set to `STATLESS` to enable the stateless server |`tool-callback-converter` |Enable/disable the conversion of Spring AI ToolCallbacks into MCP Tool specs |`true` |`name` |Server name for identification |`mcp-server` |`version` |Server version |`1.0.0` @@ -207,6 +222,7 @@ spring: ai: mcp: server: + protocol: STATELESS name: stateless-mcp-server version: 1.0.0 type: ASYNC diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-streamable-http-server-boot-starter-docs.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-streamable-http-server-boot-starter-docs.adoc index f31ed7af179..d462de43c06 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-streamable-http-server-boot-starter-docs.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/mcp/mcp-streamable-http-server-boot-starter-docs.adoc @@ -1,35 +1,46 @@ == Streamable-HTTP MCP Servers -link:https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http[Streamable-HTTP] MCP servers provide enhanced functionality with support for change notifications and persistent connections. +The link:https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http[Streamable HTTP transport] allows MCP servers to operate as independent processes that can handle multiple client connections using HTTP POST and GET requests, with optional Server-Sent Events (SSE) streaming for multiple server messages. It replaces the SSE transport. + These servers, introduced with spec version link:https://modelcontextprotocol.io/specification/2025-03-26[2025-03-26], are ideal for applications that need to notify clients about dynamic changes to tools, resources, or prompts. +TIP: Set the `spring.ai.mcp.server.protocol=STREAMABLE` property + TIP: Use the xref:api/mcp/mcp-client-boot-starter-docs#_streamable_http_transport_properties[Streamable-HTTP clients] to connect to the Streamable-HTTP servers. === Streamable-HTTP WebMVC Server +Use the `spring-ai-starter-mcp-server-webmvc` dependency: + [source,xml] ---- org.springframework.ai - spring-ai-starter-mcp-server-streamable-webmvc + spring-ai-starter-mcp-server-webmvc ---- +and set the `spring.ai.mcp.server.protocol` property to `STREAMABLE`. + * Full MCP server capabilities with Spring MVC Streamable transport * Suppport for tools, resources, prompts, completion, logging, progression, ping, root-changes capabilities * Persistent connection management === Streamable-HTTP WebFlux Server +Use the `spring-ai-starter-mcp-server-webflux` dependency: + [source,xml] ---- org.springframework.ai - spring-ai-starter-mcp-server-streamable-webflux + spring-ai-starter-mcp-server-webflux ---- +and set the `spring.ai.mcp.server.protocol` property to `STREAMABLE`. + * Reactive MCP server with WebFlux Streamable transport * Suppport for tools, resources, prompts, completion, logging, progression, ping, root-changes capabilities * Non-blocking, persistent connection management @@ -44,6 +55,7 @@ All common properties are prefixed with `spring.ai.mcp.server`: |=== |Property |Description |Default |`enabled` |Enable/disable the streamable MCP server |`true` +|`protocol` |MCP server protocol | Must be set to `STREAMABLE` to enable the streamable server |`tool-callback-converter` |Enable/disable the conversion of Spring AI ToolCallbacks into MCP Tool specs |`true` |`name` |Server name for identification |`mcp-server` |`version` |Server version |`1.0.0` @@ -319,7 +331,8 @@ NOTE: Currently, for streamable-http servers, the keep-alive mechanism is availa spring: ai: mcp: - server: + server: + protocol: STREAMABLE name: streamable-mcp-server version: 1.0.0 type: SYNC diff --git a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-stateless-webflux/pom.xml b/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-stateless-webflux/pom.xml deleted file mode 100644 index dd9d22e4146..00000000000 --- a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-stateless-webflux/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - 4.0.0 - - org.springframework.ai - spring-ai-parent - 1.1.0-SNAPSHOT - ../../pom.xml - - spring-ai-starter-mcp-server-stateless-webflux - jar - Spring AI Starter - MCP Server Stateless Webflux - Spring AI MCP Server Stateless WebFlux Spring Boot Starter - https://github.com/spring-projects/spring-ai - - - https://github.com/spring-projects/spring-ai - git://github.com/spring-projects/spring-ai.git - git@github.com:spring-projects/spring-ai.git - - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-stateless-webflux - ${project.parent.version} - - - - org.springframework.ai - spring-ai-mcp - ${project.parent.version} - - - - io.modelcontextprotocol.sdk - mcp-spring-webflux - - - - org.springframework.boot - spring-boot-starter-webflux - - - - - - diff --git a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-stateless-webmvc/pom.xml b/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-stateless-webmvc/pom.xml deleted file mode 100644 index 2c3e75a6da0..00000000000 --- a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-stateless-webmvc/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - 4.0.0 - - org.springframework.ai - spring-ai-parent - 1.1.0-SNAPSHOT - ../../pom.xml - - spring-ai-starter-mcp-server-stateless-webmvc - jar - Spring AI Starter - MCP Server Stateless WebMVC - Spring AI MCP Server Stateless WebMVC Spring Boot Starter - https://github.com/spring-projects/spring-ai - - - https://github.com/spring-projects/spring-ai - git://github.com/spring-projects/spring-ai.git - git@github.com:spring-projects/spring-ai.git - - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-stateless-webmvc - ${project.parent.version} - - - - org.springframework.ai - spring-ai-mcp - ${project.parent.version} - - - - io.modelcontextprotocol.sdk - mcp-spring-webmvc - - - - - diff --git a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-streamable-webflux/pom.xml b/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-streamable-webflux/pom.xml deleted file mode 100644 index acaffa3dd20..00000000000 --- a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-streamable-webflux/pom.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - 4.0.0 - - org.springframework.ai - spring-ai-parent - 1.1.0-SNAPSHOT - ../../pom.xml - - spring-ai-starter-mcp-server-streamable-webflux - jar - Spring AI Starter - MCP Server Streamable Webflux - Spring AI MCP Server Streamable WebFlux Spring Boot Starter - https://github.com/spring-projects/spring-ai - - - https://github.com/spring-projects/spring-ai - git://github.com/spring-projects/spring-ai.git - git@github.com:spring-projects/spring-ai.git - - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-streamable-webflux - ${project.parent.version} - - - - org.springframework.ai - spring-ai-mcp - ${project.parent.version} - - - - io.modelcontextprotocol.sdk - mcp-spring-webflux - - - - org.springframework.boot - spring-boot-starter-webflux - - - - - - diff --git a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-streamable-webmvc/pom.xml b/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-streamable-webmvc/pom.xml deleted file mode 100644 index d97989dc3a0..00000000000 --- a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-streamable-webmvc/pom.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - 4.0.0 - - org.springframework.ai - spring-ai-parent - 1.1.0-SNAPSHOT - ../../pom.xml - - spring-ai-starter-mcp-server-streamable-webmvc - jar - Spring AI Starter - MCP Server Streamable WebMVC - Spring AI MCP Server Streamable WebMVC Spring Boot Starter - https://github.com/spring-projects/spring-ai - - - https://github.com/spring-projects/spring-ai - git://github.com/spring-projects/spring-ai.git - git@github.com:spring-projects/spring-ai.git - - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.ai - spring-ai-autoconfigure-mcp-server-streamable-webmvc - ${project.parent.version} - - - - org.springframework.ai - spring-ai-mcp - ${project.parent.version} - - - - io.modelcontextprotocol.sdk - mcp-spring-webmvc - - - - - diff --git a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-webflux/pom.xml b/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-webflux/pom.xml index aa8808db939..cb7a4fcd628 100644 --- a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-webflux/pom.xml +++ b/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-webflux/pom.xml @@ -46,7 +46,7 @@ org.springframework.ai - spring-ai-autoconfigure-mcp-server-sse + spring-ai-autoconfigure-mcp-server-webflux ${project.parent.version} diff --git a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-webmvc/pom.xml b/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-webmvc/pom.xml index 9fc6b8a9195..4e8a055d941 100644 --- a/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-webmvc/pom.xml +++ b/spring-ai-spring-boot-starters/spring-ai-starter-mcp-server-webmvc/pom.xml @@ -46,7 +46,7 @@ org.springframework.ai - spring-ai-autoconfigure-mcp-server-sse + spring-ai-autoconfigure-mcp-server-webmvc ${project.parent.version} From 348846266b89b20716c1da20b2a0afc835a0a283 Mon Sep 17 00:00:00 2001 From: Christian Tzolov Date: Thu, 21 Aug 2025 13:05:33 +0200 Subject: [PATCH 2/2] minor Signed-off-by: Christian Tzolov --- .../common/autoconfigure/McpServerAutoConfiguration.java | 2 +- .../McpServerStatelessAutoConfiguration.java | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfiguration.java index 99a09940148..b7d78a9fd93 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerAutoConfiguration.java @@ -77,7 +77,7 @@ "org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebMvcAutoConfiguration", "org.springframework.ai.mcp.server.autoconfigure.McpServerStreamableHttpWebMvcAutoConfiguration", "org.springframework.ai.mcp.server.autoconfigure.McpServerStreamableHttpWebFluxAutoConfiguration" }) -@ConditionalOnClass({ McpSchema.class, McpSyncServer.class }) +@ConditionalOnClass({ McpSchema.class }) @EnableConfigurationProperties({ McpServerProperties.class, McpServerChangeNotificationProperties.class }) @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerStatelessAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerStatelessAutoConfiguration.java index 93bc5e01a52..c212bf40133 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerStatelessAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/McpServerStatelessAutoConfiguration.java @@ -29,7 +29,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; -import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase; import org.springframework.core.env.Environment; import org.springframework.core.log.LogAccessor; import org.springframework.util.CollectionUtils; @@ -55,10 +54,10 @@ /** * @author Christian Tzolov */ -@AutoConfiguration( - afterName = { "org.springframework.ai.mcp.server.autoconfigure.StatelessToolCallbackConverterAutoConfiguration", - "org.springframework.ai.mcp.server.autoconfigure.McpServerStatelessWebFluxAutoConfiguration", - "org.springframework.ai.mcp.server.autoconfigure.McpServerStatelessWebMvcAutoConfiguration" }) +@AutoConfiguration(afterName = { + "org.springframework.ai.mcp.server.common.autoconfigure.StatelessToolCallbackConverterAutoConfiguration", + "org.springframework.ai.mcp.server.autoconfigure.McpServerStatelessWebFluxAutoConfiguration", + "org.springframework.ai.mcp.server.autoconfigure.McpServerStatelessWebMvcAutoConfiguration" }) @ConditionalOnClass({ McpSchema.class }) @EnableConfigurationProperties(McpServerProperties.class) @Conditional({ McpServerStdioDisabledCondition.class,