diff --git a/kotlin-sdk-core/api/kotlin-sdk-core.api b/kotlin-sdk-core/api/kotlin-sdk-core.api index 3c1aec41..3e8851ad 100644 --- a/kotlin-sdk-core/api/kotlin-sdk-core.api +++ b/kotlin-sdk-core/api/kotlin-sdk-core.api @@ -938,6 +938,8 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/CommonKt { public final class io/modelcontextprotocol/kotlin/sdk/types/CompleteRequest : io/modelcontextprotocol/kotlin/sdk/types/ClientRequest { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/types/CompleteRequest$Companion; + public synthetic fun (Lio/modelcontextprotocol/kotlin/sdk/types/CompleteRequestParams$Argument;Lio/modelcontextprotocol/kotlin/sdk/types/Reference;Lio/modelcontextprotocol/kotlin/sdk/types/CompleteRequestParams$Context;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Lio/modelcontextprotocol/kotlin/sdk/types/CompleteRequestParams$Argument;Lio/modelcontextprotocol/kotlin/sdk/types/Reference;Lio/modelcontextprotocol/kotlin/sdk/types/CompleteRequestParams$Context;Lkotlinx/serialization/json/JsonObject;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public fun (Lio/modelcontextprotocol/kotlin/sdk/types/CompleteRequestParams;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/types/CompleteRequestParams; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/types/CompleteRequestParams;)Lio/modelcontextprotocol/kotlin/sdk/types/CompleteRequest; @@ -2057,12 +2059,14 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/ListPromptsRequest : public fun ()V public fun (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;)V public synthetic fun (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;)Lio/modelcontextprotocol/kotlin/sdk/types/ListPromptsRequest; public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/types/ListPromptsRequest;Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/types/ListPromptsRequest; public fun equals (Ljava/lang/Object;)Z - public final fun getCursor ()Ljava/lang/String; - public final fun getMeta-VI-3G7E ()Lkotlinx/serialization/json/JsonObject; + public fun getCursor ()Ljava/lang/String; + public fun getMeta-VI-3G7E ()Lkotlinx/serialization/json/JsonObject; public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/types/Method; public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams; public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/types/RequestParams; @@ -2123,12 +2127,14 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/ListResourceTemplate public fun ()V public fun (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;)V public synthetic fun (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;)Lio/modelcontextprotocol/kotlin/sdk/types/ListResourceTemplatesRequest; public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/types/ListResourceTemplatesRequest;Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/types/ListResourceTemplatesRequest; public fun equals (Ljava/lang/Object;)Z - public final fun getCursor ()Ljava/lang/String; - public final fun getMeta-VI-3G7E ()Lkotlinx/serialization/json/JsonObject; + public fun getCursor ()Ljava/lang/String; + public fun getMeta-VI-3G7E ()Lkotlinx/serialization/json/JsonObject; public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/types/Method; public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams; public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/types/RequestParams; @@ -2189,12 +2195,14 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/ListResourcesRequest public fun ()V public fun (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;)V public synthetic fun (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;)Lio/modelcontextprotocol/kotlin/sdk/types/ListResourcesRequest; public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/types/ListResourcesRequest;Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/types/ListResourcesRequest; public fun equals (Ljava/lang/Object;)Z - public final fun getCursor ()Ljava/lang/String; - public final fun getMeta-VI-3G7E ()Lkotlinx/serialization/json/JsonObject; + public fun getCursor ()Ljava/lang/String; + public fun getMeta-VI-3G7E ()Lkotlinx/serialization/json/JsonObject; public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/types/Method; public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams; public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/types/RequestParams; @@ -2255,6 +2263,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/ListRootsRequest : i public fun ()V public fun (Lio/modelcontextprotocol/kotlin/sdk/types/BaseRequestParams;)V public synthetic fun (Lio/modelcontextprotocol/kotlin/sdk/types/BaseRequestParams;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Lkotlinx/serialization/json/JsonObject;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/types/BaseRequestParams; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/types/BaseRequestParams;)Lio/modelcontextprotocol/kotlin/sdk/types/ListRootsRequest; public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/types/ListRootsRequest;Lio/modelcontextprotocol/kotlin/sdk/types/BaseRequestParams;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/types/ListRootsRequest; @@ -2318,12 +2327,14 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/ListToolsRequest : i public fun ()V public fun (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;)V public synthetic fun (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;)Lio/modelcontextprotocol/kotlin/sdk/types/ListToolsRequest; public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/types/ListToolsRequest;Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/types/ListToolsRequest; public fun equals (Ljava/lang/Object;)Z - public final fun getCursor ()Ljava/lang/String; - public final fun getMeta-VI-3G7E ()Lkotlinx/serialization/json/JsonObject; + public fun getCursor ()Ljava/lang/String; + public fun getMeta-VI-3G7E ()Lkotlinx/serialization/json/JsonObject; public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/types/Method; public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams; public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/types/RequestParams; @@ -2641,6 +2652,8 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/NotificationParams$D public abstract interface class io/modelcontextprotocol/kotlin/sdk/types/PaginatedRequest : io/modelcontextprotocol/kotlin/sdk/types/Request { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequest$Companion; + public fun getCursor ()Ljava/lang/String; + public fun getMeta-VI-3G7E ()Lkotlinx/serialization/json/JsonObject; public abstract fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams; } @@ -2648,6 +2661,11 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/PaginatedRequest$Com public final fun serializer ()Lkotlinx/serialization/KSerializer; } +public final class io/modelcontextprotocol/kotlin/sdk/types/PaginatedRequest$DefaultImpls { + public static fun getCursor (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequest;)Ljava/lang/String; + public static fun getMeta-VI-3G7E (Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequest;)Lkotlinx/serialization/json/JsonObject; +} + public final class io/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams : io/modelcontextprotocol/kotlin/sdk/types/RequestParams { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/types/PaginatedRequestParams$Companion; public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -3023,6 +3041,8 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/RPCError$ErrorCode { public final class io/modelcontextprotocol/kotlin/sdk/types/ReadResourceRequest : io/modelcontextprotocol/kotlin/sdk/types/ClientRequest { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/types/ReadResourceRequest$Companion; public fun (Lio/modelcontextprotocol/kotlin/sdk/types/ReadResourceRequestParams;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/types/ReadResourceRequestParams; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/types/ReadResourceRequestParams;)Lio/modelcontextprotocol/kotlin/sdk/types/ReadResourceRequest; public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/types/ReadResourceRequest;Lio/modelcontextprotocol/kotlin/sdk/types/ReadResourceRequestParams;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/types/ReadResourceRequest; @@ -3906,6 +3926,8 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/StopReason$Companion public final class io/modelcontextprotocol/kotlin/sdk/types/SubscribeRequest : io/modelcontextprotocol/kotlin/sdk/types/ClientRequest { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/types/SubscribeRequest$Companion; public fun (Lio/modelcontextprotocol/kotlin/sdk/types/SubscribeRequestParams;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/types/SubscribeRequestParams; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/types/SubscribeRequestParams;)Lio/modelcontextprotocol/kotlin/sdk/types/SubscribeRequest; public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/types/SubscribeRequest;Lio/modelcontextprotocol/kotlin/sdk/types/SubscribeRequestParams;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/types/SubscribeRequest; @@ -4219,6 +4241,8 @@ public final class io/modelcontextprotocol/kotlin/sdk/types/UnknownResourceConte public final class io/modelcontextprotocol/kotlin/sdk/types/UnsubscribeRequest : io/modelcontextprotocol/kotlin/sdk/types/ClientRequest { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/types/UnsubscribeRequest$Companion; public fun (Lio/modelcontextprotocol/kotlin/sdk/types/UnsubscribeRequestParams;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/types/UnsubscribeRequestParams; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/types/UnsubscribeRequestParams;)Lio/modelcontextprotocol/kotlin/sdk/types/UnsubscribeRequest; public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/types/UnsubscribeRequest;Lio/modelcontextprotocol/kotlin/sdk/types/UnsubscribeRequestParams;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/types/UnsubscribeRequest; diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt index 7d559246..64fe355c 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt @@ -397,7 +397,7 @@ public abstract class Protocol(@PublishedApi internal val options: ProtocolOptio public suspend fun request(request: Request, options: RequestOptions? = null): T { logger.trace { "Sending request: ${request.method}" } val result = CompletableDeferred() - val transport = transport ?: throw Error("Not connected") + val transport = transport ?: error("Not connected") if (this@Protocol.options?.enforceStrictCapabilities == true) { assertCapabilityForMethod(request.method) diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/completion.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/completion.kt index 89d853d6..59f558c8 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/completion.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/completion.kt @@ -1,5 +1,7 @@ package io.modelcontextprotocol.kotlin.sdk.types +import io.modelcontextprotocol.kotlin.sdk.types.CompleteRequestParams.Argument +import io.modelcontextprotocol.kotlin.sdk.types.CompleteRequestParams.Context import kotlinx.serialization.EncodeDefault import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.SerialName @@ -20,7 +22,7 @@ public data class CompleteRequest(override val params: CompleteRequestParams) : /** * The argument's information for which completion options are requested. */ - public val argument: CompleteRequestParams.Argument + public val argument: Argument get() = params.argument /** @@ -32,11 +34,23 @@ public data class CompleteRequest(override val params: CompleteRequestParams) : /** * Additional, context for generating completions. */ - public val context: CompleteRequestParams.Context? + public val context: Context? get() = params.context public val meta: RequestMeta? get() = params.meta + + @Deprecated( + message = "Will be removed in a future release.", + replaceWith = ReplaceWith(expression = "CompleteRequest(CompleteRequestParams(argument, ref, context, meta))"), + level = DeprecationLevel.WARNING, + ) + public constructor( + argument: Argument, + ref: Reference, + context: Context? = null, + meta: RequestMeta? = null, + ) : this(CompleteRequestParams(argument, ref, context, meta)) } /** @@ -67,7 +81,7 @@ public data class CompleteRequestParams( /** * Additional context to help generate more relevant completions. * - * @property arguments Previously-resolved variables in a URI template or prompt. + * @property arguments Previously resolved variables in a URI template or prompt. * These can be used to provide context-aware completions. * For example, if completing a file path, this might contain the repository or directory context. */ @@ -100,8 +114,8 @@ public data class CompleteResult( * This can exceed the number of values actually sent in the response, * indicating that pagination or filtering may be needed. * @property hasMore Indicates whether there are additional completion options beyond - * those provided in the current response, even if the exact total is unknown. - * Use this when the complete set of completions is too large to calculate upfront. + * those provided in the current response, even if the exact total is unknown. + * Use this when the complete set of completions is too large to calculate upfront. */ @Serializable public data class Completion(val values: List, val total: Int? = null, val hasMore: Boolean? = null) { diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/prompts.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/prompts.kt index fcaa22a5..68a892fb 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/prompts.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/prompts.kt @@ -205,16 +205,24 @@ public data class ListPromptsRequest(override val params: PaginatedRequestParams override val method: Method = Method.Defined.PromptsList /** - * An opaque token representing the current pagination position. + * Secondary constructor for creating a [ListPromptsRequest] instance + * using optional cursor and metadata parameters. + * + * This constructor simplifies the creation of the [ListPromptsRequest] by allowing a cursor + * and metadata to be provided. + * + * @param cursor Optional cursor string to specify the starting point of the paginated request. + * @param meta Optional metadata associated with the request. */ - public val cursor: String? - get() = params?.cursor - - /** - * Metadata for this request. May include a progressToken for out-of-band progress notifications. - */ - public val meta: RequestMeta? - get() = params?.meta + @Deprecated( + message = "Use constructor with ListPromptsParams instead", + replaceWith = ReplaceWith("ListPromptsRequest(ListPromptsParams(name, arguments, meta))"), + level = DeprecationLevel.WARNING, + ) + public constructor( + cursor: String?, + meta: RequestMeta? = null, + ) : this(paginatedRequestParams(cursor, meta)) } /** diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/request.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/request.kt index 855e2f27..7e102041 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/request.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/request.kt @@ -27,6 +27,12 @@ public value class RequestMeta(public val json: JsonObject) { @Serializable public sealed interface RequestParams { + /** + * The `_meta` property/parameter is reserved by MCP + * to allow clients and servers to attach additional metadata to their interactions. + * + * @see MCP specification + */ @SerialName("_meta") public val meta: RequestMeta? } @@ -68,6 +74,18 @@ public sealed interface ServerRequest : Request @Serializable public sealed interface PaginatedRequest : Request { public override val params: PaginatedRequestParams? + + /** + * An opaque token representing the current pagination position. + */ + public val cursor: String? + get() = params?.cursor + + /** + * Metadata for this request. May include a progressToken for out-of-band progress notifications. + */ + public val meta: RequestMeta? + get() = params?.meta } /** @@ -114,3 +132,10 @@ public data class PaginatedRequestParams( @SerialName("_meta") override val meta: RequestMeta? = null, ) : RequestParams + +internal fun paginatedRequestParams(cursor: String?, meta: RequestMeta?): PaginatedRequestParams? = + if (cursor == null && meta == null) { + null + } else { + PaginatedRequestParams(cursor = cursor, meta = meta) + } diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/resources.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/resources.kt index 121864f3..ba9533e2 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/resources.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/resources.kt @@ -17,7 +17,7 @@ public sealed interface ResourceLike : WithMeta * Resources represent data sources such as files, database entries, API responses, * or other structured data that can be read by clients. * - * @property uri The URI of this resource. Can use any protocol scheme (file://, http://, etc.). + * @property uri The URI of this resource. Can use any protocol scheme (`file://`, `http://`, etc.). * @property name The programmatic identifier for this resource. * Intended for logical use and API identification. If [title] is not provided, * this should be used as a fallback display name. @@ -25,7 +25,8 @@ public sealed interface ResourceLike : WithMeta * Clients can use this to improve the LLM's understanding of available resources. * It can be thought of like a "hint" to the model. * @property mimeType The MIME type of this resource, if known (e.g., "text/plain", "application/json", "image/png"). - * @property size The size of the raw resource content in bytes (i.e., before base64 encoding or any tokenization), if known. + * @property size The size of the raw resource content in bytes + * (i.e., before base64 encoding or any tokenization), if known. * Hosts can use this to display file sizes and estimate context window usage. * @property title Optional human-readable display name for this resource. * Intended for UI and end-user contexts, optimized to be easily understood @@ -192,16 +193,24 @@ public data class ListResourcesRequest(override val params: PaginatedRequestPara override val method: Method = Method.Defined.ResourcesList /** - * An opaque token representing the current pagination position. + * Secondary constructor for creating a [ListResourcesRequest] instance + * using optional cursor and metadata parameters. + * + * This constructor simplifies the creation of the [ListResourcesRequest] by allowing a cursor + * and metadata to be provided. + * + * @param cursor Optional cursor string to specify the starting point of the paginated request. + * @param meta Optional metadata associated with the request. */ - public val cursor: String? - get() = params?.cursor - - /** - * Metadata for this request. May include a progressToken for out-of-band progress notifications. - */ - public val meta: RequestMeta? - get() = params?.meta + @Deprecated( + message = "Use the constructor with PaginatedRequestParams property instead", + replaceWith = ReplaceWith("ReadResourceRequest(PaginatedRequestParams(cursor, meta))"), + level = DeprecationLevel.WARNING, + ) + public constructor( + cursor: String?, + meta: RequestMeta? = null, + ) : this(paginatedRequestParams(cursor, meta)) } /** @@ -252,6 +261,16 @@ public data class ReadResourceRequest(override val params: ReadResourceRequestPa */ public val meta: RequestMeta? get() = params.meta + + @Deprecated( + message = "Use the constructor with ReadResourceRequestParams property instead", + replaceWith = ReplaceWith("ReadResourceRequest(ReadResourceRequestParams(uri, meta))"), + level = DeprecationLevel.WARNING, + ) + public constructor( + uri: String, + meta: RequestMeta? = null, + ) : this(ReadResourceRequestParams(uri, meta)) } /** @@ -318,6 +337,16 @@ public data class SubscribeRequest(override val params: SubscribeRequestParams) */ public val meta: RequestMeta? get() = params.meta + + @Deprecated( + message = "Use the constructor with SubscribeRequestParams property instead", + replaceWith = ReplaceWith("ReadResourceRequest(SubscribeRequestParams(uri, meta))"), + level = DeprecationLevel.WARNING, + ) + public constructor( + uri: String, + meta: RequestMeta? = null, + ) : this(SubscribeRequestParams(uri, meta)) } /** @@ -363,6 +392,11 @@ public data class UnsubscribeRequest(override val params: UnsubscribeRequestPara */ public val meta: RequestMeta? get() = params.meta + + public constructor( + uri: String, + meta: RequestMeta? = null, + ) : this(UnsubscribeRequestParams(uri, meta)) } /** @@ -401,16 +435,24 @@ public data class ListResourceTemplatesRequest(override val params: PaginatedReq override val method: Method = Method.Defined.ResourcesTemplatesList /** - * An opaque token representing the current pagination position. - */ - public val cursor: String? - get() = params?.cursor - - /** - * Metadata for this request. May include a progressToken for out-of-band progress notifications. + * Secondary constructor for creating a [ListResourceTemplatesRequest] instance + * using optional cursor and metadata parameters. + * + * This constructor simplifies the creation of the [ListResourceTemplatesRequest] by allowing a cursor + * and metadata to be provided. + * + * @param cursor Optional cursor string to specify the starting point of the paginated request. + * @param meta Optional metadata associated with the request. */ - public val meta: RequestMeta? - get() = params?.meta + @Deprecated( + message = "Use the constructor with PaginatedRequestParams property instead", + replaceWith = ReplaceWith("ListResourceTemplatesRequest(PaginatedRequestParams(cursor, meta))"), + level = DeprecationLevel.WARNING, + ) + public constructor( + cursor: String?, + meta: RequestMeta? = null, + ) : this(paginatedRequestParams(cursor, meta)) } /** diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/roots.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/roots.kt index af7b1e7a..cc08739b 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/roots.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/roots.kt @@ -62,6 +62,15 @@ public data class ListRootsRequest(override val params: BaseRequestParams? = nul public val meta: RequestMeta? get() = params?.meta + + @Deprecated( + message = "Use the constructor with BaseRequestParams property instead", + replaceWith = ReplaceWith("ListRootsRequest(BaseRequestParams(meta))"), + level = DeprecationLevel.WARNING, + ) + public constructor( + meta: RequestMeta?, + ) : this(BaseRequestParams(meta)) } /** diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/tools.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/tools.kt index 15f04803..6cba2086 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/tools.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/tools.kt @@ -228,16 +228,24 @@ public data class ListToolsRequest(override val params: PaginatedRequestParams? override val method: Method = Method.Defined.ToolsList /** - * An opaque token representing the current pagination position. + * Secondary constructor for creating a [ListToolsRequest] instance + * using optional cursor and metadata parameters. + * + * This constructor simplifies the creation of the [ListToolsRequest] by allowing a cursor + * and metadata to be provided. + * + * @param cursor Optional cursor string to specify the starting point of the paginated request. + * @param meta Optional metadata associated with the request. */ - public val cursor: String? - get() = params?.cursor - - /** - * Metadata for this request. May include a progressToken for out-of-band progress notifications. - */ - public val meta: RequestMeta? - get() = params?.meta + @Deprecated( + message = "Use the constructor with BaseRequestParams property instead", + replaceWith = ReplaceWith("ListToolsRequest(BaseRequestParams(meta))"), + level = DeprecationLevel.WARNING, + ) + public constructor( + cursor: String?, + meta: RequestMeta? = null, + ) : this(paginatedRequestParams(cursor, meta)) } /** diff --git a/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/OldSchemaAbstractResourceIntegrationTest.kt b/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/OldSchemaAbstractResourceIntegrationTest.kt index a7a4202a..7cc5f10b 100644 --- a/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/OldSchemaAbstractResourceIntegrationTest.kt +++ b/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/OldSchemaAbstractResourceIntegrationTest.kt @@ -16,6 +16,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertNull import org.junit.jupiter.api.assertThrows import java.util.concurrent.atomic.AtomicBoolean import kotlin.test.Ignore @@ -145,6 +146,7 @@ abstract class OldSchemaAbstractResourceIntegrationTest : OldSchemaKotlinTestBas val result = client.listResources() assertNotNull(result, "List resources result should not be null") + assertNull(actual = result.meta, "List resources meta should be null") assertTrue(result.resources.isNotEmpty(), "Resources list should not be empty") val testResource = result.resources.find { it.uri == testResourceUri } @@ -158,6 +160,7 @@ abstract class OldSchemaAbstractResourceIntegrationTest : OldSchemaKotlinTestBas val result = client.readResource(ReadResourceRequest(ReadResourceRequestParams(uri = testResourceUri))) assertNotNull(result, "Read resource result should not be null") + assertNull(actual = result.meta, "Read resource result meta should be null") assertTrue(result.contents.isNotEmpty(), "Resource contents should not be empty") val content = result.contents.firstOrNull() as? TextResourceContents diff --git a/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/OldSchemaAbstractToolIntegrationTest.kt b/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/OldSchemaAbstractToolIntegrationTest.kt index 6086b47b..cd12d793 100644 --- a/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/OldSchemaAbstractToolIntegrationTest.kt +++ b/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/OldSchemaAbstractToolIntegrationTest.kt @@ -21,6 +21,7 @@ import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.put import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertNull import java.text.DecimalFormat import java.text.DecimalFormatSymbols import java.util.Locale @@ -431,7 +432,8 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() fun testListTools(): Unit = runBlocking(Dispatchers.IO) { val result = client.listTools() - assertNotNull(result, "List utils result should not be null") + assertNotNull(result, "List tools result should not be null") + assertNull(actual = result.meta, "List tools result meta should be null") assertTrue(result.tools.isNotEmpty(), "Tools list should not be empty") val testTool = result.tools.find { it.name == testToolName } @@ -449,7 +451,8 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() val testText = "Hello, world!" val arguments = mapOf("text" to testText) - val result = client.callTool(testToolName, arguments) as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + val result = client.callTool(testToolName, arguments) + assertNull(actual = result.meta, "CallTool result meta should be null") val actualContent = result.structuredContent.toString() val expectedContent = """ @@ -478,7 +481,7 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() val result = client.callTool( complexToolName, arguments, - ) as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + ) val actualContent = result.structuredContent.toString() val expectedContent = """ @@ -518,7 +521,7 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() val errorResult = client.callTool( errorToolName, errorArgs, - ) as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + ) val actualError = errorResult.structuredContent.toString() val expectedError = """ @@ -538,7 +541,7 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() val exceptionResult = client.callTool( errorToolName, exceptionArgs, - ) as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + ) assertTrue(exceptionResult.isError ?: false, "isError should be true for exception") @@ -563,7 +566,7 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() val result = client.callTool( multiContentToolName, arguments, - ) as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + ) assertEquals( 2, @@ -603,7 +606,7 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() val textOnlyResult = client.callTool( multiContentToolName, textOnlyArgs, - ) as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + ) assertEquals( 1, @@ -645,7 +648,7 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() arguments = arguments, ), ), - ) as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + ) val actualContent = result.structuredContent.toString() val expectedContent = """ @@ -671,7 +674,7 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() val result = client.callTool( largeToolName, arguments, - ) as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + ) val content = result.content.firstOrNull() as TextContent assertNotNull(content, "Tool result content should be TextContent") @@ -692,7 +695,7 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() val arguments = mapOf("delay" to delay) val startTime = System.currentTimeMillis() - val result = client.callTool(slowToolName, arguments) as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + val result = client.callTool(slowToolName, arguments) val endTime = System.currentTimeMillis() val content = result.content.firstOrNull() as? TextContent @@ -718,7 +721,7 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() val result = client.callTool( specialCharsToolName, arguments, - ) as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + ) val content = result.content.firstOrNull() as? TextContent assertNotNull(content, "Tool result content should be TextContent") @@ -802,7 +805,7 @@ abstract class OldSchemaAbstractToolIntegrationTest : OldSchemaKotlinTestBase() } assertNotNull(result, "Tool call result should not be null") - val callResult = result as io.modelcontextprotocol.kotlin.sdk.types.CallToolResult + val callResult = result assertTrue(callResult.isError ?: false, "isError should be true for non-existent tool") val textContent = callResult.content.firstOrNull { it is TextContent } as? TextContent diff --git a/samples/kotlin-mcp-server/src/test/kotlin/SseServerIntegrationTest.kt b/samples/kotlin-mcp-server/src/test/kotlin/SseServerIntegrationTest.kt index 09780ab0..7f8b6a9a 100644 --- a/samples/kotlin-mcp-server/src/test/kotlin/SseServerIntegrationTest.kt +++ b/samples/kotlin-mcp-server/src/test/kotlin/SseServerIntegrationTest.kt @@ -1,40 +1,83 @@ import io.modelcontextprotocol.kotlin.sdk.EmptyJsonObject +import io.modelcontextprotocol.kotlin.sdk.ReadResourceRequest import io.modelcontextprotocol.kotlin.sdk.TextContent +import io.modelcontextprotocol.kotlin.sdk.TextResourceContents import io.modelcontextprotocol.kotlin.sdk.client.Client import kotlinx.coroutines.runBlocking import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertIs +import kotlin.test.assertNotNull +import kotlin.test.assertTrue class SseServerIntegrationTest { private val client: Client = TestEnvironment.client @Test - fun `should get tools`(): Unit = runBlocking { - val tools = client.listTools().tools + fun `should list tools`(): Unit = runBlocking { + // when + val listToolsResult = client.listTools() + // then + assertEquals(expected = EmptyJsonObject, actual = listToolsResult._meta) + + val tools = listToolsResult.tools + assertEquals(actual = tools.size, expected = 1) assertEquals(expected = listOf("kotlin-sdk-tool"), actual = tools.map { it.name }) } @Test - fun `should get prompts`(): Unit = runBlocking { - val prompts = client.listPrompts().prompts + fun `should list prompts`(): Unit = runBlocking { + // when + val listPromptsResult = client.listPrompts() + + // then + assertEquals(expected = EmptyJsonObject, actual = listPromptsResult._meta) + + val prompts = listPromptsResult.prompts assertEquals(expected = listOf("Kotlin Developer"), actual = prompts.map { it.name }) } @Test - fun `should get resources`(): Unit = runBlocking { - val resources = client.listResources().resources + fun `should list resources`(): Unit = runBlocking { + val listResourcesResult = client.listResources() + + // then + assertEquals(expected = EmptyJsonObject, actual = listResourcesResult._meta) + val resources = listResourcesResult.resources assertEquals(expected = listOf("Web Search"), actual = resources.map { it.name }) } + @Test + fun `should get resource`(): Unit = runBlocking { + val testResourceUri = "https://search.com/" + val getResourcesResult = client.readResource( + ReadResourceRequest(uri = testResourceUri), + ) + + // then + assertEquals(expected = EmptyJsonObject, actual = getResourcesResult._meta) + val contents = getResourcesResult.contents + assertEquals(expected = 1, actual = contents.size) + assertTrue { + contents.contains( + TextResourceContents("Placeholder content for $testResourceUri", testResourceUri, "text/html"), + ) + } + } + @Test fun `should call tool`(): Unit = runBlocking { + // when val toolResult = client.callTool("kotlin-sdk-tool", EmptyJsonObject) - val content = toolResult?.content?.single() + + // then + assertNotNull(toolResult) + assertEquals(expected = EmptyJsonObject, actual = toolResult._meta) + val content = toolResult.content.single() assertIs(content, "Tool result should be a text content") assertEquals(expected = "Hello, world!", actual = content.text)