test: create the server session before connecting the client (#885)

`ChannelTransportTest` connected both sides concurrently, which is racy.

`ChannelTransport` starts delivering inbound messages when its read loop
launches, which happens before `start()` marks the transport
`Operational`. The two run on different dispatchers, so the client's
`initialize` could reach the server read loop first and the session's
`InitializeResult` was then rejected by the send state gate with
`Transport is not ready`. Measured ~3 failures in 600 rounds.

`createSession()` does not await the handshake, so creating the session
first is enough to order the two. This also matches the usage shown in
`createLinkedPair()`'s KDoc.

Not addressed here: the transport itself should not deliver inbound
messages before it is `Operational`. Fixing that needs a
post-`Operational` hook on `AbstractClientTransport` that the read loop
awaits.
This commit is contained in:
Pavel Gorgulov 2026-07-09 17:03:01 +02:00 • committed by GitHub
commit 7937390b47
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -6,7 +6,6 @@ import io.modelcontextprotocol.kotlin.sdk.ExperimentalMcpApi
import io.modelcontextprotocol.kotlin.sdk.client.Client
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.server.ServerSession
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.InitializeRequest
import io.modelcontextprotocol.kotlin.sdk.types.InitializeResult
@ -16,9 +15,6 @@ import io.modelcontextprotocol.kotlin.sdk.types.ListResourcesResult
import io.modelcontextprotocol.kotlin.sdk.types.Method
import io.modelcontextprotocol.kotlin.sdk.types.Resource
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
@ -43,18 +39,9 @@ class ChannelTransportTest {
clientInfo = Implementation(name = "test client", version = "1.0"),
)
val serverSessionResult = CompletableDeferred<ServerSession>()
val serverSession = server.createSession(serverTransport)
client.connect(clientTransport)
listOf(
launch {
client.connect(clientTransport)
},
launch {
serverSessionResult.complete(server.createSession(serverTransport))
},
).joinAll()
val serverSession = serverSessionResult.await()
serverSession.setRequestHandler<InitializeRequest>(Method.Defined.Initialize) { _, _ ->
InitializeResult(
protocolVersion = LATEST_PROTOCOL_VERSION,