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:
parent
905d4f975e
commit
7937390b47
1 changed files with 2 additions and 15 deletions
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue