Skip to content

Commit a9f524a

Browse files
committed
Fixed compilation
1 parent d9ab85f commit a9f524a

File tree

15 files changed

+135
-137
lines changed

15 files changed

+135
-137
lines changed

src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/sse.ktor.kt renamed to src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/KtorClient.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public fun HttpClient.mcpSseTransport(
1919
urlString: String? = null,
2020
reconnectionTime: Duration? = null,
2121
requestBuilder: HttpRequestBuilder.() -> Unit = {},
22-
): SSEClientTransport = SSEClientTransport(this, urlString, reconnectionTime, requestBuilder)
22+
): SseClientTransport = SseClientTransport(this, urlString, reconnectionTime, requestBuilder)
2323

2424
/**
2525
* Creates and connects an MCP client over SSE using the provided HttpClient.

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

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,28 @@ import io.ktor.client.request.*
66
import io.ktor.client.statement.*
77
import io.ktor.http.*
88
import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage
9+
import io.modelcontextprotocol.kotlin.sdk.shared.AbstractTransport
910
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
10-
import io.modelcontextprotocol.kotlin.sdk.shared.Transport
1111
import kotlinx.atomicfu.AtomicBoolean
1212
import kotlinx.atomicfu.atomic
1313
import kotlinx.coroutines.*
1414
import kotlinx.serialization.encodeToString
1515
import kotlin.properties.Delegates
1616
import kotlin.time.Duration
1717

18+
@Deprecated("Use SseClientTransport instead", ReplaceWith("SseClientTransport"), DeprecationLevel.WARNING)
19+
public typealias SSEClientTransport = SseClientTransport
20+
1821
/**
1922
* Client transport for SSE: this will connect to a server using Server-Sent Events for receiving
2023
* messages and make separate POST requests for sending messages.
2124
*/
22-
public class SSEClientTransport(
25+
public class SseClientTransport(
2326
private val client: HttpClient,
2427
private val urlString: String?,
2528
private val reconnectionTime: Duration? = null,
2629
private val requestBuilder: HttpRequestBuilder.() -> Unit = {},
27-
) : Transport {
30+
) : AbstractTransport() {
2831
private val scope by lazy {
2932
CoroutineScope(session.coroutineContext + SupervisorJob())
3033
}
@@ -33,10 +36,6 @@ public class SSEClientTransport(
3336
private var session: ClientSSESession by Delegates.notNull()
3437
private val endpoint = CompletableDeferred<String>()
3538

36-
private var _onClose: (() -> Unit) = {}
37-
private var _onError: ((Throwable) -> Unit) = {}
38-
private var _onMessage: (suspend ((JSONRPCMessage) -> Unit)) = {}
39-
4039
private var job: Job? = null
4140

4241
private val baseUrl by lazy {
@@ -136,28 +135,4 @@ public class SSEClientTransport(
136135
_onClose()
137136
job?.cancelAndJoin()
138137
}
139-
140-
override fun onClose(block: () -> Unit) {
141-
val old = _onClose
142-
_onClose = {
143-
old()
144-
block()
145-
}
146-
}
147-
148-
override fun onError(block: (Throwable) -> Unit) {
149-
val old = _onError
150-
_onError = { e ->
151-
old(e)
152-
block(e)
153-
}
154-
}
155-
156-
override fun onMessage(block: suspend (JSONRPCMessage) -> Unit) {
157-
val old = _onMessage
158-
_onMessage = { message ->
159-
old(message)
160-
block(message)
161-
}
162-
}
163138
}

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

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package io.modelcontextprotocol.kotlin.sdk.client
22

33
import io.github.oshai.kotlinlogging.KotlinLogging
44
import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage
5+
import io.modelcontextprotocol.kotlin.sdk.shared.AbstractTransport
56
import io.modelcontextprotocol.kotlin.sdk.shared.ReadBuffer
6-
import io.modelcontextprotocol.kotlin.sdk.shared.Transport
77
import io.modelcontextprotocol.kotlin.sdk.shared.serializeMessage
88
import kotlinx.atomicfu.AtomicBoolean
99
import kotlinx.atomicfu.atomic
@@ -30,7 +30,7 @@ import kotlin.coroutines.CoroutineContext
3030
public class StdioClientTransport(
3131
private val input: Source,
3232
private val output: Sink
33-
) : Transport {
33+
) : AbstractTransport() {
3434
private val logger = KotlinLogging.logger {}
3535
private val ioCoroutineContext: CoroutineContext = Dispatchers.IO
3636
private val scope by lazy {
@@ -41,10 +41,6 @@ public class StdioClientTransport(
4141
private val sendChannel = Channel<JSONRPCMessage>(Channel.UNLIMITED)
4242
private val readBuffer = ReadBuffer()
4343

44-
override var onClose: (() -> Unit)? = null
45-
override var onError: ((Throwable) -> Unit)? = null
46-
override var onMessage: (suspend ((JSONRPCMessage) -> Unit))? = null
47-
4844
override suspend fun start() {
4945
if (!initialized.compareAndSet(false, true)) {
5046
error("StdioClientTransport already started!")
@@ -70,7 +66,7 @@ public class StdioClientTransport(
7066
}
7167
}
7268
} catch (e: Exception) {
73-
onError?.invoke(e)
69+
_onError.invoke(e)
7470
logger.error(e) { "Error reading from input stream" }
7571
}
7672
}
@@ -85,7 +81,7 @@ public class StdioClientTransport(
8581
}
8682
} catch (e: Throwable) {
8783
if (isActive) {
88-
onError?.invoke(e)
84+
_onError.invoke(e)
8985
logger.error(e) { "Error writing to output stream" }
9086
}
9187
} finally {
@@ -95,7 +91,7 @@ public class StdioClientTransport(
9591

9692
readJob.join()
9793
writeJob.cancelAndJoin()
98-
onClose?.invoke()
94+
_onClose.invoke()
9995
}
10096
}
10197

@@ -116,16 +112,16 @@ public class StdioClientTransport(
116112
output.close()
117113
readBuffer.clear()
118114
sendChannel.close()
119-
onClose?.invoke()
115+
_onClose.invoke()
120116
}
121117

122118
private suspend fun processReadBuffer() {
123119
while (true) {
124120
val msg = readBuffer.readMessage() ?: break
125121
try {
126-
onMessage?.invoke(msg)
122+
_onMessage.invoke(msg)
127123
} catch (e: Throwable) {
128-
onError?.invoke(e)
124+
_onError.invoke(e)
129125
logger.error(e) { "Error processing message." }
130126
}
131127
}

src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import io.ktor.server.request.*
66
import io.ktor.server.response.*
77
import io.ktor.server.sse.*
88
import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage
9+
import io.modelcontextprotocol.kotlin.sdk.shared.AbstractTransport
910
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
10-
import io.modelcontextprotocol.kotlin.sdk.shared.Transport
1111
import kotlinx.atomicfu.AtomicBoolean
1212
import kotlinx.atomicfu.atomic
1313
import kotlinx.coroutines.job
@@ -17,24 +17,23 @@ import kotlin.uuid.Uuid
1717

1818
internal const val SESSION_ID_PARAM = "sessionId"
1919

20+
@Deprecated("Use SseServerTransport instead", ReplaceWith("SseServerTransport"), DeprecationLevel.WARNING)
21+
public typealias SSEServerTransport = SseServerTransport
22+
2023
/**
2124
* Server transport for SSE: this will send messages over an SSE connection and receive messages from HTTP POST requests.
2225
*
2326
* Creates a new SSE server transport, which will direct the client to POST messages to the relative or absolute URL identified by `_endpoint`.
2427
*/
25-
public class SSEServerTransport(
28+
public class SseServerTransport(
2629
private val endpoint: String,
2730
private val session: ServerSSESession,
28-
) : Transport {
31+
) : AbstractTransport() {
2932
private val initialized: AtomicBoolean = atomic(false)
3033

3134
@OptIn(ExperimentalUuidApi::class)
3235
public val sessionId: String = Uuid.random().toString()
3336

34-
override var onClose: (() -> Unit)? = null
35-
override var onError: ((Throwable) -> Unit)? = null
36-
override var onMessage: (suspend ((JSONRPCMessage) -> Unit))? = null
37-
3837
/**
3938
* Handles the initial SSE connection request.
4039
*
@@ -54,7 +53,7 @@ public class SSEServerTransport(
5453
try {
5554
session.coroutineContext.job.join()
5655
} finally {
57-
onClose?.invoke()
56+
_onClose.invoke()
5857
}
5958
}
6059

@@ -67,7 +66,7 @@ public class SSEServerTransport(
6766
if (!initialized.value) {
6867
val message = "SSE connection not established"
6968
call.respondText(message, status = HttpStatusCode.InternalServerError)
70-
onError?.invoke(IllegalStateException(message))
69+
_onError.invoke(IllegalStateException(message))
7170
}
7271

7372
val body = try {
@@ -79,7 +78,7 @@ public class SSEServerTransport(
7978
call.receiveText()
8079
} catch (e: Exception) {
8180
call.respondText("Invalid message: ${e.message}", status = HttpStatusCode.BadRequest)
82-
onError?.invoke(e)
81+
_onError.invoke(e)
8382
return
8483
}
8584

@@ -100,16 +99,16 @@ public class SSEServerTransport(
10099
public suspend fun handleMessage(message: String) {
101100
try {
102101
val parsedMessage = McpJson.decodeFromString<JSONRPCMessage>(message)
103-
onMessage?.invoke(parsedMessage)
102+
_onMessage.invoke(parsedMessage)
104103
} catch (e: Exception) {
105-
onError?.invoke(e)
104+
_onError.invoke(e)
106105
throw e
107106
}
108107
}
109108

110109
override suspend fun close() {
111110
session.close()
112-
onClose?.invoke()
111+
_onClose.invoke()
113112
}
114113

115114
override suspend fun send(message: JSONRPCMessage) {

src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StdioServerTransport.kt

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package io.modelcontextprotocol.kotlin.sdk.server
22

33
import io.github.oshai.kotlinlogging.KotlinLogging
44
import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage
5+
import io.modelcontextprotocol.kotlin.sdk.shared.AbstractTransport
56
import io.modelcontextprotocol.kotlin.sdk.shared.ReadBuffer
6-
import io.modelcontextprotocol.kotlin.sdk.shared.Transport
77
import io.modelcontextprotocol.kotlin.sdk.shared.serializeMessage
88
import kotlinx.atomicfu.AtomicBoolean
99
import kotlinx.atomicfu.atomic
@@ -27,11 +27,8 @@ import kotlin.coroutines.CoroutineContext
2727
public class StdioServerTransport(
2828
private val inputStream: Source, //BufferedInputStream = BufferedInputStream(System.`in`),
2929
outputStream: Sink //PrintStream = System.out
30-
) : Transport {
30+
) : AbstractTransport() {
3131
private val logger = KotlinLogging.logger {}
32-
override var onClose: (() -> Unit)? = null
33-
override var onError: ((Throwable) -> Unit)? = null
34-
override var onMessage: (suspend (JSONRPCMessage) -> Unit)? = null
3532

3633
private val readBuffer = ReadBuffer()
3734
private val initialized: AtomicBoolean = atomic(false)
@@ -65,7 +62,7 @@ public class StdioServerTransport(
6562
}
6663
} catch (e: Throwable) {
6764
logger.error(e) { "Error reading from stdin" }
68-
onError?.invoke(e)
65+
_onError.invoke(e)
6966
} finally {
7067
// Reached EOF or error, close connection
7168
close()
@@ -80,7 +77,7 @@ public class StdioServerTransport(
8077
processReadBuffer()
8178
}
8279
} catch (e: Throwable) {
83-
onError?.invoke(e)
80+
_onError.invoke(e)
8481
}
8582
}
8683
}
@@ -90,16 +87,16 @@ public class StdioServerTransport(
9087
val message = try {
9188
readBuffer.readMessage()
9289
} catch (e: Throwable) {
93-
onError?.invoke(e)
90+
_onError.invoke(e)
9491
null
9592
}
9693

9794
if (message == null) break
9895
// Async invocation broke delivery order
9996
try {
100-
onMessage?.invoke(message)
97+
_onMessage.invoke(message)
10198
} catch (e: Throwable) {
102-
onError?.invoke(e)
99+
_onError.invoke(e)
103100
}
104101
}
105102
}
@@ -112,7 +109,7 @@ public class StdioServerTransport(
112109
readChannel.close()
113110
readBuffer.clear()
114111

115-
onClose?.invoke()
112+
_onClose.invoke()
116113
}
117114

118115
override suspend fun send(message: JSONRPCMessage) {

src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,15 @@ public abstract class Protocol(
152152
*/
153153
public open suspend fun connect(transport: Transport) {
154154
this.transport = transport
155-
transport.onClose = {
155+
transport.onClose {
156156
doClose()
157157
}
158158

159-
transport.onError = {
159+
transport.onError {
160160
onError(it)
161161
}
162162

163-
transport.onMessage = { message ->
163+
transport.onMessage { message ->
164164
when (message) {
165165
is JSONRPCResponse -> onResponse(message, null)
166166
is JSONRPCRequest -> onRequest(message)
@@ -477,4 +477,4 @@ public abstract class Protocol(
477477
public fun removeNotificationHandler(method: Method) {
478478
notificationHandlers.remove(method.value)
479479
}
480-
}
480+
}

src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Transport.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,38 @@ public interface Transport {
4646
*/
4747
public fun onMessage(block: suspend (JSONRPCMessage) -> Unit)
4848
}
49+
50+
/**
51+
* Implements [onClose], [onError] and [onMessage] functions of [Transport] providing
52+
* corresponding [_onClose], [_onError] and [_onMessage] properties to use for an implementation.
53+
*/
54+
@Suppress("PropertyName")
55+
public abstract class AbstractTransport : Transport {
56+
protected var _onClose: (() -> Unit) = {}
57+
protected var _onError: ((Throwable) -> Unit) = {}
58+
protected var _onMessage: (suspend ((JSONRPCMessage) -> Unit)) = {}
59+
60+
override fun onClose(block: () -> Unit) {
61+
val old = _onClose
62+
_onClose = {
63+
old()
64+
block()
65+
}
66+
}
67+
68+
override fun onError(block: (Throwable) -> Unit) {
69+
val old = _onError
70+
_onError = { e ->
71+
old(e)
72+
block(e)
73+
}
74+
}
75+
76+
override fun onMessage(block: suspend (JSONRPCMessage) -> Unit) {
77+
val old = _onMessage
78+
_onMessage = { message ->
79+
old(message)
80+
block(message)
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)