parent
512e7b65aa
commit
16f60b4bc4
4 changed files with 60 additions and 5 deletions
|
|
@ -15,6 +15,7 @@ import io.modelcontextprotocol.kotlin.sdk.PingRequest
|
||||||
import io.modelcontextprotocol.kotlin.sdk.Progress
|
import io.modelcontextprotocol.kotlin.sdk.Progress
|
||||||
import io.modelcontextprotocol.kotlin.sdk.ProgressNotification
|
import io.modelcontextprotocol.kotlin.sdk.ProgressNotification
|
||||||
import io.modelcontextprotocol.kotlin.sdk.Request
|
import io.modelcontextprotocol.kotlin.sdk.Request
|
||||||
|
import io.modelcontextprotocol.kotlin.sdk.RequestId
|
||||||
import io.modelcontextprotocol.kotlin.sdk.RequestResult
|
import io.modelcontextprotocol.kotlin.sdk.RequestResult
|
||||||
import io.modelcontextprotocol.kotlin.sdk.fromJSON
|
import io.modelcontextprotocol.kotlin.sdk.fromJSON
|
||||||
import io.modelcontextprotocol.kotlin.sdk.toJSON
|
import io.modelcontextprotocol.kotlin.sdk.toJSON
|
||||||
|
|
@ -119,11 +120,11 @@ public abstract class Protocol<SendRequestT : Request, SendNotificationT : Notif
|
||||||
mutableMapOf()
|
mutableMapOf()
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal val responseHandlers: MutableMap<Long, (response: JSONRPCResponse?, error: Exception?) -> Unit> =
|
internal val responseHandlers: MutableMap<RequestId, (response: JSONRPCResponse?, error: Exception?) -> Unit> =
|
||||||
mutableMapOf()
|
mutableMapOf()
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal val progressHandlers: MutableMap<Long, ProgressCallback> = mutableMapOf()
|
internal val progressHandlers: MutableMap<RequestId, ProgressCallback> = mutableMapOf()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for when the connection is closed for any reason.
|
* Callback for when the connection is closed for any reason.
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ private val REQUEST_MESSAGE_ID = AtomicLong(0L)
|
||||||
* A progress token, used to associate progress notifications with the original request.
|
* A progress token, used to associate progress notifications with the original request.
|
||||||
* Stores message ID.
|
* Stores message ID.
|
||||||
*/
|
*/
|
||||||
public typealias ProgressToken = Long
|
public typealias ProgressToken = RequestId
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An opaque token used to represent a cursor for pagination.
|
* An opaque token used to represent a cursor for pagination.
|
||||||
|
|
@ -191,7 +191,14 @@ public data class EmptyRequestResult(
|
||||||
/**
|
/**
|
||||||
* A uniquely identifying ID for a request in JSON-RPC.
|
* A uniquely identifying ID for a request in JSON-RPC.
|
||||||
*/
|
*/
|
||||||
public typealias RequestId = Long
|
@Serializable(with = RequestIdSerializer::class)
|
||||||
|
public sealed interface RequestId {
|
||||||
|
@Serializable
|
||||||
|
public data class StringId(val value: String) : RequestId
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
public data class NumberId(val value: Long) : RequestId
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a JSON-RPC message in the protocol.
|
* Represents a JSON-RPC message in the protocol.
|
||||||
|
|
@ -204,7 +211,7 @@ public sealed interface JSONRPCMessage
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
public data class JSONRPCRequest(
|
public data class JSONRPCRequest(
|
||||||
val id: RequestId = REQUEST_MESSAGE_ID.incrementAndGet(),
|
val id: RequestId = RequestId.NumberId(REQUEST_MESSAGE_ID.incrementAndGet()),
|
||||||
val method: String,
|
val method: String,
|
||||||
val params: JsonElement? = null,
|
val params: JsonElement? = null,
|
||||||
val jsonrpc: String = JSONRPC_VERSION,
|
val jsonrpc: String = JSONRPC_VERSION,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.descriptors.PrimitiveKind
|
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||||
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||||
import kotlinx.serialization.encoding.Decoder
|
import kotlinx.serialization.encoding.Decoder
|
||||||
import kotlinx.serialization.encoding.Encoder
|
import kotlinx.serialization.encoding.Encoder
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
|
|
@ -270,3 +271,29 @@ internal object JSONRPCMessagePolymorphicSerializer :
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val EmptyJsonObject = JsonObject(emptyMap())
|
internal val EmptyJsonObject = JsonObject(emptyMap())
|
||||||
|
|
||||||
|
public class RequestIdSerializer : KSerializer<RequestId> {
|
||||||
|
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("RequestId")
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): RequestId {
|
||||||
|
val jsonDecoder = decoder as? JsonDecoder ?: error("Can only deserialize JSON")
|
||||||
|
val element = jsonDecoder.decodeJsonElement()
|
||||||
|
|
||||||
|
return when (element) {
|
||||||
|
is JsonPrimitive -> when {
|
||||||
|
element.isString -> RequestId.StringId(element.content)
|
||||||
|
element.longOrNull != null -> RequestId.NumberId(element.long)
|
||||||
|
else -> error("Invalid RequestId type")
|
||||||
|
}
|
||||||
|
else -> error("Invalid RequestId format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: RequestId) {
|
||||||
|
val jsonEncoder = encoder as? JsonEncoder ?: error("Can only serialize JSON")
|
||||||
|
when (value) {
|
||||||
|
is RequestId.StringId -> jsonEncoder.encodeString(value.value)
|
||||||
|
is RequestId.NumberId -> jsonEncoder.encodeLong(value.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,4 +24,24 @@ class TypesTest {
|
||||||
val line = "{\"result\":{\"content\":[{\"type\":\"text\"}],\"isError\":false},\"jsonrpc\":\"2.0\",\"id\":4}"
|
val line = "{\"result\":{\"content\":[{\"type\":\"text\"}],\"isError\":false},\"jsonrpc\":\"2.0\",\"id\":4}"
|
||||||
McpJson.decodeFromString<JSONRPCMessage>(line)
|
McpJson.decodeFromString<JSONRPCMessage>(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testJSONRPCMessageWithStringId() {
|
||||||
|
val line = """
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "initialize",
|
||||||
|
"id": "ebf9f64a-0",
|
||||||
|
"params": {
|
||||||
|
"protocolVersion": "2024-11-05",
|
||||||
|
"capabilities": {},
|
||||||
|
"clientInfo": {
|
||||||
|
"name": "mcp-java-client",
|
||||||
|
"version": "0.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
McpJson.decodeFromString<JSONRPCMessage>(line)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue