1414 * limitations under the License.
1515 */
1616
17- package org .springframework .ai .mcp .server .autoconfigure ;
17+ package org .springframework .ai .mcp .server .common . autoconfigure ;
1818
1919import java .util .ArrayList ;
2020import java .util .List ;
2121import java .util .function .BiConsumer ;
2222import java .util .function .BiFunction ;
2323
24- import org .springframework .ai .tool .ToolCallback ;
24+ import org .springframework .ai .mcp .server .common .autoconfigure .properties .McpServerChangeNotificationProperties ;
25+ import org .springframework .ai .mcp .server .common .autoconfigure .properties .McpServerProperties ;
26+ import org .springframework .ai .mcp .server .common .autoconfigure .properties .McpServerStreamableHttpProperties ;
2527import org .springframework .beans .factory .ObjectProvider ;
2628import org .springframework .boot .autoconfigure .AutoConfiguration ;
2729import org .springframework .boot .autoconfigure .EnableAutoConfiguration ;
30+ import org .springframework .boot .autoconfigure .condition .AllNestedConditions ;
2831import org .springframework .boot .autoconfigure .condition .ConditionalOnClass ;
2932import org .springframework .boot .autoconfigure .condition .ConditionalOnMissingBean ;
3033import org .springframework .boot .autoconfigure .condition .ConditionalOnProperty ;
3134import org .springframework .boot .context .properties .EnableConfigurationProperties ;
3235import org .springframework .context .annotation .Bean ;
36+ import org .springframework .context .annotation .Conditional ;
3337import org .springframework .core .env .Environment ;
3438import org .springframework .core .log .LogAccessor ;
3539import org .springframework .util .CollectionUtils ;
5458import io .modelcontextprotocol .spec .McpSchema ;
5559import io .modelcontextprotocol .spec .McpSchema .Implementation ;
5660import io .modelcontextprotocol .spec .McpServerTransportProvider ;
61+ import io .modelcontextprotocol .spec .McpServerTransportProviderBase ;
62+ import io .modelcontextprotocol .spec .McpStreamableServerTransportProvider ;
5763import reactor .core .publisher .Mono ;
5864
5965/**
6066 * {@link EnableAutoConfiguration Auto-configuration} for the Model Context Protocol (MCP)
6167 * Server.
6268 * <p>
63- * This configuration class sets up the core MCP server components with support for both
64- * synchronous and asynchronous operation modes. The server type is controlled through the
65- * {@code spring.ai.mcp.server.type} property, defaulting to SYNC mode.
66- * <p>
67- * Core features and capabilities include:
68- * <ul>
69- * <li>Tools: Extensible tool registration system supporting both sync and async
70- * execution</li>
71- * <li>Resources: Static and dynamic resource management with optional change
72- * notifications</li>
73- * <li>Prompts: Configurable prompt templates with change notification support</li>
74- * <li>Transport: Flexible transport layer with built-in support for:
75- * <ul>
76- * <li>STDIO (default): Standard input/output based communication</li>
77- * <li>WebMvc: HTTP-based transport when Spring MVC is available</li>
78- * <li>WebFlux: Reactive transport when Spring WebFlux is available</li>
79- * </ul>
80- * </li>
81- * </ul>
82- * <p>
83- * The configuration is activated when:
84- * <ul>
85- * <li>The required MCP classes ({@link McpSchema} and {@link McpSyncServer}) are on the
86- * classpath</li>
87- * <li>The {@code spring.ai.mcp.server.enabled} property is true (default)</li>
88- * </ul>
89- * <p>
90- * Server configuration is managed through {@link McpServerProperties} with support for:
91- * <ul>
92- * <li>Server identification (name, version)</li>
93- * <li>Transport selection</li>
94- * <li>Change notification settings for tools, resources, and prompts</li>
95- * <li>Sync/Async operation mode selection</li>
96- * </ul>
97- * <p>
98- * WebMvc transport support is provided separately by
99- * {@link McpWebMvcServerAutoConfiguration}.
10069 *
10170 * @author Christian Tzolov
10271 * @since 1.0.0
10372 * @see McpServerProperties
104- * @see McpWebMvcServerAutoConfiguration
105- * @see McpWebFluxServerAutoConfiguration
106- * @see ToolCallback
10773 */
108- @ AutoConfiguration (after = { ToolCallbackConverterAutoConfiguration .class , McpWebMvcServerAutoConfiguration .class ,
109- McpWebFluxServerAutoConfiguration .class })
74+ @ AutoConfiguration (afterName = {
75+ "org.springframework.ai.mcp.server.common.autoconfigure.ToolCallbackConverterAutoConfiguration" ,
76+ "org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebFluxAutoConfiguration" ,
77+ "org.springframework.ai.mcp.server.autoconfigure.McpServerSseWebMvcAutoConfiguration" ,
78+ "org.springframework.ai.mcp.server.streamable.webflux.autoconfigure.McpServerStreamableHttpWebMvcAutoConfiguration" ,
79+ "org.springframework.ai.mcp.server.streamable.webflux.autoconfigure.McpServerStreamableHttpWebFluxAutoConfiguration" })
11080@ ConditionalOnClass ({ McpSchema .class , McpSyncServer .class })
111- @ EnableConfigurationProperties (McpServerProperties .class )
81+ @ EnableConfigurationProperties ({ McpServerProperties .class , McpServerChangeNotificationProperties . class } )
11282@ ConditionalOnProperty (prefix = McpServerProperties .CONFIG_PREFIX , name = "enabled" , havingValue = "true" ,
11383 matchIfMissing = true )
11484public class McpServerAutoConfiguration {
11585
11686 private static final LogAccessor logger = new LogAccessor (McpServerAutoConfiguration .class );
11787
88+ public static class EnabledNonStatlessServerCondition extends AllNestedConditions {
89+
90+ public EnabledNonStatlessServerCondition () {
91+ super (ConfigurationPhase .PARSE_CONFIGURATION );
92+ }
93+
94+ @ ConditionalOnProperty (prefix = McpServerProperties .CONFIG_PREFIX , name = "enabled" , havingValue = "true" ,
95+ matchIfMissing = true )
96+ static class McpServerEnabledCondition {
97+
98+ }
99+
100+ @ ConditionalOnProperty (prefix = McpServerStreamableHttpProperties .CONFIG_PREFIX , name = "stateless" ,
101+ havingValue = "false" , matchIfMissing = true )
102+ static class StatelessEnabledCondition {
103+
104+ }
105+
106+ }
107+
118108 @ Bean
119109 @ ConditionalOnMissingBean
120- public McpServerTransportProvider stdioServerTransport () {
110+ public McpServerTransportProviderBase stdioServerTransport () {
121111 return new StdioServerTransportProvider ();
122112 }
123113
@@ -130,8 +120,9 @@ public McpSchema.ServerCapabilities.Builder capabilitiesBuilder() {
130120 @ Bean
131121 @ ConditionalOnProperty (prefix = McpServerProperties .CONFIG_PREFIX , name = "type" , havingValue = "SYNC" ,
132122 matchIfMissing = true )
133- public McpSyncServer mcpSyncServer (McpServerTransportProvider transportProvider ,
123+ public McpSyncServer mcpSyncServer (McpServerTransportProviderBase transportProvider ,
134124 McpSchema .ServerCapabilities .Builder capabilitiesBuilder , McpServerProperties serverProperties ,
125+ McpServerChangeNotificationProperties changeNotificationProperties ,
135126 ObjectProvider <List <SyncToolSpecification >> tools ,
136127 ObjectProvider <List <SyncResourceSpecification >> resources ,
137128 ObjectProvider <List <SyncPromptSpecification >> prompts ,
@@ -143,12 +134,20 @@ public McpSyncServer mcpSyncServer(McpServerTransportProvider transportProvider,
143134 serverProperties .getVersion ());
144135
145136 // Create the server with both tool and resource capabilities
146- SyncSpecification serverBuilder = McpServer .sync (transportProvider ).serverInfo (serverInfo );
137+ SyncSpecification <?> serverBuilder ;
138+ if (transportProvider instanceof McpStreamableServerTransportProvider ) {
139+ serverBuilder = McpServer .sync ((McpStreamableServerTransportProvider ) transportProvider );
140+ }
141+ else {
142+ serverBuilder = McpServer .sync ((McpServerTransportProvider ) transportProvider );
143+ }
144+ serverBuilder .serverInfo (serverInfo );
147145
148146 // Tools
149147 if (serverProperties .getCapabilities ().isTool ()) {
150- logger .info ("Enable tools capabilities, notification: " + serverProperties .isToolChangeNotification ());
151- capabilitiesBuilder .tools (serverProperties .isToolChangeNotification ());
148+ logger .info ("Enable tools capabilities, notification: "
149+ + changeNotificationProperties .isToolChangeNotification ());
150+ capabilitiesBuilder .tools (changeNotificationProperties .isToolChangeNotification ());
152151
153152 List <SyncToolSpecification > toolSpecifications = new ArrayList <>(
154153 tools .stream ().flatMap (List ::stream ).toList ());
@@ -161,9 +160,9 @@ public McpSyncServer mcpSyncServer(McpServerTransportProvider transportProvider,
161160
162161 // Resources
163162 if (serverProperties .getCapabilities ().isResource ()) {
164- logger .info (
165- "Enable resources capabilities, notification: " + serverProperties .isResourceChangeNotification ());
166- capabilitiesBuilder .resources (false , serverProperties .isResourceChangeNotification ());
163+ logger .info ("Enable resources capabilities, notification: "
164+ + changeNotificationProperties .isResourceChangeNotification ());
165+ capabilitiesBuilder .resources (false , changeNotificationProperties .isResourceChangeNotification ());
167166
168167 List <SyncResourceSpecification > resourceSpecifications = resources .stream ().flatMap (List ::stream ).toList ();
169168 if (!CollectionUtils .isEmpty (resourceSpecifications )) {
@@ -174,8 +173,9 @@ public McpSyncServer mcpSyncServer(McpServerTransportProvider transportProvider,
174173
175174 // Prompts
176175 if (serverProperties .getCapabilities ().isPrompt ()) {
177- logger .info ("Enable prompts capabilities, notification: " + serverProperties .isPromptChangeNotification ());
178- capabilitiesBuilder .prompts (serverProperties .isPromptChangeNotification ());
176+ logger .info ("Enable prompts capabilities, notification: "
177+ + changeNotificationProperties .isPromptChangeNotification ());
178+ capabilitiesBuilder .prompts (changeNotificationProperties .isPromptChangeNotification ());
179179
180180 List <SyncPromptSpecification > promptSpecifications = prompts .stream ().flatMap (List ::stream ).toList ();
181181 if (!CollectionUtils .isEmpty (promptSpecifications )) {
@@ -219,8 +219,9 @@ public McpSyncServer mcpSyncServer(McpServerTransportProvider transportProvider,
219219
220220 @ Bean
221221 @ ConditionalOnProperty (prefix = McpServerProperties .CONFIG_PREFIX , name = "type" , havingValue = "ASYNC" )
222- public McpAsyncServer mcpAsyncServer (McpServerTransportProvider transportProvider ,
222+ public McpAsyncServer mcpAsyncServer (McpServerTransportProviderBase transportProvider ,
223223 McpSchema .ServerCapabilities .Builder capabilitiesBuilder , McpServerProperties serverProperties ,
224+ McpServerChangeNotificationProperties changeNotificationProperties ,
224225 ObjectProvider <List <AsyncToolSpecification >> tools ,
225226 ObjectProvider <List <AsyncResourceSpecification >> resources ,
226227 ObjectProvider <List <AsyncPromptSpecification >> prompts ,
@@ -231,15 +232,23 @@ public McpAsyncServer mcpAsyncServer(McpServerTransportProvider transportProvide
231232 serverProperties .getVersion ());
232233
233234 // Create the server with both tool and resource capabilities
234- AsyncSpecification serverBuilder = McpServer .async (transportProvider ).serverInfo (serverInfo );
235+ AsyncSpecification <?> serverBuilder ;
236+ if (transportProvider instanceof McpStreamableServerTransportProvider ) {
237+ serverBuilder = McpServer .async ((McpStreamableServerTransportProvider ) transportProvider );
238+ }
239+ else {
240+ serverBuilder = McpServer .async ((McpServerTransportProvider ) transportProvider );
241+ }
242+ serverBuilder .serverInfo (serverInfo );
235243
236244 // Tools
237245 if (serverProperties .getCapabilities ().isTool ()) {
238246 List <AsyncToolSpecification > toolSpecifications = new ArrayList <>(
239247 tools .stream ().flatMap (List ::stream ).toList ());
240248
241- logger .info ("Enable tools capabilities, notification: " + serverProperties .isToolChangeNotification ());
242- capabilitiesBuilder .tools (serverProperties .isToolChangeNotification ());
249+ logger .info ("Enable tools capabilities, notification: "
250+ + changeNotificationProperties .isToolChangeNotification ());
251+ capabilitiesBuilder .tools (changeNotificationProperties .isToolChangeNotification ());
243252
244253 if (!CollectionUtils .isEmpty (toolSpecifications )) {
245254 serverBuilder .tools (toolSpecifications );
@@ -249,9 +258,9 @@ public McpAsyncServer mcpAsyncServer(McpServerTransportProvider transportProvide
249258
250259 // Resources
251260 if (serverProperties .getCapabilities ().isResource ()) {
252- logger .info (
253- "Enable resources capabilities, notification: " + serverProperties .isResourceChangeNotification ());
254- capabilitiesBuilder .resources (false , serverProperties .isResourceChangeNotification ());
261+ logger .info ("Enable resources capabilities, notification: "
262+ + changeNotificationProperties .isResourceChangeNotification ());
263+ capabilitiesBuilder .resources (false , changeNotificationProperties .isResourceChangeNotification ());
255264
256265 List <AsyncResourceSpecification > resourceSpecifications = resources .stream ().flatMap (List ::stream ).toList ();
257266 if (!CollectionUtils .isEmpty (resourceSpecifications )) {
@@ -262,8 +271,9 @@ public McpAsyncServer mcpAsyncServer(McpServerTransportProvider transportProvide
262271
263272 // Prompts
264273 if (serverProperties .getCapabilities ().isPrompt ()) {
265- logger .info ("Enable prompts capabilities, notification: " + serverProperties .isPromptChangeNotification ());
266- capabilitiesBuilder .prompts (serverProperties .isPromptChangeNotification ());
274+ logger .info ("Enable prompts capabilities, notification: "
275+ + changeNotificationProperties .isPromptChangeNotification ());
276+ capabilitiesBuilder .prompts (changeNotificationProperties .isPromptChangeNotification ());
267277 List <AsyncPromptSpecification > promptSpecifications = prompts .stream ().flatMap (List ::stream ).toList ();
268278
269279 if (!CollectionUtils .isEmpty (promptSpecifications )) {
0 commit comments