Test and fix #52 (#53)

* Add test to reproduce #52

* Solve issue #52 by improving url handling in SseClientTransport

* Remove unnecessary url processing

---------

Co-authored-by: Abdullatif.Ghajar <abdullatif.ghajar@jetbrains.com>
This commit is contained in:
Abdullatif Ghajar 2025-03-26 09:29:48 +01:00 • committed by GitHub
commit be4f9c37e0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 3 deletions

View file

@ -39,7 +39,7 @@ public class SseClientTransport(
private var job: Job? = null
private val baseUrl by lazy {
session.call.request.url.toString().removeSuffix("/")
session.call.request.url.toString().removeSuffix("/sse")
}
override suspend fun start() {
@ -52,7 +52,7 @@ public class SseClientTransport(
session = urlString?.let {
client.sseSession(
urlString = it,
urlString = "$it/sse",
reconnectionTime = reconnectionTime,
block = requestBuilder,
)
@ -79,7 +79,7 @@ public class SseClientTransport(
val eventData = event.data ?: ""
// check url correctness
val maybeEndpoint = Url("$baseUrl/$eventData")
val maybeEndpoint = Url(baseUrl + eventData)
endpoint.complete(maybeEndpoint.toString())
} catch (e: Exception) {

View file

@ -0,0 +1,51 @@
package integration
import io.ktor.client.*
import io.ktor.client.plugins.sse.*
import io.ktor.server.cio.*
import io.ktor.server.engine.*
import io.modelcontextprotocol.kotlin.sdk.Implementation
import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.client.Client
import io.modelcontextprotocol.kotlin.sdk.client.mcpSse
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.server.mcp
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
import io.ktor.client.engine.cio.CIO as ClientCIO
import io.ktor.server.cio.CIO as ServerCIO
class SseIntegrationTest {
@Test
fun `client should be able to connect to sse server`() { // runTest will cause network timeout issues
runBlocking {
val serverEngine = initServer()
try {
assertDoesNotThrow { initClient() }
} finally {
// Make sure to stop the server
serverEngine.stop(1000, 2000)
}
}
}
private suspend fun initClient(): Client {
return HttpClient(ClientCIO) { install(SSE) }.mcpSse("http://$URL:$PORT")
}
private fun initServer(): EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration> {
val server = Server(
Implementation(name = "sse-e2e-test", version = "1.0.0"),
ServerOptions(capabilities = ServerCapabilities()),
)
return embeddedServer(ServerCIO, host = URL, port = PORT) { mcp { server } }.start(wait = false)
}
companion object {
private const val PORT = 3001
private const val URL = "localhost"
}
}