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