From a857b92723a33541cd303164e77901dcaa25a4ac Mon Sep 17 00:00:00 2001 From: Maria Tigina Date: Fri, 15 Aug 2025 16:20:11 +0200 Subject: [PATCH 1/2] Add deserialization error processing --- .../kotlin/sdk/shared/ReadBuffer.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/ReadBuffer.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/ReadBuffer.kt index 10d91c14..6315cb15 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/ReadBuffer.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/ReadBuffer.kt @@ -1,5 +1,6 @@ package io.modelcontextprotocol.kotlin.sdk.shared +import io.github.oshai.kotlinlogging.KotlinLogging import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage import kotlinx.io.Buffer import kotlinx.io.indexOf @@ -9,6 +10,9 @@ import kotlinx.io.readString * Buffers a continuous stdio stream into discrete JSON-RPC messages. */ public class ReadBuffer { + + private val logger = KotlinLogging.logger { } + private val buffer: Buffer = Buffer() public fun append(chunk: ByteArray) { @@ -37,7 +41,13 @@ public class ReadBuffer { string } } - return deserializeMessage(line) + try { + return deserializeMessage(line) + } catch (e: Exception) { + logger.error(e) { "Failed to deserialize message from line: $line\nSkipping..." } + } + + return null } public fun clear() { From ee22eb91a161cd62986c1b7ed0955c2dc3982535 Mon Sep 17 00:00:00 2001 From: Maria Tigina Date: Fri, 15 Aug 2025 16:53:02 +0200 Subject: [PATCH 2/2] Add test --- .../sdk/client/StdioClientTransportTest.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/StdioClientTransportTest.kt b/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/StdioClientTransportTest.kt index e8a163d3..6d0da329 100644 --- a/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/StdioClientTransportTest.kt +++ b/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/StdioClientTransportTest.kt @@ -45,4 +45,24 @@ class StdioClientTransportTest : BaseTransportTest() { process.waitFor() process.destroy() } + + @Test + fun `should ignore first output messages`() = runTest { + val processBuilder = ProcessBuilder("/usr/bin/tee") + val process = processBuilder.start() + process.outputStream.write("Stdio server started".toByteArray()) + + val input = process.inputStream.asSource().buffered() + val output = process.outputStream.asSink().buffered() + + val client = StdioClientTransport( + input = input, + output = output, + ) + + testClientRead(client) + + process.waitFor() + process.destroy() + } }