@@ -18,6 +18,32 @@ import kotlinx.serialization.json.longOrNull
1818
1919private val logger = KotlinLogging .logger {}
2020
21+ // ============================================================================
22+ // Utility Functions
23+ // ============================================================================
24+
25+ /* *
26+ * Safely extracts the method field from a JSON element.
27+ * Returns null if the method field is not present.
28+ */
29+ private fun JsonElement.getMethodOrNull (): String? = jsonObject[" method" ]?.jsonPrimitive?.content
30+
31+ /* *
32+ * Extracts the method field from a JSON element.
33+ * Throws [SerializationException] if the method field is not present.
34+ */
35+ private fun JsonElement.getMethod (): String =
36+ getMethodOrNull() ? : throw SerializationException (" Missing required 'method' field in notification" )
37+
38+ // ============================================================================
39+ // Method Serializer
40+ // ============================================================================
41+
42+ /* *
43+ * Custom serializer for [Method] that handles both defined and custom methods.
44+ * Defined methods are deserialized to [Method.Defined], while unknown methods
45+ * are deserialized to [Method.Custom].
46+ */
2147internal object MethodSerializer : KSerializer<Method> {
2248 override val descriptor: SerialDescriptor =
2349 PrimitiveSerialDescriptor (" io.modelcontextprotocol.kotlin.sdk.types.Method" , PrimitiveKind .STRING )
@@ -36,6 +62,14 @@ internal object MethodSerializer : KSerializer<Method> {
3662 }
3763}
3864
65+ // ============================================================================
66+ // Reference Serializers
67+ // ============================================================================
68+
69+ /* *
70+ * Polymorphic serializer for [Reference] types.
71+ * Determines the concrete type based on the "type" field in JSON.
72+ */
3973internal object ReferencePolymorphicSerializer : JsonContentPolymorphicSerializer<Reference>(Reference : :class) {
4074 override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <Reference > =
4175 when (element.jsonObject.getValue(" type" ).jsonPrimitive.content) {
@@ -45,6 +79,14 @@ internal object ReferencePolymorphicSerializer : JsonContentPolymorphicSerialize
4579 }
4680}
4781
82+ // ============================================================================
83+ // Content Serializers
84+ // ============================================================================
85+
86+ /* *
87+ * Polymorphic serializer for [ContentBlock] types.
88+ * Determines the concrete type based on the "type" field in JSON.
89+ */
4890internal object ContentBlockPolymorphicSerializer :
4991 JsonContentPolymorphicSerializer <ContentBlock >(ContentBlock ::class ) {
5092 override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <ContentBlock > =
@@ -58,6 +100,10 @@ internal object ContentBlockPolymorphicSerializer :
58100 }
59101}
60102
103+ /* *
104+ * Polymorphic serializer for [MediaContent] types (text, image, audio).
105+ * Determines the concrete type based on the "type" field in JSON.
106+ */
61107internal object MediaContentPolymorphicSerializer :
62108 JsonContentPolymorphicSerializer <MediaContent >(MediaContent ::class ) {
63109 override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <MediaContent > =
@@ -69,6 +115,14 @@ internal object MediaContentPolymorphicSerializer :
69115 }
70116}
71117
118+ // ============================================================================
119+ // Resource Serializers
120+ // ============================================================================
121+
122+ /* *
123+ * Polymorphic serializer for [ResourceContents] types.
124+ * Determines the concrete type based on the presence of "text" or "blob" fields.
125+ */
72126internal object ResourceContentsPolymorphicSerializer :
73127 JsonContentPolymorphicSerializer <ResourceContents >(ResourceContents ::class ) {
74128 override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <ResourceContents > {
@@ -81,6 +135,14 @@ internal object ResourceContentsPolymorphicSerializer :
81135 }
82136}
83137
138+ // ============================================================================
139+ // Request Serializers
140+ // ============================================================================
141+
142+ /* *
143+ * Selects the appropriate deserializer for client requests based on the method name.
144+ * Returns null if the method is not a known client request method.
145+ */
84146internal fun selectClientRequestDeserializer (method : String ): DeserializationStrategy <ClientRequest >? = when (method) {
85147 Method .Defined .CompletionComplete .value -> CompleteRequest .serializer()
86148 Method .Defined .Initialize .value -> InitializeRequest .serializer()
@@ -98,10 +160,43 @@ internal fun selectClientRequestDeserializer(method: String): DeserializationStr
98160 else -> null
99161}
100162
101- private fun JsonElement.getMethodOrNull (): String? = jsonObject[" method" ]?.jsonPrimitive?.content
102- private fun JsonElement.getMethod (): String =
103- getMethodOrNull() ? : throw SerializationException (" Missing required 'method' field in notification" )
163+ /* *
164+ * Selects the appropriate deserializer for server requests based on the method name.
165+ * Returns null if the method is not a known server request method.
166+ */
167+ internal fun selectServerRequestDeserializer (method : String ): DeserializationStrategy <ServerRequest >? = when (method) {
168+ Method .Defined .ElicitationCreate .value -> ElicitRequest .serializer()
169+ Method .Defined .Ping .value -> PingRequest .serializer()
170+ Method .Defined .RootsList .value -> ListRootsRequest .serializer()
171+ Method .Defined .SamplingCreateMessage .value -> CreateMessageRequest .serializer()
172+ else -> null
173+ }
104174
175+ /* *
176+ * Polymorphic serializer for [Request] types.
177+ * Supports both client and server requests, as well as custom requests.
178+ */
179+ internal object RequestPolymorphicSerializer : JsonContentPolymorphicSerializer<Request>(Request : :class) {
180+ override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <Request > {
181+ val method = element.getMethodOrNull() ? : run {
182+ logger.error { " No method in $element " }
183+ error(" No method in $element " )
184+ }
185+
186+ return selectClientRequestDeserializer(method)
187+ ? : selectServerRequestDeserializer(method)
188+ ? : CustomRequest .serializer()
189+ }
190+ }
191+
192+ // ============================================================================
193+ // Notification Serializers
194+ // ============================================================================
195+
196+ /* *
197+ * Selects the appropriate deserializer for client notifications based on the method name.
198+ * Returns null if the method is not a known client notification method.
199+ */
105200private fun selectClientNotificationDeserializer (element : JsonElement ): DeserializationStrategy <ClientNotification >? {
106201 val method = element.getMethodOrNull() ? : return null
107202
@@ -114,21 +209,10 @@ private fun selectClientNotificationDeserializer(element: JsonElement): Deserial
114209 }
115210}
116211
117- internal object ClientNotificationPolymorphicSerializer :
118- JsonContentPolymorphicSerializer <ClientNotification >(ClientNotification ::class ) {
119- override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <ClientNotification > =
120- selectClientNotificationDeserializer(element)
121- ? : CustomNotification .serializer()
122- }
123-
124- internal fun selectServerRequestDeserializer (method : String ): DeserializationStrategy <ServerRequest >? = when (method) {
125- Method .Defined .ElicitationCreate .value -> ElicitRequest .serializer()
126- Method .Defined .Ping .value -> PingRequest .serializer()
127- Method .Defined .RootsList .value -> ListRootsRequest .serializer()
128- Method .Defined .SamplingCreateMessage .value -> CreateMessageRequest .serializer()
129- else -> null
130- }
131-
212+ /* *
213+ * Selects the appropriate deserializer for server notifications based on the method name.
214+ * Returns null if the method is not a known server notification method.
215+ */
132216internal fun selectServerNotificationDeserializer (element : JsonElement ): DeserializationStrategy <ServerNotification >? {
133217 val method = element.getMethodOrNull() ? : return null
134218
@@ -144,13 +228,10 @@ internal fun selectServerNotificationDeserializer(element: JsonElement): Deseria
144228 }
145229}
146230
147- internal object ServerNotificationPolymorphicSerializer :
148- JsonContentPolymorphicSerializer <ServerNotification >(ServerNotification ::class ) {
149- override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <ServerNotification > =
150- selectServerNotificationDeserializer(element)
151- ? : CustomNotification .serializer()
152- }
153-
231+ /* *
232+ * Polymorphic serializer for [Notification] types.
233+ * Supports both client and server notifications, as well as custom notifications.
234+ */
154235internal object NotificationPolymorphicSerializer :
155236 JsonContentPolymorphicSerializer <Notification >(Notification ::class ) {
156237 override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <Notification > =
@@ -159,35 +240,48 @@ internal object NotificationPolymorphicSerializer :
159240 ? : CustomNotification .serializer()
160241}
161242
162- internal object RequestPolymorphicSerializer : JsonContentPolymorphicSerializer<Request>(Request : :class) {
163- override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <Request > {
164- val method = element.getMethodOrNull() ? : run {
165- logger.error { " No method in $element " }
166- error(" No method in $element " )
167- }
243+ /* *
244+ * Polymorphic serializer for [ClientNotification] types.
245+ * Falls back to [CustomNotification] for unknown methods.
246+ */
247+ internal object ClientNotificationPolymorphicSerializer :
248+ JsonContentPolymorphicSerializer <ClientNotification >(ClientNotification ::class ) {
249+ override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <ClientNotification > =
250+ selectClientNotificationDeserializer(element)
251+ ? : CustomNotification .serializer()
252+ }
168253
169- return selectClientRequestDeserializer(method)
170- ? : selectServerRequestDeserializer(method)
171- ? : CustomRequest .serializer()
172- }
254+ /* *
255+ * Polymorphic serializer for [ServerNotification] types.
256+ * Falls back to [CustomNotification] for unknown methods.
257+ */
258+ internal object ServerNotificationPolymorphicSerializer :
259+ JsonContentPolymorphicSerializer <ServerNotification >(ServerNotification ::class ) {
260+ override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <ServerNotification > =
261+ selectServerNotificationDeserializer(element)
262+ ? : CustomNotification .serializer()
173263}
174264
175- private fun selectServerResultDeserializer (element : JsonElement ): DeserializationStrategy <ServerResult >? {
265+ // ============================================================================
266+ // Result Serializers
267+ // ============================================================================
268+
269+ /* *
270+ * Selects the appropriate deserializer for empty results.
271+ * Returns EmptyResult serializer if the JSON object is empty or contains only metadata.
272+ */
273+ private fun selectEmptyResult (element : JsonElement ): DeserializationStrategy <EmptyResult >? {
176274 val jsonObject = element.jsonObject
177275 return when {
178- jsonObject.contains(" protocolVersion" ) && jsonObject.contains(" capabilities" ) -> InitializeResult .serializer()
179- jsonObject.contains(" completion" ) -> CompleteResult .serializer()
180- jsonObject.contains(" tools" ) -> ListToolsResult .serializer()
181- jsonObject.contains(" resources" ) -> ListResourcesResult .serializer()
182- jsonObject.contains(" resourceTemplates" ) -> ListResourceTemplatesResult .serializer()
183- jsonObject.contains(" prompts" ) -> ListPromptsResult .serializer()
184- jsonObject.contains(" messages" ) -> GetPromptResult .serializer()
185- jsonObject.contains(" contents" ) -> ReadResourceResult .serializer()
186- jsonObject.contains(" content" ) -> CallToolResult .serializer()
276+ jsonObject.isEmpty() || (jsonObject.size == 1 && jsonObject.contains(" _meta" )) -> EmptyResult .serializer()
187277 else -> null
188278 }
189279}
190280
281+ /* *
282+ * Selects the appropriate deserializer for client results based on JSON content.
283+ * Returns null if the structure doesn't match any known client result type.
284+ */
191285private fun selectClientResultDeserializer (element : JsonElement ): DeserializationStrategy <ClientResult >? {
192286 val jsonObject = element.jsonObject
193287 return when {
@@ -198,22 +292,44 @@ private fun selectClientResultDeserializer(element: JsonElement): Deserializatio
198292 }
199293}
200294
201- private fun selectEmptyResult (element : JsonElement ): DeserializationStrategy <EmptyResult >? {
295+ /* *
296+ * Selects the appropriate deserializer for server results based on JSON content.
297+ * Returns null if the structure doesn't match any known server result type.
298+ */
299+ private fun selectServerResultDeserializer (element : JsonElement ): DeserializationStrategy <ServerResult >? {
202300 val jsonObject = element.jsonObject
203301 return when {
204- jsonObject.isEmpty() || (jsonObject.size == 1 && jsonObject.contains(" _meta" )) -> EmptyResult .serializer()
302+ jsonObject.contains(" protocolVersion" ) && jsonObject.contains(" capabilities" ) -> InitializeResult .serializer()
303+ jsonObject.contains(" completion" ) -> CompleteResult .serializer()
304+ jsonObject.contains(" tools" ) -> ListToolsResult .serializer()
305+ jsonObject.contains(" resources" ) -> ListResourcesResult .serializer()
306+ jsonObject.contains(" resourceTemplates" ) -> ListResourceTemplatesResult .serializer()
307+ jsonObject.contains(" prompts" ) -> ListPromptsResult .serializer()
308+ jsonObject.contains(" messages" ) -> GetPromptResult .serializer()
309+ jsonObject.contains(" contents" ) -> ReadResourceResult .serializer()
310+ jsonObject.contains(" content" ) -> CallToolResult .serializer()
205311 else -> null
206312 }
207313}
208314
209- internal object ServerResultPolymorphicSerializer :
210- JsonContentPolymorphicSerializer <ServerResult >(ServerResult ::class ) {
211- override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <ServerResult > =
212- selectServerResultDeserializer(element)
315+ /* *
316+ * Polymorphic serializer for [RequestResult] types.
317+ * Supports both client and server results.
318+ * Throws [SerializationException] if the result type cannot be determined.
319+ */
320+ internal object RequestResultPolymorphicSerializer :
321+ JsonContentPolymorphicSerializer <RequestResult >(RequestResult ::class ) {
322+ override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <RequestResult > =
323+ selectClientResultDeserializer(element)
324+ ? : selectServerResultDeserializer(element)
213325 ? : selectEmptyResult(element)
214326 ? : throw SerializationException (" Cannot determine RequestResult type from JSON: ${element.jsonObject.keys} " )
215327}
216328
329+ /* *
330+ * Polymorphic serializer for [ClientResult] types.
331+ * Throws [SerializationException] if the result type cannot be determined.
332+ */
217333internal object ClientResultPolymorphicSerializer :
218334 JsonContentPolymorphicSerializer <ClientResult >(ClientResult ::class ) {
219335 override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <ClientResult > =
@@ -222,15 +338,30 @@ internal object ClientResultPolymorphicSerializer :
222338 ? : throw SerializationException (" Cannot determine RequestResult type from JSON: ${element.jsonObject.keys} " )
223339}
224340
225- internal object RequestResultPolymorphicSerializer :
226- JsonContentPolymorphicSerializer <RequestResult >(RequestResult ::class ) {
227- override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <RequestResult > =
228- selectClientResultDeserializer(element)
229- ? : selectServerResultDeserializer(element)
341+ /* *
342+ * Polymorphic serializer for [ServerResult] types.
343+ * Throws [SerializationException] if the result type cannot be determined.
344+ */
345+ internal object ServerResultPolymorphicSerializer :
346+ JsonContentPolymorphicSerializer <ServerResult >(ServerResult ::class ) {
347+ override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <ServerResult > =
348+ selectServerResultDeserializer(element)
230349 ? : selectEmptyResult(element)
231350 ? : throw SerializationException (" Cannot determine RequestResult type from JSON: ${element.jsonObject.keys} " )
232351}
233352
353+ // ============================================================================
354+ // JSON-RPC Serializers
355+ // ============================================================================
356+
357+ /* *
358+ * Polymorphic serializer for [JSONRPCMessage] types.
359+ * Determines the message type based on the presence of specific fields:
360+ * - "error" -> JSONRPCError
361+ * - "result" -> JSONRPCResponse
362+ * - "method" + "id" -> JSONRPCRequest
363+ * - "method" -> JSONRPCNotification
364+ */
234365internal object JSONRPCMessagePolymorphicSerializer :
235366 JsonContentPolymorphicSerializer <JSONRPCMessage >(JSONRPCMessage ::class ) {
236367 override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <JSONRPCMessage > {
@@ -245,6 +376,10 @@ internal object JSONRPCMessagePolymorphicSerializer :
245376 }
246377}
247378
379+ /* *
380+ * Polymorphic serializer for [RequestId] types.
381+ * Supports both string and number IDs.
382+ */
248383internal object RequestIdPolymorphicSerializer : JsonContentPolymorphicSerializer<RequestId>(RequestId : :class) {
249384 override fun selectDeserializer (element : JsonElement ): DeserializationStrategy <RequestId > = when (element) {
250385 is JsonPrimitive if (element.isString) -> RequestId .StringId .serializer()
0 commit comments