Skip to content

Commit 958e5e5

Browse files
shendaxia-smtpp-builderdevcrocode5l
authored
sse server does not process endpoint correctly when sse path is not a directory (#43)
* fix SSEClientTransport endpoint process with none directory sse path * fix SSEClientTransport endpoint process with none directory sse path * Refactor `SseTransportTest` to use `route` for better clarity and update server handling with suspend functions. --------- Co-authored-by: tpp-builder <[email protected]> Co-authored-by: devcrocod <[email protected]> Co-authored-by: Leonid Stashevsky <[email protected]>
1 parent aa00fc3 commit 958e5e5

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SSEClientTransport.kt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import io.ktor.http.HttpHeaders
1212
import io.ktor.http.Url
1313
import io.ktor.http.append
1414
import io.ktor.http.isSuccess
15+
import io.ktor.http.protocolWithAuthority
1516
import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage
1617
import io.modelcontextprotocol.kotlin.sdk.shared.AbstractTransport
1718
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
@@ -24,7 +25,6 @@ import kotlinx.coroutines.SupervisorJob
2425
import kotlinx.coroutines.cancel
2526
import kotlinx.coroutines.cancelAndJoin
2627
import kotlinx.coroutines.launch
27-
import kotlinx.serialization.encodeToString
2828
import kotlin.concurrent.atomics.AtomicBoolean
2929
import kotlin.concurrent.atomics.ExperimentalAtomicApi
3030
import kotlin.properties.Delegates
@@ -55,7 +55,18 @@ public class SseClientTransport(
5555
private var job: Job? = null
5656

5757
private val baseUrl by lazy {
58-
session.call.request.url.toString().removeSuffix("/sse")
58+
val requestUrl = session.call.request.url.toString()
59+
val url = Url(requestUrl)
60+
var path = url.encodedPath
61+
if (path.isEmpty()) {
62+
url.protocolWithAuthority
63+
} else if (path.endsWith("/")) {
64+
url.protocolWithAuthority + path.removeSuffix("/")
65+
} else {
66+
// the last item is not a directory, so will not be taken into account
67+
path = path.substring(0, path.lastIndexOf("/"))
68+
url.protocolWithAuthority + path
69+
}
5970
}
6071

6172
override suspend fun start() {
@@ -95,8 +106,7 @@ public class SseClientTransport(
95106
val eventData = event.data ?: ""
96107

97108
// check url correctness
98-
val maybeEndpoint = Url(baseUrl + eventData)
99-
109+
val maybeEndpoint = Url("$baseUrl/${if (eventData.startsWith("/")) eventData.substring(1) else eventData}")
100110
endpoint.complete(maybeEndpoint.toString())
101111
} catch (e: Exception) {
102112
_onError(e)

src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseTransportTest.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import io.ktor.server.application.install
66
import io.ktor.server.cio.CIO
77
import io.ktor.server.engine.embeddedServer
88
import io.ktor.server.routing.post
9+
import io.ktor.server.routing.route
910
import io.ktor.server.routing.routing
1011
import io.ktor.server.sse.sse
1112
import io.ktor.util.collections.ConcurrentMap
@@ -82,4 +83,43 @@ class SseTransportTest : BaseTransportTest() {
8283
testClientRead(client)
8384
server.stopSuspend()
8485
}
86+
87+
@Test
88+
fun `test sse path not root path`() = runTest {
89+
val port = 3007
90+
val server = embeddedServer(CIO, port = port) {
91+
install(io.ktor.server.sse.SSE)
92+
val transports = ConcurrentMap<String, SseServerTransport>()
93+
routing {
94+
route("/sse") {
95+
sse {
96+
mcpSseTransport("", transports).apply {
97+
onMessage {
98+
send(it)
99+
}
100+
101+
start()
102+
}
103+
}
104+
105+
post {
106+
mcpPostEndpoint(transports)
107+
}
108+
}
109+
}
110+
}.startSuspend(wait = false)
111+
112+
val client = HttpClient {
113+
install(SSE)
114+
}.mcpSseTransport {
115+
url {
116+
host = "localhost"
117+
this.port = port
118+
pathSegments = listOf("sse")
119+
}
120+
}
121+
122+
testClientRead(client)
123+
server.stopSuspend()
124+
}
85125
}

0 commit comments

Comments
 (0)