Skip to content

Commit 7d89618

Browse files
committed
Merge remote-tracking branch 'origin/master' into sql-multi-column-foreign-keys
2 parents 4fda1fd + 0dfc68e commit 7d89618

File tree

48 files changed

+1438
-224
lines changed

Some content is hidden

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

48 files changed

+1438
-224
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ experiments/target/
5151

5252
/core-tests/e2e-tests/spring/spring-rest-openapi-v3/target
5353
/core-tests/e2e-tests/spring/spring-graphql/target
54+
/core-tests/e2e-tests/spring/spring-mcp-bb/target/
5455
/core-tests/e2e-tests/ci-utils/target
5556

5657
/core-tests/core-it/target/

core-tests/e2e-tests/spring/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<module>spring-rest-rsa</module>
3232
<module>spring-rpc-grpc</module>
3333
<module>spring-rpc-thrift</module>
34+
<module>spring-mcp-bb</module>
3435
</modules>
3536

3637
<dependencyManagement>
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>org.evomaster</groupId>
8+
<artifactId>evomaster-e2e-tests-spring</artifactId>
9+
<version>5.1.1-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>evomaster-e2e-tests-spring-mcp-bb</artifactId>
13+
<packaging>jar</packaging>
14+
15+
<properties>
16+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
17+
<spring.ai.version>1.1.0</spring.ai.version>
18+
<!--
19+
Spring AI 1.x requires Spring Boot 3.3+.
20+
springboot3.version in the root pom is 3.1.5 which is too old,
21+
so we define a local version for this module.
22+
-->
23+
<springboot.mcp.version>3.5.7</springboot.mcp.version>
24+
<!--
25+
Spring Boot 3.3.x requires Logback 1.5.x and SLF4J 2.0.x.
26+
The root pom pins logback-classic to 1.2.3 and slf4j-api to 1.7.24,
27+
so we override them here.
28+
-->
29+
<logback.mcp.version>1.5.8</logback.mcp.version>
30+
<slf4j.mcp.version>2.0.16</slf4j.mcp.version>
31+
</properties>
32+
33+
<dependencyManagement>
34+
<dependencies>
35+
<!--
36+
The parent pom pins spring-boot to ${springboot.version} (2.5.4).
37+
Override all Spring Boot artifacts to 3.3.x needed by Spring AI 1.x.
38+
-->
39+
<dependency>
40+
<groupId>org.springframework.boot</groupId>
41+
<artifactId>spring-boot</artifactId>
42+
<version>${springboot.mcp.version}</version>
43+
</dependency>
44+
<dependency>
45+
<groupId>org.springframework.boot</groupId>
46+
<artifactId>spring-boot-autoconfigure</artifactId>
47+
<version>${springboot.mcp.version}</version>
48+
</dependency>
49+
<!--
50+
The root pom pins logback to 1.2.3 and slf4j to 1.7.24 globally.
51+
Spring Boot 3.3.x requires Logback 1.5.x (Configurator interface changed)
52+
and SLF4J 2.0.x. Override here to avoid AbstractMethodError at startup.
53+
-->
54+
<dependency>
55+
<groupId>ch.qos.logback</groupId>
56+
<artifactId>logback-classic</artifactId>
57+
<version>${logback.mcp.version}</version>
58+
</dependency>
59+
<dependency>
60+
<groupId>ch.qos.logback</groupId>
61+
<artifactId>logback-core</artifactId>
62+
<version>${logback.mcp.version}</version>
63+
</dependency>
64+
<dependency>
65+
<groupId>org.slf4j</groupId>
66+
<artifactId>slf4j-api</artifactId>
67+
<version>${slf4j.mcp.version}</version>
68+
</dependency>
69+
<dependency>
70+
<groupId>org.springframework.ai</groupId>
71+
<artifactId>spring-ai-bom</artifactId>
72+
<version>${spring.ai.version}</version>
73+
<type>pom</type>
74+
<scope>import</scope>
75+
</dependency>
76+
</dependencies>
77+
</dependencyManagement>
78+
79+
<dependencies>
80+
<dependency>
81+
<groupId>org.jetbrains.kotlin</groupId>
82+
<artifactId>kotlin-stdlib</artifactId>
83+
</dependency>
84+
<dependency>
85+
<groupId>org.jetbrains.kotlin</groupId>
86+
<artifactId>kotlin-reflect</artifactId>
87+
</dependency>
88+
89+
<dependency>
90+
<groupId>org.springframework.boot</groupId>
91+
<artifactId>spring-boot-starter-validation</artifactId>
92+
<version>${springboot.mcp.version}</version>
93+
</dependency>
94+
<dependency>
95+
<groupId>org.springframework.boot</groupId>
96+
<artifactId>spring-boot-starter-web</artifactId>
97+
<version>${springboot.mcp.version}</version>
98+
</dependency>
99+
<dependency>
100+
<groupId>org.springframework.boot</groupId>
101+
<artifactId>spring-boot-starter-test</artifactId>
102+
<version>${springboot.mcp.version}</version>
103+
<scope>test</scope>
104+
</dependency>
105+
<dependency>
106+
<groupId>org.springframework.ai</groupId>
107+
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
108+
</dependency>
109+
110+
<dependency>
111+
<groupId>org.evomaster</groupId>
112+
<artifactId>evomaster-e2e-tests-utils</artifactId>
113+
<version>${project.version}</version>
114+
</dependency>
115+
<dependency>
116+
<groupId>org.evomaster</groupId>
117+
<artifactId>evomaster-e2e-tests-utils</artifactId>
118+
<type>test-jar</type>
119+
</dependency>
120+
<dependency>
121+
<groupId>org.evomaster</groupId>
122+
<artifactId>evomaster-client-java-controller</artifactId>
123+
</dependency>
124+
<dependency>
125+
<groupId>org.evomaster</groupId>
126+
<artifactId>evomaster-client-java-controller</artifactId>
127+
<scope>test</scope>
128+
<exclusions>
129+
<exclusion>
130+
<groupId>javax.validation</groupId>
131+
<artifactId>validation-api</artifactId>
132+
</exclusion>
133+
</exclusions>
134+
</dependency>
135+
<dependency>
136+
<groupId>org.evomaster</groupId>
137+
<artifactId>evomaster-core</artifactId>
138+
<scope>test</scope>
139+
</dependency>
140+
141+
<dependency>
142+
<groupId>org.junit.jupiter</groupId>
143+
<artifactId>junit-jupiter-engine</artifactId>
144+
</dependency>
145+
<dependency>
146+
<groupId>org.junit.jupiter</groupId>
147+
<artifactId>junit-jupiter-params</artifactId>
148+
</dependency>
149+
<dependency>
150+
<groupId>io.rest-assured</groupId>
151+
<artifactId>rest-assured</artifactId>
152+
</dependency>
153+
<dependency>
154+
<groupId>org.hamcrest</groupId>
155+
<artifactId>hamcrest-all</artifactId>
156+
</dependency>
157+
</dependencies>
158+
159+
<build>
160+
<plugins>
161+
<plugin>
162+
<artifactId>kotlin-maven-plugin</artifactId>
163+
<groupId>org.jetbrains.kotlin</groupId>
164+
<configuration>
165+
<jvmTarget>${java.version}</jvmTarget>
166+
<args>
167+
<arg>-java-parameters</arg>
168+
</args>
169+
</configuration>
170+
</plugin>
171+
<plugin>
172+
<groupId>org.apache.maven.plugins</groupId>
173+
<artifactId>maven-compiler-plugin</artifactId>
174+
</plugin>
175+
<plugin>
176+
<groupId>org.apache.maven.plugins</groupId>
177+
<artifactId>maven-surefire-plugin</artifactId>
178+
<configuration>
179+
<!-- Otherwise tests using mvn will not work -->
180+
<redirectTestOutputToFile>false</redirectTestOutputToFile>
181+
<environmentVariables>
182+
<SKIP_INSTRUMENTATION>true</SKIP_INSTRUMENTATION>
183+
</environmentVariables>
184+
</configuration>
185+
</plugin>
186+
</plugins>
187+
</build>
188+
189+
</project>
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package com.foo.mcp.bb.examples.spring.holidays
2+
3+
import org.springframework.ai.tool.annotation.Tool
4+
import org.springframework.ai.tool.annotation.ToolParam
5+
import org.springframework.stereotype.Service
6+
import java.util.*
7+
8+
@Service
9+
class HolidayService {
10+
11+
private val destinations: MutableMap<String, MutableMap<String, String>> = mutableMapOf()
12+
13+
init {
14+
setDestinations()
15+
}
16+
17+
fun setDestinations() {
18+
destinations["bali"] = destination(
19+
"Bali, Indonesia",
20+
"A tropical paradise of Hindu temples, lush rice terraces, volcanic peaks, and white-sand beaches.",
21+
)
22+
destinations["paris"] = destination(
23+
"Paris, France",
24+
"The City of Light: world-class art, haute cuisine, grand boulevards, and the iconic Eiffel Tower.",
25+
)
26+
destinations["tokyo"] = destination(
27+
"Tokyo, Japan",
28+
"A dazzling blend of ultra-modern skyscrapers, ancient shrines, anime culture, and Michelin-starred dining.",
29+
)
30+
destinations["new_york"] = destination(
31+
"New York City, USA",
32+
"The city that never sleeps: Broadway shows, world-famous museums, Central Park, and a skyline unlike any other.",
33+
)
34+
}
35+
36+
private fun destination(name: String, description: String): MutableMap<String, String> {
37+
val result: MutableMap<String, String> = LinkedHashMap<String, String>()
38+
result["name"] = name
39+
result["description"] = description
40+
return result
41+
}
42+
43+
@Tool(name = "list_destinations", description = "List all available holiday destinations with a short description.")
44+
fun listDestinations(): MutableMap<String, Any> {
45+
val list: MutableList<MutableMap<String, Any>> = mutableListOf()
46+
for (entry in destinations.entries) {
47+
val item: MutableMap<String, Any> = LinkedHashMap()
48+
item["id"] = entry.key
49+
item["name"] = entry.value["name"] as Any
50+
item["description"] = entry.value["description"] as Any
51+
list.add(item)
52+
}
53+
val text = formatDestinationList(list)
54+
return textResult(text)
55+
}
56+
57+
@Tool(
58+
name = "get_destination_info",
59+
description = "Get full details about a holiday destination: highlights, best travel months, weather, currency, and language."
60+
)
61+
fun getDestinationInfo(
62+
@ToolParam(description = "Destination ID (e.g. bali, paris, tokyo). Use list_destinations to see all IDs.")
63+
destinationId: String
64+
): MutableMap<String, Any> {
65+
if (destinationId.isBlank()) {
66+
return textResult("Error: 'destination' parameter is required.", true)
67+
}
68+
val destination = destinations[destinationId.lowercase(Locale.getDefault()).replace(" ", "_")]
69+
if (destination == null) {
70+
return textResult(
71+
"Destination '$destinationId' not found. Call list_destinations to see available options.",
72+
true
73+
)
74+
}
75+
76+
return textResult(destination["description"]!!)
77+
}
78+
79+
private fun textResult(text: String): MutableMap<String, Any> {
80+
return textResult(text, false)
81+
}
82+
83+
private fun textResult(text: String, isError: Boolean): MutableMap<String, Any> {
84+
val content: MutableMap<String, Any> = LinkedHashMap()
85+
content["type"] = "text"
86+
content["text"] = text
87+
val result: MutableMap<String, Any> = LinkedHashMap()
88+
result["content"] = mutableListOf(content)
89+
if (isError) result["isError"] = true
90+
return result
91+
}
92+
93+
private fun formatDestinationList(list: MutableList<MutableMap<String, Any>>): String {
94+
val sb = StringBuilder("# Available Holiday Destinations\n\n")
95+
for (item in list) {
96+
sb.append("- **${item["id"]}** — ${item["name"]}: ${item["description"]}\n")
97+
}
98+
sb.append("\nUse `get_destination_info` with one of these IDs for full details.")
99+
return sb.toString()
100+
}
101+
102+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.foo.mcp.bb.examples.spring.holidays
2+
3+
import org.springframework.ai.tool.ToolCallbackProvider
4+
import org.springframework.ai.tool.method.MethodToolCallbackProvider
5+
import org.springframework.boot.autoconfigure.SpringBootApplication
6+
import org.springframework.boot.runApplication
7+
import org.springframework.context.annotation.Bean
8+
9+
@SpringBootApplication
10+
open class HolidaysApplication {
11+
12+
@Bean
13+
open fun holidayTools(holidayService: HolidayService): ToolCallbackProvider {
14+
return MethodToolCallbackProvider.builder()
15+
.toolObjects(holidayService)
16+
.build()
17+
}
18+
19+
}
20+
21+
fun main(args: Array<String>) {
22+
runApplication<HolidaysApplication>(*args)
23+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
spring.ai.mcp.server.name=holiday-mcp-server
2+
spring.ai.mcp.server.version=1.0.0
3+
spring.ai.mcp.server.protocol=STATELESS

0 commit comments

Comments
 (0)