diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/pom.xml b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/pom.xml index f8d1d3509b5..ad5c54b933d 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/pom.xml +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/pom.xml @@ -68,7 +68,11 @@ test - + + jakarta.servlet + jakarta.servlet-api + provided + diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpHttpServletStreamableServerAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpHttpServletStreamableServerAutoConfiguration.java new file mode 100644 index 00000000000..9bc05ba43b5 --- /dev/null +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpHttpServletStreamableServerAutoConfiguration.java @@ -0,0 +1,86 @@ +/* + * 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.autoconfigure; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.modelcontextprotocol.server.transport.HttpServletStreamableServerTransportProvider; +import io.modelcontextprotocol.spec.McpServerTransportProvider; +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.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; + +/** + * {@link AutoConfiguration Auto-configuration} for MCP HttpServlet Streamable Server + * Transport. + *

+ * This configuration class sets up the HttpServlet-specific Streamable transport + * components for the MCP server, providing HTTP streaming communication through standard + * Java Servlet API. It is activated when: + *

+ *

+ * The configuration provides: + *

+ *

+ * This configuration has the lowest priority and will only be activated if no WebFlux or + * WebMVC streamable transports are available. + *

+ * Required dependencies:

{@code
+ * 
+ *     io.modelcontextprotocol.sdk
+ *     mcp-server-http-servlet
+ * 
+ * }
+ * + * @author yinh + * @since 1.0.1 + * @see McpServerProperties + * @see HttpServletStreamableServerTransportProvider + */ +@AutoConfiguration( + after = { McpWebFluxStreamableServerAutoConfiguration.class, McpWebMvcStreamableServerAutoConfiguration.class }) +@ConditionalOnClass({ HttpServletStreamableServerTransportProvider.class }) +@ConditionalOnMissingBean(McpServerTransportProvider.class) +@Conditional(McpServerStreamableTransportCondition.class) +public class McpHttpServletStreamableServerAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public HttpServletStreamableServerTransportProvider httpServletStreamableTransport( + ObjectProvider objectMapperProvider, McpServerProperties serverProperties) { + + ObjectMapper objectMapper = objectMapperProvider.getIfAvailable(ObjectMapper::new); + + // Create an HttpServlet Streamable transport provider using the builder pattern + return HttpServletStreamableServerTransportProvider.builder() + .mcpEndpoint(serverProperties.getSseMessageEndpoint()) + .objectMapper(objectMapper) + .build(); + } + +} diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java index 5c8d9f140ec..76c5423d357 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java @@ -42,6 +42,8 @@ import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpSchema.Implementation; import io.modelcontextprotocol.spec.McpServerTransportProvider; +import io.modelcontextprotocol.spec.McpServerTransportProviderBase; +import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider; import reactor.core.publisher.Mono; import org.springframework.ai.mcp.McpToolUtils; @@ -93,7 +95,7 @@ * Server configuration is managed through {@link McpServerProperties} with support for: * @@ -106,9 +108,14 @@ * @see McpServerProperties * @see McpWebMvcServerAutoConfiguration * @see McpWebFluxServerAutoConfiguration + * @see McpWebMvcStreamableServerAutoConfiguration + * @see McpWebFluxStreamableServerAutoConfiguration + * @see McpHttpServletStreamableServerAutoConfiguration * @see ToolCallback */ -@AutoConfiguration(after = { McpWebMvcServerAutoConfiguration.class, McpWebFluxServerAutoConfiguration.class }) +@AutoConfiguration(after = { McpWebMvcServerAutoConfiguration.class, McpWebFluxServerAutoConfiguration.class, + McpWebMvcStreamableServerAutoConfiguration.class, McpWebFluxStreamableServerAutoConfiguration.class, + McpHttpServletStreamableServerAutoConfiguration.class }) @ConditionalOnClass({ McpSchema.class, McpSyncServer.class }) @EnableConfigurationProperties(McpServerProperties.class) @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", @@ -170,7 +177,7 @@ private List toSyncToolSpecifications(L @Bean @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC", matchIfMissing = true) - public McpSyncServer mcpSyncServer(McpServerTransportProvider transportProvider, + public McpSyncServer mcpSyncServer(McpServerTransportProviderBase transportProvider, McpSchema.ServerCapabilities.Builder capabilitiesBuilder, McpServerProperties serverProperties, ObjectProvider> tools, ObjectProvider> resources, @@ -183,7 +190,14 @@ public McpSyncServer mcpSyncServer(McpServerTransportProvider transportProvider, serverProperties.getVersion()); // Create the server with both tool and resource capabilities - SyncSpecification serverBuilder = McpServer.sync(transportProvider).serverInfo(serverInfo); + SyncSpecification serverBuilder; + if (transportProvider instanceof McpStreamableServerTransportProvider) { + serverBuilder = McpServer.sync((McpStreamableServerTransportProvider) transportProvider); + } + else { + serverBuilder = McpServer.sync((McpServerTransportProvider) transportProvider); + } + serverBuilder.serverInfo(serverInfo); // Tools if (serverProperties.getCapabilities().isTool()) { @@ -300,7 +314,7 @@ private List toAsyncToolSpecification( @Bean @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC") - public McpAsyncServer mcpAsyncServer(McpServerTransportProvider transportProvider, + public McpAsyncServer mcpAsyncServer(McpServerTransportProviderBase transportProvider, McpSchema.ServerCapabilities.Builder capabilitiesBuilder, McpServerProperties serverProperties, ObjectProvider> tools, ObjectProvider> resources, @@ -313,7 +327,14 @@ public McpAsyncServer mcpAsyncServer(McpServerTransportProvider transportProvide serverProperties.getVersion()); // Create the server with both tool and resource capabilities - AsyncSpecification serverBuilder = McpServer.async(transportProvider).serverInfo(serverInfo); + AsyncSpecification serverBuilder; + if (transportProvider instanceof McpStreamableServerTransportProvider) { + serverBuilder = McpServer.async((McpStreamableServerTransportProvider) transportProvider); + } + else { + serverBuilder = McpServer.async((McpServerTransportProvider) transportProvider); + } + serverBuilder.serverInfo(serverInfo); // Tools if (serverProperties.getCapabilities().isTool()) { diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerProperties.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerProperties.java index ebde2ecfff3..9f9cca75af3 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerProperties.java +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerProperties.java @@ -59,6 +59,18 @@ public class McpServerProperties { */ private boolean stdio = false; + /** + * The transport type for web-based communication. + *

+ * Supported transport types: + *

    + *
  • SSE - Server-Sent Events transport (default)
  • + *
  • STREAMABLE - Streamable HTTP transport
  • + *
+ * Only relevant when stdio is disabled. + */ + private TransportType transportType = TransportType.SSE; + /** * The name of the MCP server instance. *

@@ -170,6 +182,23 @@ public enum ServerType { } + /** + * Transport types supported by the MCP server for web communication. + */ + public enum TransportType { + + /** + * Server-Sent Events transport + */ + SSE, + + /** + * Streamable HTTP transport + */ + STREAMABLE + + } + /** * (Optional) response MIME type per tool name. */ diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableTransportCondition.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableTransportCondition.java new file mode 100644 index 00000000000..c5c52b4658c --- /dev/null +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpServerStreamableTransportCondition.java @@ -0,0 +1,37 @@ +package org.springframework.ai.mcp.server.autoconfigure; + +import org.springframework.boot.autoconfigure.condition.AllNestedConditions; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +/** + * This class defines a condition met when the MCP server is enabled, STDIO transport is + * disabled, and STREAMABLE transport type is selected. + * + * @since 1.1.0 + * @author yinh + */ +public class McpServerStreamableTransportCondition extends AllNestedConditions { + + public McpServerStreamableTransportCondition() { + super(ConfigurationPhase.PARSE_CONFIGURATION); + } + + @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", + matchIfMissing = true) + static class McpServerEnabledCondition { + + } + + @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "stdio", havingValue = "false", + matchIfMissing = true) + static class StdioDisabledCondition { + + } + + @ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "transport-type", + havingValue = "STREAMABLE") + static class StreamableTransportCondition { + + } + +} diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxStreamableServerAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxStreamableServerAutoConfiguration.java new file mode 100644 index 00000000000..800d526432c --- /dev/null +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpWebFluxStreamableServerAutoConfiguration.java @@ -0,0 +1,97 @@ +/* + * 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.autoconfigure; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.modelcontextprotocol.server.transport.WebFluxStreamableServerTransportProvider; +import io.modelcontextprotocol.spec.McpServerTransportProvider; +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.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.web.reactive.function.server.RouterFunction; + +/** + * {@link AutoConfiguration Auto-configuration} for MCP WebFlux Streamable Server + * Transport. + *

+ * This configuration class sets up the WebFlux-specific Streamable transport components + * for the MCP server, providing reactive HTTP streaming communication through Spring + * WebFlux. It is activated when: + *

    + *
  • The WebFluxStreamableServerTransportProvider class is on the classpath (from + * mcp-spring-webflux dependency)
  • + *
  • Spring WebFlux's RouterFunction class is available (from + * spring-boot-starter-webflux)
  • + *
  • The MCP server is enabled and STDIO transport is disabled
  • + *
  • The transport type is set to STREAMABLE
  • + *
+ *

+ * The configuration provides: + *

    + *
  • A WebFluxStreamableServerTransportProvider bean for handling reactive HTTP + * streaming communication
  • + *
  • A RouterFunction bean that sets up the reactive streaming endpoint
  • + *
+ *

+ * Required dependencies:

{@code
+ * 
+ *     io.modelcontextprotocol.sdk
+ *     mcp-spring-webflux
+ * 
+ * 
+ *     org.springframework.boot
+ *     spring-boot-starter-webflux
+ * 
+ * }
+ * + * @author yinh + * @since 1.0.1 + * @see McpServerProperties + * @see WebFluxStreamableServerTransportProvider + */ +@AutoConfiguration +@ConditionalOnClass({ WebFluxStreamableServerTransportProvider.class, RouterFunction.class }) +@ConditionalOnMissingBean(McpServerTransportProvider.class) +@Conditional(McpServerStreamableTransportCondition.class) +public class McpWebFluxStreamableServerAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public WebFluxStreamableServerTransportProvider webFluxStreamableTransport( + ObjectProvider objectMapperProvider, McpServerProperties serverProperties) { + + ObjectMapper objectMapper = objectMapperProvider.getIfAvailable(ObjectMapper::new); + + // 使用builder模式创建WebFlux Streamable传输提供者 + return WebFluxStreamableServerTransportProvider.builder() + .messageEndpoint(serverProperties.getSseMessageEndpoint()) + .objectMapper(objectMapper) + .build(); + } + + // Router function for Streamable transport used by Spring WebFlux to start an HTTP + // server. + @Bean + public RouterFunction webfluxMcpStreamableRouterFunction( + WebFluxStreamableServerTransportProvider webFluxStreamableProvider) { + return webFluxStreamableProvider.getRouterFunction(); + } + +} diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpWebMvcStreamableServerAutoConfiguration.java b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpWebMvcStreamableServerAutoConfiguration.java new file mode 100644 index 00000000000..94f94bbe57b --- /dev/null +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/java/org/springframework/ai/mcp/server/autoconfigure/McpWebMvcStreamableServerAutoConfiguration.java @@ -0,0 +1,95 @@ +/* + * 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.autoconfigure; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.modelcontextprotocol.server.transport.WebMvcStreamableServerTransportProvider; +import io.modelcontextprotocol.spec.McpServerTransportProvider; +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.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.web.servlet.function.RouterFunction; +import org.springframework.web.servlet.function.ServerResponse; + +/** + * {@link AutoConfiguration Auto-configuration} for MCP WebMvc Streamable Server + * Transport. + *

+ * This configuration class sets up the WebMvc-specific Streamable transport components + * for the MCP server, providing HTTP streaming communication through Spring MVC. It is + * activated when: + *

    + *
  • The WebMvcStreamableServerTransportProvider class is on the classpath (from + * mcp-spring-webmvc dependency)
  • + *
  • Spring MVC's RouterFunction class is available (from spring-boot-starter-web)
  • + *
  • The MCP server is enabled and STDIO transport is disabled
  • + *
  • The transport type is set to STREAMABLE
  • + *
+ *

+ * The configuration provides: + *

    + *
  • A WebMvcStreamableServerTransportProvider bean for handling HTTP streaming + * communication
  • + *
  • A RouterFunction bean that sets up the streaming endpoint
  • + *
+ *

+ * Required dependencies:

{@code
+ * 
+ *     io.modelcontextprotocol.sdk
+ *     mcp-spring-webmvc
+ * 
+ * 
+ *     org.springframework.boot
+ *     spring-boot-starter-web
+ * 
+ * }
+ * + * @author yinh + * @since 1.1.0 + * @see McpServerProperties + * @see WebMvcStreamableServerTransportProvider + */ +@AutoConfiguration +@ConditionalOnClass({ WebMvcStreamableServerTransportProvider.class, RouterFunction.class }) +@ConditionalOnMissingBean(McpServerTransportProvider.class) +@Conditional(McpServerStreamableTransportCondition.class) +public class McpWebMvcStreamableServerAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public WebMvcStreamableServerTransportProvider webMvcStreamableTransport( + ObjectProvider objectMapperProvider, McpServerProperties serverProperties) { + + ObjectMapper objectMapper = objectMapperProvider.getIfAvailable(ObjectMapper::new); + + // 使用builder模式创建WebMvc Streamable传输提供者 + return WebMvcStreamableServerTransportProvider.builder() + .mcpEndpoint(serverProperties.getSseMessageEndpoint()) + .objectMapper(objectMapper) + .build(); + } + + @Bean + public RouterFunction mvcMcpStreamableRouterFunction( + WebMvcStreamableServerTransportProvider transportProvider) { + return transportProvider.getRouterFunction(); + } + +} diff --git a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index d2faa1cbfe5..dc6a853c220 100644 --- a/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -16,3 +16,6 @@ org.springframework.ai.mcp.server.autoconfigure.McpServerAutoConfiguration org.springframework.ai.mcp.server.autoconfigure.McpWebFluxServerAutoConfiguration org.springframework.ai.mcp.server.autoconfigure.McpWebMvcServerAutoConfiguration +org.springframework.ai.mcp.server.autoconfigure.McpWebMvcStreamableServerAutoConfiguration +org.springframework.ai.mcp.server.autoconfigure.McpWebFluxStreamableServerAutoConfiguration +org.springframework.ai.mcp.server.autoconfigure.McpHttpServletStreamableServerAutoConfiguration