11package io.modelcontextprotocol.kotlin.sdk.client
22
33import io.github.oshai.kotlinlogging.KotlinLogging
4- import io.modelcontextprotocol.kotlin.sdk.CallToolRequest
5- import io.modelcontextprotocol.kotlin.sdk.CallToolResult
6- import io.modelcontextprotocol.kotlin.sdk.CallToolResultBase
7- import io.modelcontextprotocol.kotlin.sdk.ClientCapabilities
8- import io.modelcontextprotocol.kotlin.sdk.CompatibilityCallToolResult
9- import io.modelcontextprotocol.kotlin.sdk.CompleteRequest
10- import io.modelcontextprotocol.kotlin.sdk.CompleteResult
11- import io.modelcontextprotocol.kotlin.sdk.CreateElicitationRequest
12- import io.modelcontextprotocol.kotlin.sdk.CreateElicitationResult
13- import io.modelcontextprotocol.kotlin.sdk.EmptyRequestResult
14- import io.modelcontextprotocol.kotlin.sdk.GetPromptRequest
15- import io.modelcontextprotocol.kotlin.sdk.GetPromptResult
16- import io.modelcontextprotocol.kotlin.sdk.Implementation
17- import io.modelcontextprotocol.kotlin.sdk.InitializeRequest
18- import io.modelcontextprotocol.kotlin.sdk.InitializeResult
19- import io.modelcontextprotocol.kotlin.sdk.InitializedNotification
20- import io.modelcontextprotocol.kotlin.sdk.LATEST_PROTOCOL_VERSION
21- import io.modelcontextprotocol.kotlin.sdk.ListPromptsRequest
22- import io.modelcontextprotocol.kotlin.sdk.ListPromptsResult
23- import io.modelcontextprotocol.kotlin.sdk.ListResourceTemplatesRequest
24- import io.modelcontextprotocol.kotlin.sdk.ListResourceTemplatesResult
25- import io.modelcontextprotocol.kotlin.sdk.ListResourcesRequest
26- import io.modelcontextprotocol.kotlin.sdk.ListResourcesResult
27- import io.modelcontextprotocol.kotlin.sdk.ListRootsRequest
28- import io.modelcontextprotocol.kotlin.sdk.ListRootsResult
29- import io.modelcontextprotocol.kotlin.sdk.ListToolsRequest
30- import io.modelcontextprotocol.kotlin.sdk.ListToolsResult
31- import io.modelcontextprotocol.kotlin.sdk.LoggingLevel
32- import io.modelcontextprotocol.kotlin.sdk.LoggingMessageNotification.SetLevelRequest
33- import io.modelcontextprotocol.kotlin.sdk.Method
34- import io.modelcontextprotocol.kotlin.sdk.PingRequest
35- import io.modelcontextprotocol.kotlin.sdk.ReadResourceRequest
36- import io.modelcontextprotocol.kotlin.sdk.ReadResourceResult
37- import io.modelcontextprotocol.kotlin.sdk.Root
38- import io.modelcontextprotocol.kotlin.sdk.RootsListChangedNotification
39- import io.modelcontextprotocol.kotlin.sdk.SUPPORTED_PROTOCOL_VERSIONS
40- import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities
41- import io.modelcontextprotocol.kotlin.sdk.SubscribeRequest
42- import io.modelcontextprotocol.kotlin.sdk.UnsubscribeRequest
434import io.modelcontextprotocol.kotlin.sdk.shared.Protocol
445import io.modelcontextprotocol.kotlin.sdk.shared.ProtocolOptions
456import io.modelcontextprotocol.kotlin.sdk.shared.RequestOptions
467import io.modelcontextprotocol.kotlin.sdk.shared.Transport
8+ import io.modelcontextprotocol.kotlin.sdk.types.CallToolRequest
9+ import io.modelcontextprotocol.kotlin.sdk.types.CallToolRequestParams
10+ import io.modelcontextprotocol.kotlin.sdk.types.CallToolResult
11+ import io.modelcontextprotocol.kotlin.sdk.types.ClientCapabilities
12+ import io.modelcontextprotocol.kotlin.sdk.types.CompleteRequest
13+ import io.modelcontextprotocol.kotlin.sdk.types.CompleteResult
14+ import io.modelcontextprotocol.kotlin.sdk.types.ElicitRequest
15+ import io.modelcontextprotocol.kotlin.sdk.types.ElicitResult
16+ import io.modelcontextprotocol.kotlin.sdk.types.EmptyResult
17+ import io.modelcontextprotocol.kotlin.sdk.types.GetPromptRequest
18+ import io.modelcontextprotocol.kotlin.sdk.types.GetPromptResult
19+ import io.modelcontextprotocol.kotlin.sdk.types.Implementation
20+ import io.modelcontextprotocol.kotlin.sdk.types.InitializeRequest
21+ import io.modelcontextprotocol.kotlin.sdk.types.InitializeRequestParams
22+ import io.modelcontextprotocol.kotlin.sdk.types.InitializeResult
23+ import io.modelcontextprotocol.kotlin.sdk.types.InitializedNotification
24+ import io.modelcontextprotocol.kotlin.sdk.types.LATEST_PROTOCOL_VERSION
25+ import io.modelcontextprotocol.kotlin.sdk.types.ListPromptsRequest
26+ import io.modelcontextprotocol.kotlin.sdk.types.ListPromptsResult
27+ import io.modelcontextprotocol.kotlin.sdk.types.ListResourceTemplatesRequest
28+ import io.modelcontextprotocol.kotlin.sdk.types.ListResourceTemplatesResult
29+ import io.modelcontextprotocol.kotlin.sdk.types.ListResourcesRequest
30+ import io.modelcontextprotocol.kotlin.sdk.types.ListResourcesResult
31+ import io.modelcontextprotocol.kotlin.sdk.types.ListRootsRequest
32+ import io.modelcontextprotocol.kotlin.sdk.types.ListRootsResult
33+ import io.modelcontextprotocol.kotlin.sdk.types.ListToolsRequest
34+ import io.modelcontextprotocol.kotlin.sdk.types.ListToolsResult
35+ import io.modelcontextprotocol.kotlin.sdk.types.LoggingLevel
36+ import io.modelcontextprotocol.kotlin.sdk.types.Method
37+ import io.modelcontextprotocol.kotlin.sdk.types.PingRequest
38+ import io.modelcontextprotocol.kotlin.sdk.types.ReadResourceRequest
39+ import io.modelcontextprotocol.kotlin.sdk.types.ReadResourceResult
40+ import io.modelcontextprotocol.kotlin.sdk.types.RequestMeta
41+ import io.modelcontextprotocol.kotlin.sdk.types.Root
42+ import io.modelcontextprotocol.kotlin.sdk.types.RootsListChangedNotification
43+ import io.modelcontextprotocol.kotlin.sdk.types.SUPPORTED_PROTOCOL_VERSIONS
44+ import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
45+ import io.modelcontextprotocol.kotlin.sdk.types.SetLevelRequest
46+ import io.modelcontextprotocol.kotlin.sdk.types.SetLevelRequestParams
47+ import io.modelcontextprotocol.kotlin.sdk.types.SubscribeRequest
48+ import io.modelcontextprotocol.kotlin.sdk.types.UnsubscribeRequest
49+ import io.modelcontextprotocol.kotlin.sdk.types.toJson
4750import kotlinx.atomicfu.atomic
4851import kotlinx.atomicfu.getAndUpdate
4952import kotlinx.atomicfu.update
5053import kotlinx.collections.immutable.minus
5154import kotlinx.collections.immutable.persistentMapOf
5255import kotlinx.collections.immutable.toPersistentSet
53- import kotlinx.serialization.ExperimentalSerializationApi
54- import kotlinx.serialization.json.JsonElement
55- import kotlinx.serialization.json.JsonNull
5656import kotlinx.serialization.json.JsonObject
57- import kotlinx.serialization.json.JsonPrimitive
58- import kotlinx.serialization.json.add
59- import kotlinx.serialization.json.buildJsonArray
60- import kotlinx.serialization.json.buildJsonObject
6157import kotlin.coroutines.cancellation.CancellationException
6258
6359private val logger = KotlinLogging .logger {}
@@ -152,9 +148,11 @@ public open class Client(private val clientInfo: Implementation, options: Client
152148
153149 try {
154150 val message = InitializeRequest (
155- protocolVersion = LATEST_PROTOCOL_VERSION ,
156- capabilities = capabilities,
157- clientInfo = clientInfo,
151+ InitializeRequestParams (
152+ protocolVersion = LATEST_PROTOCOL_VERSION ,
153+ capabilities = capabilities,
154+ clientInfo = clientInfo,
155+ ),
158156 )
159157 val result = request<InitializeResult >(message)
160158
@@ -293,8 +291,7 @@ public open class Client(private val clientInfo: Implementation, options: Client
293291 * @param options Optional request options.
294292 * @throws IllegalStateException If the server does not support the ping method (unlikely).
295293 */
296- public suspend fun ping (options : RequestOptions ? = null): EmptyRequestResult =
297- request<EmptyRequestResult >(PingRequest (), options)
294+ public suspend fun ping (options : RequestOptions ? = null): EmptyResult = request(PingRequest (), options)
298295
299296 /* *
300297 * Sends a completion request to the server, typically to generate or complete some content.
@@ -314,8 +311,8 @@ public open class Client(private val clientInfo: Implementation, options: Client
314311 * @param options Optional request options.
315312 * @throws IllegalStateException If the server does not support logging.
316313 */
317- public suspend fun setLoggingLevel (level : LoggingLevel , options : RequestOptions ? = null): EmptyRequestResult =
318- request(SetLevelRequest (level), options)
314+ public suspend fun setLoggingLevel (level : LoggingLevel , options : RequestOptions ? = null): EmptyResult =
315+ request(SetLevelRequest (SetLevelRequestParams ( level) ), options)
319316
320317 /* *
321318 * Retrieves a prompt by name from the server.
@@ -387,10 +384,8 @@ public open class Client(private val clientInfo: Implementation, options: Client
387384 * @param options Optional request options.
388385 * @throws IllegalStateException If the server does not support resource subscriptions.
389386 */
390- public suspend fun subscribeResource (
391- request : SubscribeRequest ,
392- options : RequestOptions ? = null,
393- ): EmptyRequestResult = request(request, options)
387+ public suspend fun subscribeResource (request : SubscribeRequest , options : RequestOptions ? = null): EmptyResult =
388+ request(request, options)
394389
395390 /* *
396391 * Unsubscribes from resource changes on the server.
@@ -399,10 +394,8 @@ public open class Client(private val clientInfo: Implementation, options: Client
399394 * @param options Optional request options.
400395 * @throws IllegalStateException If the server does not support resource subscriptions.
401396 */
402- public suspend fun unsubscribeResource (
403- request : UnsubscribeRequest ,
404- options : RequestOptions ? = null,
405- ): EmptyRequestResult = request(request, options)
397+ public suspend fun unsubscribeResource (request : UnsubscribeRequest , options : RequestOptions ? = null): EmptyResult =
398+ request(request, options)
406399
407400 /* *
408401 * Calls a tool on the server by name, passing the specified arguments and metadata.
@@ -413,7 +406,6 @@ public open class Client(private val clientInfo: Implementation, options: Client
413406 * - Optional prefix: dot-separated labels followed by slash (e.g., "api.example.com/")
414407 * - Name: alphanumeric start/end, may contain hyphens, underscores, dots, alphanumerics
415408 * - Reserved prefixes starting with "mcp" or "modelcontextprotocol" are forbidden
416- * @param compatibility Whether to use compatibility mode for older protocol versions.
417409 * @param options Optional request options.
418410 * @return The result of the tool call, or `null` if none.
419411 * @throws IllegalStateException If the server does not support tools.
@@ -422,40 +414,33 @@ public open class Client(private val clientInfo: Implementation, options: Client
422414 name : String ,
423415 arguments : Map <String , Any ?>,
424416 meta : Map <String , Any ?> = emptyMap(),
425- compatibility : Boolean = false,
426417 options : RequestOptions ? = null,
427- ): CallToolResultBase ? {
418+ ): CallToolResult {
428419 validateMetaKeys(meta.keys)
429420
430- val jsonArguments = convertToJsonMap( arguments)
431- val jsonMeta = convertToJsonMap( meta)
421+ val jsonArguments = arguments.toJson( )
422+ val jsonMeta = meta.toJson( )
432423
433424 val request = CallToolRequest (
434- name = name,
435- arguments = JsonObject (jsonArguments),
436- _meta = JsonObject (jsonMeta),
425+ CallToolRequestParams (
426+ name = name,
427+ arguments = JsonObject (jsonArguments),
428+ meta = RequestMeta (JsonObject (jsonMeta)),
429+ ),
437430 )
438- return callTool(request, compatibility, options)
431+ return callTool(request, options)
439432 }
440433
441434 /* *
442435 * Calls a tool on the server using a [CallToolRequest] object.
443436 *
444437 * @param request The request object containing the tool name and arguments.
445- * @param compatibility Whether to use compatibility mode for older protocol versions.
446438 * @param options Optional request options.
447439 * @return The result of the tool call, or `null` if none.
448440 * @throws IllegalStateException If the server does not support tools.
449441 */
450- public suspend fun callTool (
451- request : CallToolRequest ,
452- compatibility : Boolean = false,
453- options : RequestOptions ? = null,
454- ): CallToolResultBase ? = if (compatibility) {
455- request<CompatibilityCallToolResult >(request, options)
456- } else {
457- request<CallToolResult >(request, options)
458- }
442+ public suspend fun callTool (request : CallToolRequest , options : RequestOptions ? = null): CallToolResult =
443+ request(request, options)
459444
460445 /* *
461446 * Lists all available tools on the server.
@@ -570,14 +555,14 @@ public open class Client(private val clientInfo: Implementation, options: Client
570555 * @param handler The elicitation handler.
571556 * @throws IllegalStateException if the client does not support elicitation.
572557 */
573- public fun setElicitationHandler (handler : (CreateElicitationRequest ) -> CreateElicitationResult ) {
558+ public fun setElicitationHandler (handler : (ElicitRequest ) -> ElicitResult ) {
574559 if (capabilities.elicitation == null ) {
575560 logger.error { " Failed to set elicitation handler: Client does not support elicitation" }
576561 throw IllegalStateException (" Client does not support elicitation." )
577562 }
578563 logger.info { " Setting the elicitation handler" }
579564
580- setRequestHandler<CreateElicitationRequest >(Method .Defined .ElicitationCreate ) { request, _ ->
565+ setRequestHandler<ElicitRequest >(Method .Defined .ElicitationCreate ) { request, _ ->
581566 handler(request)
582567 }
583568 }
@@ -637,67 +622,4 @@ public open class Client(private val clientInfo: Implementation, options: Client
637622 }
638623 }
639624 }
640-
641- private fun convertToJsonMap (map : Map <String , Any ?>): Map <String , JsonElement > = map.mapValues { (key, value) ->
642- try {
643- convertToJsonElement(value)
644- } catch (e: Exception ) {
645- logger.warn { " Failed to convert value for key '$key ': ${e.message} . Using string representation." }
646- JsonPrimitive (value.toString())
647- }
648- }
649-
650- @OptIn(ExperimentalUnsignedTypes ::class , ExperimentalSerializationApi ::class )
651- private fun convertToJsonElement (value : Any? ): JsonElement = when (value) {
652- null -> JsonNull
653-
654- is JsonElement -> value
655-
656- is String -> JsonPrimitive (value)
657-
658- is Number -> JsonPrimitive (value)
659-
660- is Boolean -> JsonPrimitive (value)
661-
662- is Char -> JsonPrimitive (value.toString())
663-
664- is Enum <* > -> JsonPrimitive (value.name)
665-
666- is Map <* , * > -> buildJsonObject { value.forEach { (k, v) -> put(k.toString(), convertToJsonElement(v)) } }
667-
668- is Collection <* > -> buildJsonArray { value.forEach { add(convertToJsonElement(it)) } }
669-
670- is Array <* > -> buildJsonArray { value.forEach { add(convertToJsonElement(it)) } }
671-
672- // Primitive arrays
673- is IntArray -> buildJsonArray { value.forEach { add(it) } }
674-
675- is LongArray -> buildJsonArray { value.forEach { add(it) } }
676-
677- is FloatArray -> buildJsonArray { value.forEach { add(it) } }
678-
679- is DoubleArray -> buildJsonArray { value.forEach { add(it) } }
680-
681- is BooleanArray -> buildJsonArray { value.forEach { add(it) } }
682-
683- is ShortArray -> buildJsonArray { value.forEach { add(it) } }
684-
685- is ByteArray -> buildJsonArray { value.forEach { add(it) } }
686-
687- is CharArray -> buildJsonArray { value.forEach { add(it.toString()) } }
688-
689- // Unsigned arrays
690- is UIntArray -> buildJsonArray { value.forEach { add(JsonPrimitive (it)) } }
691-
692- is ULongArray -> buildJsonArray { value.forEach { add(JsonPrimitive (it)) } }
693-
694- is UShortArray -> buildJsonArray { value.forEach { add(JsonPrimitive (it)) } }
695-
696- is UByteArray -> buildJsonArray { value.forEach { add(JsonPrimitive (it)) } }
697-
698- else -> {
699- logger.debug { " Converting unknown type ${value::class } to string: $value " }
700- JsonPrimitive (value.toString())
701- }
702- }
703625}
0 commit comments