Skip to content

Commit 128f798

Browse files
committed
Refactored code to streamline error handling and consolidate RPCError usage. Updated references from ErrorCode to RPCError.ErrorCode. Adjusted imports for consistency with types package structure.
1 parent 8cab89f commit 128f798

File tree

4 files changed

+41
-40
lines changed

4 files changed

+41
-40
lines changed

kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/jsonRpc.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ public data class JSONRPCResponse(val id: RequestId, val result: RequestResult =
171171
* @property error Details about the error that occurred, including error code and message.
172172
*/
173173
@Serializable
174-
public data class JSONRPCError(val id: RequestId, val error: RPCError) : JSONRPCMessage {
174+
public data class JSONRPCError(val id: RequestId?, val error: RPCError) : JSONRPCMessage {
175175
@EncodeDefault
176176
override val jsonrpc: String = JSONRPC_VERSION
177177
}

kotlin-sdk-server/api/kotlin-sdk-server.api

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
public abstract interface class io/modelcontextprotocol/kotlin/sdk/server/EventStore {
22
public abstract fun replayEventsAfter (Ljava/lang/String;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
3-
public abstract fun storeEvent (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/JSONRPCMessage;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
3+
public abstract fun storeEvent (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/types/JSONRPCMessage;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
44
}
55

66
public final class io/modelcontextprotocol/kotlin/sdk/server/KtorServerKt {
@@ -167,7 +167,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServe
167167
public final fun handleGetRequest (Lio/ktor/server/sse/ServerSSESession;Lio/ktor/server/application/ApplicationCall;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
168168
public final fun handlePostRequest (Lio/ktor/server/sse/ServerSSESession;Lio/ktor/server/application/ApplicationCall;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
169169
public final fun handleRequest (Lio/ktor/server/sse/ServerSSESession;Lio/ktor/server/application/ApplicationCall;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
170-
public fun send (Lio/modelcontextprotocol/kotlin/sdk/JSONRPCMessage;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
170+
public fun send (Lio/modelcontextprotocol/kotlin/sdk/types/JSONRPCMessage;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
171171
public final fun setOnSessionClosed (Lkotlin/jvm/functions/Function1;)V
172172
public final fun setOnSessionInitialized (Lkotlin/jvm/functions/Function1;)V
173173
public final fun setSessionIdGenerator (Lkotlin/jvm/functions/Function0;)V

kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ import io.ktor.server.sse.SSE
1515
import io.ktor.server.sse.ServerSSESession
1616
import io.ktor.server.sse.sse
1717
import io.ktor.utils.io.KtorDsl
18+
import io.modelcontextprotocol.kotlin.sdk.shared.AbstractTransport
19+
import io.modelcontextprotocol.kotlin.sdk.types.RPCError
1820
import kotlinx.atomicfu.AtomicRef
1921
import kotlinx.atomicfu.atomic
2022
import kotlinx.atomicfu.update
2123
import kotlinx.collections.immutable.PersistentMap
2224
import kotlinx.collections.immutable.toPersistentMap
2325
import kotlinx.coroutines.awaitCancellation
24-
import io.modelcontextprotocol.kotlin.sdk.ErrorCode
25-
import io.modelcontextprotocol.kotlin.sdk.shared.AbstractTransport
2626

2727
private val logger = KotlinLogging.logger {}
2828

@@ -190,7 +190,7 @@ internal suspend fun RoutingContext.mcpStreamableHttpEndpoint(
190190
logger.info { "Server connection closed for sessionId: ${transport.sessionId}" }
191191
}
192192

193-
server.connect(transport)
193+
server.createSession(transport)
194194

195195
transport
196196
} else {
@@ -200,7 +200,7 @@ internal suspend fun RoutingContext.mcpStreamableHttpEndpoint(
200200
if (transport == null) {
201201
this.call.reject(
202202
HttpStatusCode.BadRequest,
203-
ErrorCode.Unknown(-32000),
203+
RPCError.ErrorCode.CONNECTION_CLOSED,
204204
"Bad Request: No valid session ID provided",
205205
)
206206
return
@@ -234,7 +234,7 @@ internal suspend fun RoutingContext.mcpStatelessStreamableHttpEndpoint(
234234
logger.info { "Server connection closed without sessionId" }
235235
}
236236

237-
server.connect(transport)
237+
server.createSession(transport)
238238

239239
transport.handleRequest(null, this.call)
240240

kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransport.kt

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ import io.ktor.server.response.respondBytes
1616
import io.ktor.server.response.respondNullable
1717
import io.ktor.server.sse.ServerSSESession
1818
import io.ktor.util.collections.ConcurrentMap
19-
import io.modelcontextprotocol.kotlin.sdk.ErrorCode
20-
import io.modelcontextprotocol.kotlin.sdk.JSONRPCError
21-
import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage
22-
import io.modelcontextprotocol.kotlin.sdk.JSONRPCRequest
23-
import io.modelcontextprotocol.kotlin.sdk.JSONRPCResponse
24-
import io.modelcontextprotocol.kotlin.sdk.LATEST_PROTOCOL_VERSION
25-
import io.modelcontextprotocol.kotlin.sdk.Method
26-
import io.modelcontextprotocol.kotlin.sdk.RequestId
27-
import io.modelcontextprotocol.kotlin.sdk.SUPPORTED_PROTOCOL_VERSIONS
2819
import io.modelcontextprotocol.kotlin.sdk.shared.AbstractTransport
29-
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
20+
import io.modelcontextprotocol.kotlin.sdk.types.JSONRPCError
21+
import io.modelcontextprotocol.kotlin.sdk.types.JSONRPCMessage
22+
import io.modelcontextprotocol.kotlin.sdk.types.JSONRPCRequest
23+
import io.modelcontextprotocol.kotlin.sdk.types.JSONRPCResponse
24+
import io.modelcontextprotocol.kotlin.sdk.types.LATEST_PROTOCOL_VERSION
25+
import io.modelcontextprotocol.kotlin.sdk.types.McpJson
26+
import io.modelcontextprotocol.kotlin.sdk.types.Method
27+
import io.modelcontextprotocol.kotlin.sdk.types.RPCError
28+
import io.modelcontextprotocol.kotlin.sdk.types.RequestId
29+
import io.modelcontextprotocol.kotlin.sdk.types.SUPPORTED_PROTOCOL_VERSIONS
3030
import kotlinx.coroutines.job
3131
import kotlinx.coroutines.sync.Mutex
3232
import kotlinx.coroutines.sync.withLock
@@ -237,7 +237,8 @@ public class StreamableHttpServerTransport(
237237
streamsMapping.values.forEach {
238238
try {
239239
it.session?.close()
240-
} catch (_: Exception) {}
240+
} catch (_: Exception) {
241+
}
241242
}
242243
streamsMapping.clear()
243244
requestToResponseMapping.clear()
@@ -250,7 +251,7 @@ public class StreamableHttpServerTransport(
250251
*/
251252
public suspend fun handleRequest(session: ServerSSESession?, call: ApplicationCall) {
252253
validateHeaders(call)?.let { reason ->
253-
call.reject(HttpStatusCode.Forbidden, ErrorCode.Unknown(-32000), reason)
254+
call.reject(HttpStatusCode.Forbidden, RPCError.ErrorCode.CONNECTION_CLOSED, reason)
254255
_onError(Error(reason))
255256
return
256257
}
@@ -264,7 +265,7 @@ public class StreamableHttpServerTransport(
264265

265266
else -> call.run {
266267
response.header(HttpHeaders.Allow, "GET, POST, DELETE")
267-
reject(HttpStatusCode.MethodNotAllowed, ErrorCode.Unknown(-32000), "Method not allowed.")
268+
reject(HttpStatusCode.MethodNotAllowed, RPCError.ErrorCode.CONNECTION_CLOSED, "Method not allowed.")
268269
}
269270
}
270271
}
@@ -283,7 +284,7 @@ public class StreamableHttpServerTransport(
283284
if (!isAcceptEventStream || !isAcceptJson) {
284285
call.reject(
285286
HttpStatusCode.NotAcceptable,
286-
ErrorCode.Unknown(-32000),
287+
RPCError.ErrorCode.CONNECTION_CLOSED,
287288
"Not Acceptable: Client must accept both application/json and text/event-stream",
288289
)
289290
return
@@ -292,7 +293,7 @@ public class StreamableHttpServerTransport(
292293
if (!call.request.contentType().match(ContentType.Application.Json)) {
293294
call.reject(
294295
HttpStatusCode.UnsupportedMediaType,
295-
ErrorCode.Unknown(-32000),
296+
RPCError.ErrorCode.CONNECTION_CLOSED,
296297
"Unsupported Media Type: Content-Type must be application/json",
297298
)
298299
return
@@ -307,15 +308,15 @@ public class StreamableHttpServerTransport(
307308
if (initialized.load() && sessionId != null) {
308309
call.reject(
309310
HttpStatusCode.BadRequest,
310-
ErrorCode.Defined.InvalidRequest,
311+
RPCError.ErrorCode.INVALID_REQUEST,
311312
"Invalid Request: Server already initialized",
312313
)
313314
return
314315
}
315316
if (messages.size > 1) {
316317
call.reject(
317318
HttpStatusCode.BadRequest,
318-
ErrorCode.Defined.InvalidRequest,
319+
RPCError.ErrorCode.INVALID_REQUEST,
319320
"Invalid Request: Only one initialization request is allowed",
320321
)
321322
return
@@ -354,7 +355,7 @@ public class StreamableHttpServerTransport(
354355
} catch (e: Exception) {
355356
call.reject(
356357
HttpStatusCode.BadRequest,
357-
ErrorCode.Defined.ParseError,
358+
RPCError.ErrorCode.PARSE_ERROR,
358359
"Parse error: ${e.message}",
359360
)
360361
_onError(e)
@@ -365,7 +366,7 @@ public class StreamableHttpServerTransport(
365366
if (enableJsonResponse) {
366367
call.reject(
367368
HttpStatusCode.MethodNotAllowed,
368-
ErrorCode.Unknown(-32000),
369+
RPCError.ErrorCode.CONNECTION_CLOSED,
369370
"Method not allowed.",
370371
)
371372
return
@@ -376,7 +377,7 @@ public class StreamableHttpServerTransport(
376377
if (!acceptHeader.accepts(ContentType.Text.EventStream)) {
377378
call.reject(
378379
HttpStatusCode.NotAcceptable,
379-
ErrorCode.Unknown(-32000),
380+
RPCError.ErrorCode.CONNECTION_CLOSED,
380381
"Not Acceptable: Client must accept text/event-stream",
381382
)
382383
return
@@ -394,7 +395,7 @@ public class StreamableHttpServerTransport(
394395
if (STANDALONE_SSE_STREAM_ID in streamsMapping) {
395396
call.reject(
396397
HttpStatusCode.Conflict,
397-
ErrorCode.Unknown(-32000),
398+
RPCError.ErrorCode.CONNECTION_CLOSED,
398399
"Conflict: Only one SSE stream is allowed per session",
399400
)
400401
return
@@ -410,7 +411,7 @@ public class StreamableHttpServerTransport(
410411
if (enableJsonResponse) {
411412
call.reject(
412413
HttpStatusCode.MethodNotAllowed,
413-
ErrorCode.Unknown(-32000),
414+
RPCError.ErrorCode.CONNECTION_CLOSED,
414415
"Method not allowed.",
415416
)
416417
}
@@ -449,7 +450,7 @@ public class StreamableHttpServerTransport(
449450
if (!initialized.load()) {
450451
call.reject(
451452
HttpStatusCode.BadRequest,
452-
ErrorCode.Unknown(-32000),
453+
RPCError.ErrorCode.CONNECTION_CLOSED,
453454
"Bad Request: Server not initialized",
454455
)
455456
return false
@@ -461,7 +462,7 @@ public class StreamableHttpServerTransport(
461462
headerId == null -> {
462463
call.reject(
463464
HttpStatusCode.BadRequest,
464-
ErrorCode.Unknown(-32000),
465+
RPCError.ErrorCode.CONNECTION_CLOSED,
465466
"Bad Request: Mcp-Session-Id header is required",
466467
)
467468
false
@@ -470,7 +471,7 @@ public class StreamableHttpServerTransport(
470471
headerId != sessionId -> {
471472
call.reject(
472473
HttpStatusCode.NotFound,
473-
ErrorCode.Unknown(-32001),
474+
-32001,
474475
"Session not found",
475476
)
476477
false
@@ -487,7 +488,7 @@ public class StreamableHttpServerTransport(
487488
!in SUPPORTED_PROTOCOL_VERSIONS -> {
488489
call.reject(
489490
HttpStatusCode.BadRequest,
490-
ErrorCode.Unknown(-32000),
491+
RPCError.ErrorCode.CONNECTION_CLOSED,
491492
"Bad Request: Unsupported protocol version (supported versions: ${
492493
SUPPORTED_PROTOCOL_VERSIONS.joinToString(
493494
", ",
@@ -531,10 +532,10 @@ public class StreamableHttpServerTransport(
531532
else -> {
532533
call.reject(
533534
HttpStatusCode.BadRequest,
534-
ErrorCode.Defined.InvalidRequest,
535+
RPCError.ErrorCode.INVALID_REQUEST,
535536
"Invalid Request: unable to parse JSON body",
536537
)
537-
return null
538+
null
538539
}
539540
}
540541
}
@@ -565,12 +566,12 @@ public class StreamableHttpServerTransport(
565566
}
566567
}
567568

568-
internal suspend fun ApplicationCall.reject(status: HttpStatusCode, code: ErrorCode, message: String) {
569+
internal suspend fun ApplicationCall.reject(status: HttpStatusCode, code: Int, message: String) {
569570
this.response.status(status)
570571
this.respond(
571-
JSONRPCResponse(
572-
id = RequestId.StringId("server-error"),
573-
error = JSONRPCError(message = message, code = code),
572+
JSONRPCError(
573+
id = null,
574+
error = RPCError(code = code, message = message),
574575
),
575576
)
576577
}

0 commit comments

Comments
 (0)