1+ package integration.kotlin
2+
3+ import io.ktor.client.*
4+ import io.ktor.client.engine.cio.*
5+ import io.ktor.client.plugins.sse.*
6+ import io.ktor.server.application.*
7+ import io.ktor.server.engine.*
8+ import io.ktor.server.routing.*
9+ import io.modelcontextprotocol.kotlin.sdk.Implementation
10+ import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities
11+ import io.modelcontextprotocol.kotlin.sdk.client.Client
12+ import io.modelcontextprotocol.kotlin.sdk.client.SseClientTransport
13+ import io.modelcontextprotocol.kotlin.sdk.server.Server
14+ import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
15+ import io.modelcontextprotocol.kotlin.sdk.server.mcp
16+ import kotlinx.coroutines.runBlocking
17+ import kotlinx.coroutines.withTimeout
18+ import org.junit.jupiter.api.AfterEach
19+ import org.junit.jupiter.api.BeforeEach
20+ import kotlin.time.Duration.Companion.seconds
21+ import io.ktor.server.cio.CIO as ServerCIO
22+ import io.ktor.server.sse.SSE as ServerSSE
23+
24+ abstract class KotlinTestBase {
25+
26+ protected val host = " localhost"
27+ protected abstract val port: Int
28+
29+ protected lateinit var server: Server
30+ protected lateinit var client: Client
31+ protected lateinit var serverEngine: EmbeddedServer <* , * >
32+
33+ protected abstract fun configureServerCapabilities (): ServerCapabilities
34+ protected abstract fun configureServer ()
35+
36+ @BeforeEach
37+ fun setUp () {
38+ setupServer()
39+ runBlocking {
40+ setupClient()
41+ }
42+ }
43+
44+ protected suspend fun setupClient () {
45+ val transport = SseClientTransport (HttpClient (CIO ) {
46+ install(SSE )
47+ }, " http://$host :$port " )
48+ client = Client (
49+ Implementation (" test" , " 1.0" ),
50+ )
51+ client.connect(transport)
52+ }
53+
54+ protected fun setupServer () {
55+ val capabilities = configureServerCapabilities()
56+
57+ server = Server (
58+ Implementation (name = " test-server" , version = " 1.0" ),
59+ ServerOptions (capabilities = capabilities)
60+ )
61+
62+ configureServer()
63+
64+ serverEngine = embeddedServer(ServerCIO , host = host, port = port) {
65+ install(ServerSSE )
66+ routing {
67+ mcp { server }
68+ }
69+ }.start(wait = false )
70+ }
71+
72+ @AfterEach
73+ fun tearDown () {
74+ // close client
75+ if (::client.isInitialized) {
76+ try {
77+ runBlocking {
78+ withTimeout(3 .seconds) {
79+ client.close()
80+ }
81+ }
82+ } catch (e: Exception ) {
83+ println (" Warning: Error during client close: ${e.message} " )
84+ }
85+ }
86+
87+ // stop server
88+ if (::serverEngine.isInitialized) {
89+ try {
90+ serverEngine.stop(500 , 1000 )
91+ } catch (e: Exception ) {
92+ println (" Warning: Error during server stop: ${e.message} " )
93+ }
94+ }
95+ }
96+ }
0 commit comments