Skip to content

Commit bec5885

Browse files
committed
Update the McpServerAutoConfigurationIT
Signed-off-by: Christian Tzolov <[email protected]>
1 parent 13f4428 commit bec5885

File tree

1 file changed

+221
-1
lines changed

1 file changed

+221
-1
lines changed

auto-configurations/spring-ai-mcp-server/src/test/java/org/springframework/ai/autoconfigure/mcp/server/McpServerAutoConfigurationIT.java

Lines changed: 221 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,30 @@
1616

1717
package org.springframework.ai.autoconfigure.mcp.server;
1818

19+
import com.fasterxml.jackson.core.type.TypeReference;
20+
import io.modelcontextprotocol.client.McpSyncClient;
1921
import io.modelcontextprotocol.server.McpAsyncServer;
22+
import io.modelcontextprotocol.server.McpServerFeatures.AsyncToolRegistration;
23+
import io.modelcontextprotocol.server.McpServerFeatures.SyncToolRegistration;
24+
import io.modelcontextprotocol.server.McpServerFeatures.SyncResourceRegistration;
25+
import io.modelcontextprotocol.server.McpServerFeatures.SyncPromptRegistration;
2026
import io.modelcontextprotocol.server.McpSyncServer;
2127
import io.modelcontextprotocol.server.transport.StdioServerTransport;
28+
import io.modelcontextprotocol.spec.McpSchema;
2229
import io.modelcontextprotocol.spec.ServerMcpTransport;
30+
import org.mockito.Mockito;
2331
import org.junit.jupiter.api.Test;
24-
32+
import org.springframework.ai.mcp.SyncMcpToolCallback;
33+
import org.springframework.ai.tool.ToolCallback;
2534
import org.springframework.boot.autoconfigure.AutoConfigurations;
2635
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
36+
import org.springframework.context.annotation.Bean;
37+
import org.springframework.context.annotation.Configuration;
38+
import reactor.core.publisher.Mono;
39+
40+
import java.util.List;
41+
import java.util.function.Consumer;
42+
import java.util.function.Function;
2743

2844
import static org.assertj.core.api.Assertions.assertThat;
2945

@@ -65,6 +81,36 @@ void asyncConfiguration() {
6581
});
6682
}
6783

84+
@Test
85+
void transportConfiguration() {
86+
this.contextRunner.withUserConfiguration(CustomTransportConfiguration.class).run(context -> {
87+
assertThat(context).hasSingleBean(ServerMcpTransport.class);
88+
assertThat(context.getBean(ServerMcpTransport.class)).isInstanceOf(CustomServerTransport.class);
89+
});
90+
}
91+
92+
@Test
93+
void serverNotificationConfiguration() {
94+
this.contextRunner
95+
.withPropertyValues("spring.ai.mcp.server.tool-change-notification=false",
96+
"spring.ai.mcp.server.resource-change-notification=false")
97+
.run(context -> {
98+
McpServerProperties properties = context.getBean(McpServerProperties.class);
99+
assertThat(properties.isToolChangeNotification()).isFalse();
100+
assertThat(properties.isResourceChangeNotification()).isFalse();
101+
});
102+
}
103+
104+
// @Test
105+
void invalidConfigurationThrowsException() {
106+
this.contextRunner.withPropertyValues("spring.ai.mcp.server.version=invalid-version").run(context -> {
107+
assertThat(context).hasFailed();
108+
assertThat(context).getFailure()
109+
.hasRootCauseInstanceOf(IllegalArgumentException.class)
110+
.hasMessageContaining("Invalid version format");
111+
});
112+
}
113+
68114
@Test
69115
void disabledConfiguration() {
70116
this.contextRunner.withPropertyValues("spring.ai.mcp.server.enabled=false").run(context -> {
@@ -88,4 +134,178 @@ void notificationConfiguration() {
88134
});
89135
}
90136

137+
@Test
138+
void stdioConfiguration() {
139+
this.contextRunner.withPropertyValues("spring.ai.mcp.server.stdio=true").run(context -> {
140+
McpServerProperties properties = context.getBean(McpServerProperties.class);
141+
assertThat(properties.isStdio()).isTrue();
142+
});
143+
}
144+
145+
@Test
146+
void serverCapabilitiesConfiguration() {
147+
this.contextRunner.run(context -> {
148+
assertThat(context).hasSingleBean(McpSchema.ServerCapabilities.Builder.class);
149+
McpSchema.ServerCapabilities.Builder builder = context.getBean(McpSchema.ServerCapabilities.Builder.class);
150+
assertThat(builder).isNotNull();
151+
});
152+
}
153+
154+
@Test
155+
void toolRegistrationConfiguration() {
156+
this.contextRunner.withUserConfiguration(TestToolConfiguration.class).run(context -> {
157+
List<SyncToolRegistration> tools = context.getBean("syncTools", List.class);
158+
assertThat(tools).hasSize(1);
159+
});
160+
}
161+
162+
@Test
163+
void resourceRegistrationConfiguration() {
164+
this.contextRunner.withUserConfiguration(TestResourceConfiguration.class).run(context -> {
165+
McpSyncServer server = context.getBean(McpSyncServer.class);
166+
assertThat(server).isNotNull();
167+
});
168+
}
169+
170+
@Test
171+
void promptRegistrationConfiguration() {
172+
this.contextRunner.withUserConfiguration(TestPromptConfiguration.class).run(context -> {
173+
McpSyncServer server = context.getBean(McpSyncServer.class);
174+
assertThat(server).isNotNull();
175+
});
176+
}
177+
178+
@Test
179+
void asyncToolRegistrationConfiguration() {
180+
this.contextRunner.withPropertyValues("spring.ai.mcp.server.type=ASYNC")
181+
.withUserConfiguration(TestToolConfiguration.class)
182+
.run(context -> {
183+
List<AsyncToolRegistration> tools = context.getBean("asyncTools", List.class);
184+
assertThat(tools).hasSize(1);
185+
});
186+
}
187+
188+
@Test
189+
void customCapabilitiesBuilder() {
190+
this.contextRunner.withUserConfiguration(CustomCapabilitiesConfiguration.class).run(context -> {
191+
assertThat(context).hasSingleBean(McpSchema.ServerCapabilities.Builder.class);
192+
assertThat(context.getBean(McpSchema.ServerCapabilities.Builder.class))
193+
.isInstanceOf(CustomCapabilitiesBuilder.class);
194+
});
195+
}
196+
197+
@Test
198+
void rootsChangeConsumerConfiguration() {
199+
this.contextRunner.withUserConfiguration(TestRootsChangeConfiguration.class).run(context -> {
200+
McpSyncServer server = context.getBean(McpSyncServer.class);
201+
assertThat(server).isNotNull();
202+
});
203+
}
204+
205+
@Configuration
206+
static class TestResourceConfiguration {
207+
208+
@Bean
209+
List<SyncResourceRegistration> testResources() {
210+
return List.of();
211+
}
212+
213+
}
214+
215+
@Configuration
216+
static class TestPromptConfiguration {
217+
218+
@Bean
219+
List<SyncPromptRegistration> testPrompts() {
220+
return List.of();
221+
}
222+
223+
}
224+
225+
@Configuration
226+
static class CustomCapabilitiesConfiguration {
227+
228+
@Bean
229+
McpSchema.ServerCapabilities.Builder customCapabilitiesBuilder() {
230+
return new CustomCapabilitiesBuilder();
231+
}
232+
233+
}
234+
235+
static class CustomCapabilitiesBuilder extends McpSchema.ServerCapabilities.Builder {
236+
237+
// Custom implementation for testing
238+
239+
}
240+
241+
@Configuration
242+
static class TestToolConfiguration {
243+
244+
@Bean
245+
List<ToolCallback> testTool() {
246+
McpSyncClient mockClient = Mockito.mock(McpSyncClient.class);
247+
McpSchema.Tool mockTool = Mockito.mock(McpSchema.Tool.class);
248+
McpSchema.CallToolResult mockResult = Mockito.mock(McpSchema.CallToolResult.class);
249+
250+
Mockito.when(mockTool.name()).thenReturn("test-tool");
251+
Mockito.when(mockTool.description()).thenReturn("Test Tool");
252+
Mockito.when(mockClient.callTool(Mockito.any(McpSchema.CallToolRequest.class))).thenReturn(mockResult);
253+
254+
return List.of(new SyncMcpToolCallback(mockClient, mockTool));
255+
}
256+
257+
}
258+
259+
@Configuration
260+
static class TestRootsChangeConfiguration {
261+
262+
@Bean
263+
Consumer<List<McpSchema.Root>> rootsChangeConsumer() {
264+
return roots -> {
265+
// Test implementation
266+
};
267+
}
268+
269+
}
270+
271+
static class CustomServerTransport implements ServerMcpTransport {
272+
273+
@Override
274+
public Mono<Void> connect(
275+
Function<Mono<McpSchema.JSONRPCMessage>, Mono<McpSchema.JSONRPCMessage>> messageHandler) {
276+
return Mono.empty(); // Test implementation
277+
}
278+
279+
@Override
280+
public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {
281+
return Mono.empty(); // Test implementation
282+
}
283+
284+
@Override
285+
public <T> T unmarshalFrom(Object value, TypeReference<T> type) {
286+
return null; // Test implementation
287+
}
288+
289+
@Override
290+
public void close() {
291+
// Test implementation
292+
}
293+
294+
@Override
295+
public Mono<Void> closeGracefully() {
296+
return Mono.empty(); // Test implementation
297+
}
298+
299+
}
300+
301+
@Configuration
302+
static class CustomTransportConfiguration {
303+
304+
@Bean
305+
ServerMcpTransport customTransport() {
306+
return new CustomServerTransport();
307+
}
308+
309+
}
310+
91311
}

0 commit comments

Comments
 (0)