Update notification schema and refactor tests package structure (#199)
This commit is contained in:
parent
e5214fe30f
commit
cb79ea7a13
14 changed files with 1174 additions and 151 deletions
|
|
@ -133,20 +133,16 @@ public final class io/modelcontextprotocol/kotlin/sdk/CallToolResultBase$Default
|
|||
public static fun isError (Lio/modelcontextprotocol/kotlin/sdk/CallToolResultBase;)Ljava/lang/Boolean;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/CancelledNotification : io/modelcontextprotocol/kotlin/sdk/ClientNotification, io/modelcontextprotocol/kotlin/sdk/ServerNotification, io/modelcontextprotocol/kotlin/sdk/WithMeta {
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/CancelledNotification : io/modelcontextprotocol/kotlin/sdk/ClientNotification, io/modelcontextprotocol/kotlin/sdk/ServerNotification {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Companion;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/RequestId;
|
||||
public final fun component2 ()Ljava/lang/String;
|
||||
public final fun component3 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification;Lio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params;)Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification;Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public final fun getReason ()Ljava/lang/String;
|
||||
public final fun getRequestId ()Lio/modelcontextprotocol/kotlin/sdk/RequestId;
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params;
|
||||
public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
|
@ -166,6 +162,38 @@ public final class io/modelcontextprotocol/kotlin/sdk/CancelledNotification$Comp
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params : io/modelcontextprotocol/kotlin/sdk/NotificationParams {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params$Companion;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/RequestId;
|
||||
public final fun component2 ()Ljava/lang/String;
|
||||
public final fun component3 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params;Lio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public final fun getReason ()Ljava/lang/String;
|
||||
public final fun getRequestId ()Lio/modelcontextprotocol/kotlin/sdk/RequestId;
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params$$serializer;
|
||||
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/CancelledNotification$Params$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ClientCapabilities {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ClientCapabilities$Companion;
|
||||
public fun <init> ()V
|
||||
|
|
@ -942,7 +970,17 @@ public final class io/modelcontextprotocol/kotlin/sdk/InitializeResult$Companion
|
|||
public final class io/modelcontextprotocol/kotlin/sdk/InitializedNotification : io/modelcontextprotocol/kotlin/sdk/ClientNotification {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;)V
|
||||
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;)Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification;Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;
|
||||
public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/InitializedNotification$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
|
|
@ -960,6 +998,35 @@ public final class io/modelcontextprotocol/kotlin/sdk/InitializedNotification$Co
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params : io/modelcontextprotocol/kotlin/sdk/NotificationParams {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params$$serializer;
|
||||
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/InitializedNotification$Params$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/JSONRPCError : io/modelcontextprotocol/kotlin/sdk/JSONRPCMessage {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/JSONRPCError$Companion;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/ErrorCode;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)V
|
||||
|
|
@ -1386,22 +1453,16 @@ public final class io/modelcontextprotocol/kotlin/sdk/LoggingLevel$Companion {
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification : io/modelcontextprotocol/kotlin/sdk/ServerNotification, io/modelcontextprotocol/kotlin/sdk/WithMeta {
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification : io/modelcontextprotocol/kotlin/sdk/ServerNotification {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Companion;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;
|
||||
public final fun component2 ()Ljava/lang/String;
|
||||
public final fun component3 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun component4 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification;Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params;)Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification;Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public final fun getData ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun getLevel ()Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;
|
||||
public final fun getLogger ()Ljava/lang/String;
|
||||
public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params;
|
||||
public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
|
@ -1421,6 +1482,40 @@ public final class io/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params : io/modelcontextprotocol/kotlin/sdk/NotificationParams {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params$Companion;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;
|
||||
public final fun component2 ()Ljava/lang/String;
|
||||
public final fun component3 ()Lkotlinx/serialization/json/JsonElement;
|
||||
public final fun component4 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params;Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;Ljava/lang/String;Lkotlinx/serialization/json/JsonElement;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public final fun getData ()Lkotlinx/serialization/json/JsonElement;
|
||||
public final fun getLevel ()Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;
|
||||
public final fun getLogger ()Ljava/lang/String;
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params$$serializer;
|
||||
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$Params$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$SetLevelRequest : io/modelcontextprotocol/kotlin/sdk/ClientRequest, io/modelcontextprotocol/kotlin/sdk/WithMeta {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification$SetLevelRequest$Companion;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/LoggingLevel;Lkotlinx/serialization/json/JsonObject;)V
|
||||
|
|
@ -1587,12 +1682,21 @@ public final class io/modelcontextprotocol/kotlin/sdk/ModelPreferences$Companion
|
|||
public abstract interface class io/modelcontextprotocol/kotlin/sdk/Notification {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/Notification$Companion;
|
||||
public abstract fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public abstract fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/Notification$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public abstract interface class io/modelcontextprotocol/kotlin/sdk/NotificationParams : io/modelcontextprotocol/kotlin/sdk/WithMeta {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/NotificationParams$Companion;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/NotificationParams$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public abstract interface class io/modelcontextprotocol/kotlin/sdk/PaginatedRequest : io/modelcontextprotocol/kotlin/sdk/Request, io/modelcontextprotocol/kotlin/sdk/WithMeta {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PaginatedRequest$Companion;
|
||||
public abstract fun getCursor ()Ljava/lang/String;
|
||||
|
|
@ -1635,10 +1739,10 @@ public final class io/modelcontextprotocol/kotlin/sdk/PingRequest$Companion {
|
|||
|
||||
public class io/modelcontextprotocol/kotlin/sdk/Progress : io/modelcontextprotocol/kotlin/sdk/ProgressBase {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/Progress$Companion;
|
||||
public synthetic fun <init> (IILjava/lang/Double;Ljava/lang/String;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
|
||||
public fun <init> (ILjava/lang/Double;Ljava/lang/String;)V
|
||||
public fun <init> (DLjava/lang/Double;Ljava/lang/String;)V
|
||||
public synthetic fun <init> (IDLjava/lang/Double;Ljava/lang/String;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V
|
||||
public fun getMessage ()Ljava/lang/String;
|
||||
public fun getProgress ()I
|
||||
public fun getProgress ()D
|
||||
public fun getTotal ()Ljava/lang/Double;
|
||||
public static final synthetic fun write$Self (Lio/modelcontextprotocol/kotlin/sdk/Progress;Lkotlinx/serialization/encoding/CompositeEncoder;Lkotlinx/serialization/descriptors/SerialDescriptor;)V
|
||||
}
|
||||
|
|
@ -1661,7 +1765,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/Progress$Companion {
|
|||
public abstract interface class io/modelcontextprotocol/kotlin/sdk/ProgressBase {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ProgressBase$Companion;
|
||||
public abstract fun getMessage ()Ljava/lang/String;
|
||||
public abstract fun getProgress ()I
|
||||
public abstract fun getProgress ()D
|
||||
public abstract fun getTotal ()Ljava/lang/Double;
|
||||
}
|
||||
|
||||
|
|
@ -1669,24 +1773,16 @@ public final class io/modelcontextprotocol/kotlin/sdk/ProgressBase$Companion {
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ProgressNotification : io/modelcontextprotocol/kotlin/sdk/ClientNotification, io/modelcontextprotocol/kotlin/sdk/ProgressBase, io/modelcontextprotocol/kotlin/sdk/ServerNotification {
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ProgressNotification : io/modelcontextprotocol/kotlin/sdk/ClientNotification, io/modelcontextprotocol/kotlin/sdk/ServerNotification {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Companion;
|
||||
public fun <init> (ILio/modelcontextprotocol/kotlin/sdk/RequestId;Lkotlinx/serialization/json/JsonObject;Ljava/lang/Double;Ljava/lang/String;)V
|
||||
public synthetic fun <init> (ILio/modelcontextprotocol/kotlin/sdk/RequestId;Lkotlinx/serialization/json/JsonObject;Ljava/lang/Double;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()I
|
||||
public final fun component2 ()Lio/modelcontextprotocol/kotlin/sdk/RequestId;
|
||||
public final fun component3 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun component4 ()Ljava/lang/Double;
|
||||
public final fun component5 ()Ljava/lang/String;
|
||||
public final fun copy (ILio/modelcontextprotocol/kotlin/sdk/RequestId;Lkotlinx/serialization/json/JsonObject;Ljava/lang/Double;Ljava/lang/String;)Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification;ILio/modelcontextprotocol/kotlin/sdk/RequestId;Lkotlinx/serialization/json/JsonObject;Ljava/lang/Double;Ljava/lang/String;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params;)Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification;Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getMessage ()Ljava/lang/String;
|
||||
public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public fun getProgress ()I
|
||||
public final fun getProgressToken ()Lio/modelcontextprotocol/kotlin/sdk/RequestId;
|
||||
public fun getTotal ()Ljava/lang/Double;
|
||||
public final fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
|
@ -1706,6 +1802,42 @@ public final class io/modelcontextprotocol/kotlin/sdk/ProgressNotification$Compa
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params : io/modelcontextprotocol/kotlin/sdk/NotificationParams, io/modelcontextprotocol/kotlin/sdk/ProgressBase {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params$Companion;
|
||||
public fun <init> (DLio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/Double;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (DLio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/Double;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()D
|
||||
public final fun component2 ()Lio/modelcontextprotocol/kotlin/sdk/RequestId;
|
||||
public final fun component3 ()Ljava/lang/Double;
|
||||
public final fun component4 ()Ljava/lang/String;
|
||||
public final fun component5 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (DLio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/Double;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params;DLio/modelcontextprotocol/kotlin/sdk/RequestId;Ljava/lang/Double;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getMessage ()Ljava/lang/String;
|
||||
public fun getProgress ()D
|
||||
public final fun getProgressToken ()Lio/modelcontextprotocol/kotlin/sdk/RequestId;
|
||||
public fun getTotal ()Ljava/lang/Double;
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params$$serializer;
|
||||
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ProgressNotification$Params$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/Prompt {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/Prompt$Companion;
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V
|
||||
|
|
@ -1763,7 +1895,17 @@ public final class io/modelcontextprotocol/kotlin/sdk/PromptArgument$Companion {
|
|||
public final class io/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification : io/modelcontextprotocol/kotlin/sdk/ServerNotification {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;)V
|
||||
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;)Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification;Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
|
|
@ -1781,6 +1923,35 @@ public final class io/modelcontextprotocol/kotlin/sdk/PromptListChangedNotificat
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params : io/modelcontextprotocol/kotlin/sdk/NotificationParams {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params$$serializer;
|
||||
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/PromptListChangedNotification$Params$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/PromptMessage {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptMessage$Companion;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContent;)V
|
||||
|
|
@ -2053,7 +2224,17 @@ public final class io/modelcontextprotocol/kotlin/sdk/ResourceContents$Companion
|
|||
public final class io/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification : io/modelcontextprotocol/kotlin/sdk/ServerNotification {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;)V
|
||||
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;)Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification;Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
|
|
@ -2071,6 +2252,35 @@ public final class io/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotific
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params : io/modelcontextprotocol/kotlin/sdk/NotificationParams {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params$$serializer;
|
||||
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ResourceListChangedNotification$Params$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ResourceReference : io/modelcontextprotocol/kotlin/sdk/Reference {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ResourceReference$Companion;
|
||||
public static final field TYPE Ljava/lang/String;
|
||||
|
|
@ -2133,18 +2343,16 @@ public final class io/modelcontextprotocol/kotlin/sdk/ResourceTemplate$Companion
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification : io/modelcontextprotocol/kotlin/sdk/ServerNotification, io/modelcontextprotocol/kotlin/sdk/WithMeta {
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification : io/modelcontextprotocol/kotlin/sdk/ServerNotification {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Companion;
|
||||
public fun <init> (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Ljava/lang/String;
|
||||
public final fun component2 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params;)Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification;Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public final fun getUri ()Ljava/lang/String;
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
|
@ -2164,6 +2372,36 @@ public final class io/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotificatio
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params : io/modelcontextprotocol/kotlin/sdk/NotificationParams {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params$Companion;
|
||||
public fun <init> (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Ljava/lang/String;
|
||||
public final fun component2 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public final fun getUri ()Ljava/lang/String;
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params$$serializer;
|
||||
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ResourceUpdatedNotification$Params$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/Role : java/lang/Enum {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/Role$Companion;
|
||||
public static final field assistant Lio/modelcontextprotocol/kotlin/sdk/Role;
|
||||
|
|
@ -2209,7 +2447,17 @@ public final class io/modelcontextprotocol/kotlin/sdk/Root$Companion {
|
|||
public final class io/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification : io/modelcontextprotocol/kotlin/sdk/ClientNotification {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;)V
|
||||
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;)Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification;Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
|
|
@ -2227,6 +2475,35 @@ public final class io/modelcontextprotocol/kotlin/sdk/RootsListChangedNotificati
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params : io/modelcontextprotocol/kotlin/sdk/NotificationParams {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params$$serializer;
|
||||
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/RootsListChangedNotification$Params$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/SamplingMessage {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage$Companion;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;)V
|
||||
|
|
@ -2696,7 +2973,17 @@ public final class io/modelcontextprotocol/kotlin/sdk/ToolAnnotations$Companion
|
|||
public final class io/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification : io/modelcontextprotocol/kotlin/sdk/ServerNotification {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;)V
|
||||
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;)Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification;Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public synthetic fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
|
|
@ -2714,6 +3001,35 @@ public final class io/modelcontextprotocol/kotlin/sdk/ToolListChangedNotificatio
|
|||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params : io/modelcontextprotocol/kotlin/sdk/NotificationParams {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params$Companion;
|
||||
public fun <init> ()V
|
||||
public fun <init> (Lkotlinx/serialization/json/JsonObject;)V
|
||||
public synthetic fun <init> (Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lkotlinx/serialization/json/JsonObject;
|
||||
public final fun copy (Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final synthetic class io/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
|
||||
public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params$$serializer;
|
||||
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;
|
||||
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
|
||||
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
|
||||
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params;)V
|
||||
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
|
||||
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/ToolListChangedNotification$Params$Companion {
|
||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||
}
|
||||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/TypesKt {
|
||||
public static final field JSONRPC_VERSION Ljava/lang/String;
|
||||
public static final field LATEST_PROTOCOL_VERSION Ljava/lang/String;
|
||||
|
|
@ -2756,12 +3072,15 @@ public final class io/modelcontextprotocol/kotlin/sdk/UnknownContent$Companion {
|
|||
|
||||
public final class io/modelcontextprotocol/kotlin/sdk/UnknownMethodRequestOrNotification : io/modelcontextprotocol/kotlin/sdk/ClientNotification, io/modelcontextprotocol/kotlin/sdk/ClientRequest, io/modelcontextprotocol/kotlin/sdk/ServerNotification, io/modelcontextprotocol/kotlin/sdk/ServerRequest {
|
||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/UnknownMethodRequestOrNotification$Companion;
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/Method;)V
|
||||
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/Method;Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;)V
|
||||
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/Method;Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/Method;)Lio/modelcontextprotocol/kotlin/sdk/UnknownMethodRequestOrNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/UnknownMethodRequestOrNotification;Lio/modelcontextprotocol/kotlin/sdk/Method;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/UnknownMethodRequestOrNotification;
|
||||
public final fun component2 ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/Method;Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;)Lio/modelcontextprotocol/kotlin/sdk/UnknownMethodRequestOrNotification;
|
||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/UnknownMethodRequestOrNotification;Lio/modelcontextprotocol/kotlin/sdk/Method;Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/UnknownMethodRequestOrNotification;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getMethod ()Lio/modelcontextprotocol/kotlin/sdk/Method;
|
||||
public fun getParams ()Lio/modelcontextprotocol/kotlin/sdk/NotificationParams;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ public open class Server(
|
|||
* @param params The logging message notification parameters.
|
||||
*/
|
||||
public suspend fun sendLoggingMessage(params: LoggingMessageNotification) {
|
||||
logger.trace { "Sending logging message: ${params.data}" }
|
||||
logger.trace { "Sending logging message: ${params.params.data}" }
|
||||
notification(params)
|
||||
}
|
||||
|
||||
|
|
@ -568,7 +568,7 @@ public open class Server(
|
|||
* @param params Details of the updated resource.
|
||||
*/
|
||||
public suspend fun sendResourceUpdated(params: ResourceUpdatedNotification) {
|
||||
logger.debug { "Sending resource updated notification for: ${params.uri}" }
|
||||
logger.debug { "Sending resource updated notification for: ${params.params.uri}" }
|
||||
notification(params)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -292,11 +292,11 @@ public abstract class Protocol(
|
|||
}
|
||||
|
||||
private fun onProgress(notification: ProgressNotification) {
|
||||
LOGGER.trace { "Received progress notification: token=${notification.progressToken}, progress=${notification.progress}/${notification.total}" }
|
||||
val progress = notification.progress
|
||||
val total = notification.total
|
||||
val message = notification.message
|
||||
val progressToken = notification.progressToken
|
||||
LOGGER.trace { "Received progress notification: token=${notification.params.progressToken}, progress=${notification.params.progress}/${notification.params.total}" }
|
||||
val progress = notification.params.progress
|
||||
val total = notification.params.total
|
||||
val message = notification.params.message
|
||||
val progressToken = notification.params.progressToken
|
||||
|
||||
val handler = _progressHandlers.value[progressToken]
|
||||
if (handler == null) {
|
||||
|
|
@ -424,7 +424,12 @@ public abstract class Protocol(
|
|||
_responseHandlers.update { current -> current.remove(messageId) }
|
||||
_progressHandlers.update { current -> current.remove(messageId) }
|
||||
|
||||
val notification = CancelledNotification(requestId = messageId, reason = reason.message ?: "Unknown")
|
||||
val notification = CancelledNotification(
|
||||
params = CancelledNotification.Params(
|
||||
requestId = messageId,
|
||||
reason = reason.message ?: "Unknown"
|
||||
)
|
||||
)
|
||||
|
||||
val serialized = JSONRPCNotification(
|
||||
notification.method.value,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import kotlinx.serialization.Serializable
|
|||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.decodeFromJsonElement
|
||||
import kotlinx.serialization.json.encodeToJsonElement
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
|
|
@ -125,10 +126,11 @@ public sealed interface Request {
|
|||
* @return The JSON-RPC request representation.
|
||||
*/
|
||||
internal fun Request.toJSON(): JSONRPCRequest {
|
||||
val encoded = JsonObject(McpJson.encodeToJsonElement(this).jsonObject.minus("method"))
|
||||
val fullJson = McpJson.encodeToJsonElement(this).jsonObject
|
||||
val params = JsonObject(fullJson.filterKeys { it != "method" })
|
||||
return JSONRPCRequest(
|
||||
method = method.value,
|
||||
params = encoded,
|
||||
params = params,
|
||||
jsonrpc = JSONRPC_VERSION,
|
||||
)
|
||||
}
|
||||
|
|
@ -139,8 +141,7 @@ internal fun Request.toJSON(): JSONRPCRequest {
|
|||
* @return The decoded [Request] or null
|
||||
*/
|
||||
internal fun JSONRPCRequest.fromJSON(): Request {
|
||||
val requestData = JsonObject(params.jsonObject.plus("method" to JsonPrimitive(method)))
|
||||
|
||||
val requestData = JsonObject(params.jsonObject + ("method" to JsonPrimitive(method)))
|
||||
val deserializer = selectRequestDeserializer(method)
|
||||
return McpJson.decodeFromJsonElement(deserializer, requestData)
|
||||
}
|
||||
|
|
@ -159,6 +160,7 @@ public open class CustomRequest(override val method: Method) : Request
|
|||
@Serializable(with = NotificationPolymorphicSerializer::class)
|
||||
public sealed interface Notification {
|
||||
public val method: Method
|
||||
public val params: NotificationParams?
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -167,10 +169,9 @@ public sealed interface Notification {
|
|||
* @return The JSON-RPC notification representation.
|
||||
*/
|
||||
internal fun Notification.toJSON(): JSONRPCNotification {
|
||||
val encoded = JsonObject(McpJson.encodeToJsonElement<Notification>(this).jsonObject.minus("method"))
|
||||
return JSONRPCNotification(
|
||||
method.value,
|
||||
params = encoded
|
||||
method = method.value,
|
||||
params = McpJson.encodeToJsonElement(params),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +181,10 @@ internal fun Notification.toJSON(): JSONRPCNotification {
|
|||
* @return The decoded [Notification].
|
||||
*/
|
||||
internal fun JSONRPCNotification.fromJSON(): Notification {
|
||||
val data = JsonObject(params.jsonObject.plus("method" to JsonPrimitive(method)))
|
||||
val data = buildJsonObject {
|
||||
put("method", JsonPrimitive(method))
|
||||
put("params", params)
|
||||
}
|
||||
return McpJson.decodeFromJsonElement<Notification>(data)
|
||||
}
|
||||
|
||||
|
|
@ -295,6 +299,12 @@ public data class JSONRPCError(
|
|||
val data: JsonObject = EmptyJsonObject,
|
||||
) : JSONRPCMessage
|
||||
|
||||
/**
|
||||
* Base interface for notification parameters with optional metadata.
|
||||
*/
|
||||
@Serializable
|
||||
public sealed interface NotificationParams : WithMeta
|
||||
|
||||
/* Cancellation */
|
||||
/**
|
||||
* This notification can be sent by either side to indicate that it is cancelling a previously issued request.
|
||||
|
|
@ -307,19 +317,24 @@ public data class JSONRPCError(
|
|||
*/
|
||||
@Serializable
|
||||
public data class CancelledNotification(
|
||||
/**
|
||||
* The ID of the request to cancel.
|
||||
*
|
||||
* It MUST correspond to the ID of a request previously issued in the same direction.
|
||||
*/
|
||||
val requestId: RequestId,
|
||||
/**
|
||||
* An optional string describing the reason for the cancellation. This MAY be logged or presented to the user.
|
||||
*/
|
||||
val reason: String?,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientNotification, ServerNotification, WithMeta {
|
||||
override val params: Params,
|
||||
) : ClientNotification, ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsCancelled
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
/**
|
||||
* The ID of the request to cancel.
|
||||
*
|
||||
* It MUST correspond to the ID of a request previously issued in the same direction.
|
||||
*/
|
||||
val requestId: RequestId,
|
||||
/**
|
||||
* An optional string describing the reason for the cancellation. This MAY be logged or presented to the user.
|
||||
*/
|
||||
val reason: String? = null,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
}
|
||||
|
||||
/* Initialization */
|
||||
|
|
@ -408,7 +423,7 @@ public sealed interface ServerResult : RequestResult
|
|||
*/
|
||||
@Serializable
|
||||
public data class UnknownMethodRequestOrNotification(
|
||||
override val method: Method,
|
||||
override val method: Method, override val params: NotificationParams? = null,
|
||||
) : ClientNotification, ClientRequest, ServerNotification, ServerRequest
|
||||
|
||||
/**
|
||||
|
|
@ -506,8 +521,15 @@ public data class InitializeResult(
|
|||
* This notification is sent from the client to the server after initialization has finished.
|
||||
*/
|
||||
@Serializable
|
||||
public class InitializedNotification : ClientNotification {
|
||||
public data class InitializedNotification(
|
||||
override val params: Params = Params(),
|
||||
) : ClientNotification {
|
||||
override val method: Method = Method.Defined.NotificationsInitialized
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
}
|
||||
|
||||
/* Ping */
|
||||
|
|
@ -528,7 +550,7 @@ public sealed interface ProgressBase {
|
|||
/**
|
||||
* The progress thus far. This should increase every time progress is made, even if the total is unknown.
|
||||
*/
|
||||
public val progress: Int
|
||||
public val progress: Double
|
||||
|
||||
/**
|
||||
* Total number of items to a process (or total progress required), if known.
|
||||
|
|
@ -553,7 +575,7 @@ public open class Progress(
|
|||
/**
|
||||
* The progress thus far. This should increase every time progress is made, even if the total is unknown.
|
||||
*/
|
||||
override val progress: Int,
|
||||
override val progress: Double,
|
||||
|
||||
/**
|
||||
* Total number of items to a process (or total progress required), if known.
|
||||
|
|
@ -571,18 +593,32 @@ public open class Progress(
|
|||
*/
|
||||
@Serializable
|
||||
public data class ProgressNotification(
|
||||
override val progress: Int,
|
||||
/**
|
||||
* The progress token,
|
||||
* which was given in the initial request,
|
||||
* used to associate this notification with the request that is proceeding.
|
||||
*/
|
||||
public val progressToken: ProgressToken,
|
||||
@Suppress("PropertyName") val _meta: JsonObject = EmptyJsonObject,
|
||||
override val total: Double?,
|
||||
override val message: String?,
|
||||
) : ClientNotification, ServerNotification, ProgressBase {
|
||||
override val params: Params,
|
||||
) : ClientNotification, ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsProgress
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
/**
|
||||
* The progress thus far. This should increase every time progress is made, even if the total is unknown.
|
||||
*/
|
||||
override val progress: Double,
|
||||
/**
|
||||
* The progress token,
|
||||
* which was given in the initial request,
|
||||
* used to associate this notification with the request that is proceeding.
|
||||
*/
|
||||
val progressToken: ProgressToken,
|
||||
/**
|
||||
* Total number of items to process (or total progress required), if known.
|
||||
*/
|
||||
override val total: Double? = null,
|
||||
/**
|
||||
* An optional message describing the current progress.
|
||||
*/
|
||||
override val message: String? = null,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams, ProgressBase
|
||||
}
|
||||
|
||||
/* Pagination */
|
||||
|
|
@ -784,8 +820,15 @@ public class ReadResourceResult(
|
|||
* Servers may issue this without any previous subscription from the client.
|
||||
*/
|
||||
@Serializable
|
||||
public class ResourceListChangedNotification : ServerNotification {
|
||||
public data class ResourceListChangedNotification(
|
||||
override val params: Params = Params(),
|
||||
) : ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsResourcesListChanged
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -821,13 +864,18 @@ public data class UnsubscribeRequest(
|
|||
*/
|
||||
@Serializable
|
||||
public data class ResourceUpdatedNotification(
|
||||
/**
|
||||
* The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.
|
||||
*/
|
||||
val uri: String,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ServerNotification, WithMeta {
|
||||
override val params: Params,
|
||||
) : ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsResourcesUpdated
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
/**
|
||||
* The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.
|
||||
*/
|
||||
val uri: String,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
}
|
||||
|
||||
/* Prompts */
|
||||
|
|
@ -1044,8 +1092,15 @@ public class GetPromptResult(
|
|||
* Servers may issue this without any previous subscription from the client.
|
||||
*/
|
||||
@Serializable
|
||||
public class PromptListChangedNotification : ServerNotification {
|
||||
public data class PromptListChangedNotification(
|
||||
override val params: Params = Params(),
|
||||
) : ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsPromptsListChanged
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
}
|
||||
|
||||
/* Tools */
|
||||
|
|
@ -1223,8 +1278,15 @@ public data class CallToolRequest(
|
|||
* Servers may issue this without any previous subscription from the client.
|
||||
*/
|
||||
@Serializable
|
||||
public class ToolListChangedNotification : ServerNotification {
|
||||
public data class ToolListChangedNotification(
|
||||
override val params: Params = Params(),
|
||||
) : ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsToolsListChanged
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
}
|
||||
|
||||
/* Logging */
|
||||
|
|
@ -1252,22 +1314,27 @@ public enum class LoggingLevel {
|
|||
*/
|
||||
@Serializable
|
||||
public data class LoggingMessageNotification(
|
||||
/**
|
||||
* The severity of this log message.
|
||||
*/
|
||||
val level: LoggingLevel,
|
||||
override val params: Params,
|
||||
) : ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsMessage
|
||||
|
||||
/**
|
||||
* An optional name of the logger issuing this message.
|
||||
*/
|
||||
val logger: String? = null,
|
||||
@Serializable
|
||||
public data class Params(
|
||||
/**
|
||||
* The severity of this log message.
|
||||
*/
|
||||
val level: LoggingLevel,
|
||||
/**
|
||||
* An optional name of the logger issuing this message.
|
||||
*/
|
||||
val logger: String? = null,
|
||||
/**
|
||||
* The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here.
|
||||
*/
|
||||
val data: JsonElement,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
|
||||
/**
|
||||
* The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here.
|
||||
*/
|
||||
val data: JsonObject = EmptyJsonObject,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ServerNotification, WithMeta {
|
||||
/**
|
||||
* A request from the client to the server to enable or adjust logging.
|
||||
*/
|
||||
|
|
@ -1281,8 +1348,6 @@ public data class LoggingMessageNotification(
|
|||
) : ClientRequest, WithMeta {
|
||||
override val method: Method = Method.Defined.LoggingSetLevel
|
||||
}
|
||||
|
||||
override val method: Method = Method.Defined.NotificationsMessage
|
||||
}
|
||||
|
||||
/* Sampling */
|
||||
|
|
@ -1578,8 +1643,15 @@ public class ListRootsResult(
|
|||
* A notification from the client to the server, informing it that the list of roots has changed.
|
||||
*/
|
||||
@Serializable
|
||||
public class RootsListChangedNotification : ClientNotification {
|
||||
public data class RootsListChangedNotification(
|
||||
override val params: Params = Params(),
|
||||
) : ClientNotification {
|
||||
override val method: Method = Method.Defined.NotificationsRootsListChanged
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk
|
||||
|
||||
import io.kotest.assertions.json.shouldEqualJson
|
||||
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class AudioContentSerializationTest {
|
||||
|
||||
private val audioContentJson = """
|
||||
{
|
||||
"data": "base64-encoded-audio-data",
|
||||
"mimeType": "audio/wav",
|
||||
"type": "audio"
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
private val audioContent = AudioContent(
|
||||
data = "base64-encoded-audio-data",
|
||||
mimeType = "audio/wav"
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `should serialize audio content`() {
|
||||
McpJson.encodeToString(audioContent) shouldEqualJson audioContentJson
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize audio content`() {
|
||||
val content = McpJson.decodeFromString<AudioContent>(audioContentJson)
|
||||
assertEquals(expected = audioContent, actual = content)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk
|
||||
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class CallToolResultUtilsTest {
|
||||
|
||||
@Test
|
||||
fun testOkWithOnlyText() {
|
||||
val content = "TextMessage"
|
||||
val result = CallToolResult.Companion.ok(content)
|
||||
|
||||
assertEquals(1, result.content.size)
|
||||
assertEquals(content, (result.content[0] as TextContent).text)
|
||||
assertFalse(result.isError == true)
|
||||
assertEquals(EmptyJsonObject, result._meta)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOkWithMeta() {
|
||||
val content = "TextMessageWithMeta"
|
||||
val meta = buildJsonObject {
|
||||
put("key1", JsonPrimitive("value1"))
|
||||
put("key2", JsonPrimitive(42))
|
||||
}
|
||||
val result = CallToolResult.Companion.ok(content, meta)
|
||||
|
||||
assertEquals(1, result.content.size)
|
||||
assertEquals(content, (result.content[0] as TextContent).text)
|
||||
assertFalse(result.isError == true)
|
||||
assertEquals(meta, result._meta)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorWithOnlyText() {
|
||||
val content = "ErrorMessage"
|
||||
val result = CallToolResult.Companion.error(content)
|
||||
|
||||
assertEquals(1, result.content.size)
|
||||
assertEquals(content, (result.content[0] as TextContent).text)
|
||||
assertTrue(result.isError == true)
|
||||
assertEquals(EmptyJsonObject, result._meta)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testErrorWithMeta() {
|
||||
val content = "ErrorMessageWithMeta"
|
||||
val meta = buildJsonObject {
|
||||
put("errorCode", JsonPrimitive(404))
|
||||
put("errorDetail", JsonPrimitive("资源未找到"))
|
||||
}
|
||||
val result = CallToolResult.Companion.error(content, meta)
|
||||
|
||||
assertEquals(1, result.content.size)
|
||||
assertEquals(content, (result.content[0] as TextContent).text)
|
||||
assertTrue(result.isError == true)
|
||||
assertEquals(meta, result._meta)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk
|
||||
|
||||
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertIs
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class TypesTest {
|
||||
|
||||
@Test
|
||||
fun `should have correct latest protocol version`() {
|
||||
assertNotEquals("", LATEST_PROTOCOL_VERSION)
|
||||
assertEquals("2024-11-05", LATEST_PROTOCOL_VERSION)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should have correct supported protocol versions`() {
|
||||
assertIs<Array<String>>(SUPPORTED_PROTOCOL_VERSIONS)
|
||||
assertTrue(SUPPORTED_PROTOCOL_VERSIONS.contains(LATEST_PROTOCOL_VERSION))
|
||||
assertTrue(SUPPORTED_PROTOCOL_VERSIONS.contains("2024-10-07"))
|
||||
assertEquals(2, SUPPORTED_PROTOCOL_VERSIONS.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should validate JSONRPC version constant`() {
|
||||
assertEquals("2.0", JSONRPC_VERSION)
|
||||
}
|
||||
|
||||
// Reference Tests
|
||||
@Test
|
||||
fun `should validate ResourceReference`() {
|
||||
val resourceRef = ResourceReference(uri = "file:///path/to/file.txt")
|
||||
|
||||
assertEquals("ref/resource", resourceRef.type)
|
||||
assertEquals("file:///path/to/file.txt", resourceRef.uri)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize ResourceReference correctly`() {
|
||||
val resourceRef = ResourceReference(uri = "https://example.com/resource")
|
||||
|
||||
val json = McpJson.encodeToString<Reference>(resourceRef)
|
||||
val decoded = McpJson.decodeFromString<Reference>(json)
|
||||
|
||||
assertIs<ResourceReference>(decoded)
|
||||
assertEquals("ref/resource", decoded.type)
|
||||
assertEquals("https://example.com/resource", decoded.uri)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should validate PromptReference`() {
|
||||
val promptRef = PromptReference(name = "greeting")
|
||||
|
||||
assertEquals("ref/prompt", promptRef.type)
|
||||
assertEquals("greeting", promptRef.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize PromptReference correctly`() {
|
||||
val promptRef = PromptReference(name = "test-prompt")
|
||||
|
||||
val json = McpJson.encodeToString<Reference>(promptRef)
|
||||
val decoded = McpJson.decodeFromString<Reference>(json)
|
||||
|
||||
assertIs<PromptReference>(decoded)
|
||||
assertEquals("ref/prompt", decoded.type)
|
||||
assertEquals("test-prompt", decoded.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle UnknownReference for invalid type`() {
|
||||
val invalidJson = """{"type": "invalid_type"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<Reference>(invalidJson)
|
||||
|
||||
assertIs<UnknownReference>(decoded)
|
||||
assertEquals("invalid_type", decoded.type)
|
||||
}
|
||||
|
||||
// PromptMessageContent Tests
|
||||
@Test
|
||||
fun `should validate text content`() {
|
||||
val textContent = TextContent(text = "Hello, world!")
|
||||
|
||||
assertEquals("text", textContent.type)
|
||||
assertEquals("Hello, world!", textContent.text)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize text content correctly`() {
|
||||
val textContent = TextContent(text = "Test message")
|
||||
|
||||
val json = McpJson.encodeToString<PromptMessageContent>(textContent)
|
||||
val decoded = McpJson.decodeFromString<PromptMessageContent>(json)
|
||||
|
||||
assertIs<TextContent>(decoded)
|
||||
assertEquals("text", decoded.type)
|
||||
assertEquals("Test message", decoded.text)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should validate image content`() {
|
||||
val imageContent = ImageContent(
|
||||
data = "aGVsbG8=", // base64 encoded "hello"
|
||||
mimeType = "image/png"
|
||||
)
|
||||
|
||||
assertEquals("image", imageContent.type)
|
||||
assertEquals("aGVsbG8=", imageContent.data)
|
||||
assertEquals("image/png", imageContent.mimeType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize image content correctly`() {
|
||||
val imageContent = ImageContent(
|
||||
data = "dGVzdA==", // base64 encoded "test"
|
||||
mimeType = "image/jpeg"
|
||||
)
|
||||
|
||||
val json = McpJson.encodeToString<PromptMessageContent>(imageContent)
|
||||
val decoded = McpJson.decodeFromString<PromptMessageContent>(json)
|
||||
|
||||
assertIs<ImageContent>(decoded)
|
||||
assertEquals("image", decoded.type)
|
||||
assertEquals("dGVzdA==", decoded.data)
|
||||
assertEquals("image/jpeg", decoded.mimeType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should validate audio content`() {
|
||||
val audioContent = AudioContent(
|
||||
data = "aGVsbG8=", // base64 encoded "hello"
|
||||
mimeType = "audio/mp3"
|
||||
)
|
||||
|
||||
assertEquals("audio", audioContent.type)
|
||||
assertEquals("aGVsbG8=", audioContent.data)
|
||||
assertEquals("audio/mp3", audioContent.mimeType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize audio content correctly`() {
|
||||
val audioContent = AudioContent(
|
||||
data = "YXVkaW8=", // base64 encoded "audio"
|
||||
mimeType = "audio/wav"
|
||||
)
|
||||
|
||||
val json = McpJson.encodeToString<PromptMessageContent>(audioContent)
|
||||
val decoded = McpJson.decodeFromString<PromptMessageContent>(json)
|
||||
|
||||
assertIs<AudioContent>(decoded)
|
||||
assertEquals("audio", decoded.type)
|
||||
assertEquals("YXVkaW8=", decoded.data)
|
||||
assertEquals("audio/wav", decoded.mimeType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should validate embedded resource content`() {
|
||||
val resource = TextResourceContents(
|
||||
text = "File contents",
|
||||
uri = "file:///path/to/file.txt",
|
||||
mimeType = "text/plain"
|
||||
)
|
||||
val embeddedResource = EmbeddedResource(resource = resource)
|
||||
|
||||
assertEquals("resource", embeddedResource.type)
|
||||
assertEquals(resource, embeddedResource.resource)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize embedded resource content correctly`() {
|
||||
val resource = BlobResourceContents(
|
||||
blob = "YmluYXJ5ZGF0YQ==",
|
||||
uri = "file:///path/to/binary.dat",
|
||||
mimeType = "application/octet-stream"
|
||||
)
|
||||
val embeddedResource = EmbeddedResource(resource = resource)
|
||||
|
||||
val json = McpJson.encodeToString<PromptMessageContent>(embeddedResource)
|
||||
val decoded = McpJson.decodeFromString<PromptMessageContent>(json)
|
||||
|
||||
assertIs<EmbeddedResource>(decoded)
|
||||
assertEquals("resource", decoded.type)
|
||||
assertIs<BlobResourceContents>(decoded.resource)
|
||||
val decodedBlob = decoded.resource
|
||||
assertEquals("YmluYXJ5ZGF0YQ==", decodedBlob.blob)
|
||||
assertEquals("file:///path/to/binary.dat", decodedBlob.uri)
|
||||
assertEquals("application/octet-stream", decodedBlob.mimeType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle unknown content type`() {
|
||||
val unknownJson = """{"type": "unknown_type"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<PromptMessageContent>(unknownJson)
|
||||
|
||||
assertIs<UnknownContent>(decoded)
|
||||
assertEquals("unknown_type", decoded.type)
|
||||
}
|
||||
|
||||
// PromptMessage Tests
|
||||
@Test
|
||||
fun `should validate prompt message with text content`() {
|
||||
val textContent = TextContent(text = "Hello, assistant!")
|
||||
val promptMessage = PromptMessage(
|
||||
role = Role.user,
|
||||
content = textContent
|
||||
)
|
||||
|
||||
assertEquals(Role.user, promptMessage.role)
|
||||
assertEquals(textContent, promptMessage.content)
|
||||
assertEquals("text", promptMessage.content.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should validate prompt message with embedded resource`() {
|
||||
val resource = TextResourceContents(
|
||||
text = "Primary application entry point",
|
||||
uri = "file:///project/src/main.rs",
|
||||
mimeType = "text/x-rust"
|
||||
)
|
||||
val embeddedResource = EmbeddedResource(resource = resource)
|
||||
val promptMessage = PromptMessage(
|
||||
role = Role.assistant,
|
||||
content = embeddedResource
|
||||
)
|
||||
|
||||
assertEquals(Role.assistant, promptMessage.role)
|
||||
assertEquals("resource", promptMessage.content.type)
|
||||
val content = promptMessage.content as EmbeddedResource
|
||||
val textResource = content.resource as TextResourceContents
|
||||
assertEquals("Primary application entry point", textResource.text)
|
||||
assertEquals("file:///project/src/main.rs", textResource.uri)
|
||||
assertEquals("text/x-rust", textResource.mimeType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize prompt message correctly`() {
|
||||
val imageContent = ImageContent(
|
||||
data = "aW1hZ2VkYXRh", // base64 encoded "imagedata"
|
||||
mimeType = "image/png"
|
||||
)
|
||||
val promptMessage = PromptMessage(
|
||||
role = Role.assistant,
|
||||
content = imageContent
|
||||
)
|
||||
|
||||
val json = McpJson.encodeToString(promptMessage)
|
||||
val decoded = McpJson.decodeFromString<PromptMessage>(json)
|
||||
|
||||
assertEquals(Role.assistant, decoded.role)
|
||||
assertIs<ImageContent>(decoded.content)
|
||||
val decodedContent = decoded.content
|
||||
assertEquals("aW1hZ2VkYXRh", decodedContent.data)
|
||||
assertEquals("image/png", decodedContent.mimeType)
|
||||
}
|
||||
|
||||
// CallToolResult Tests
|
||||
@Test
|
||||
fun `should validate tool result with multiple content types`() {
|
||||
val toolResult = CallToolResult(
|
||||
content = listOf(
|
||||
TextContent(text = "Found the following files:"),
|
||||
EmbeddedResource(
|
||||
resource = TextResourceContents(
|
||||
text = "fn main() {}",
|
||||
uri = "file:///project/src/main.rs",
|
||||
mimeType = "text/x-rust"
|
||||
)
|
||||
),
|
||||
EmbeddedResource(
|
||||
resource = TextResourceContents(
|
||||
text = "pub mod lib;",
|
||||
uri = "file:///project/src/lib.rs",
|
||||
mimeType = "text/x-rust"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
assertEquals(3, toolResult.content.size)
|
||||
assertEquals("text", toolResult.content[0].type)
|
||||
assertEquals("resource", toolResult.content[1].type)
|
||||
assertEquals("resource", toolResult.content[2].type)
|
||||
assertEquals(false, toolResult.isError)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should validate empty content array with default`() {
|
||||
val toolResult = CallToolResult(content = emptyList())
|
||||
|
||||
assertEquals(0, toolResult.content.size)
|
||||
assertEquals(false, toolResult.isError)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize CallToolResult correctly`() {
|
||||
val toolResult = CallToolResult(
|
||||
content = listOf(
|
||||
TextContent(text = "Operation completed"),
|
||||
ImageContent(data = "aW1hZ2U=", mimeType = "image/png")
|
||||
),
|
||||
isError = false
|
||||
)
|
||||
|
||||
val json = McpJson.encodeToString(toolResult)
|
||||
val decoded = McpJson.decodeFromString<CallToolResult>(json)
|
||||
|
||||
assertEquals(2, decoded.content.size)
|
||||
assertIs<TextContent>(decoded.content[0])
|
||||
assertIs<ImageContent>(decoded.content[1])
|
||||
assertEquals(false, decoded.isError)
|
||||
}
|
||||
|
||||
// CompleteRequest Tests
|
||||
@Test
|
||||
fun `should validate CompleteRequest with prompt reference`() {
|
||||
val request = CompleteRequest(
|
||||
ref = PromptReference(name = "greeting"),
|
||||
argument = CompleteRequest.Argument(name = "name", value = "A")
|
||||
)
|
||||
|
||||
assertEquals("completion/complete", request.method.value)
|
||||
assertIs<PromptReference>(request.ref)
|
||||
val promptRef = request.ref
|
||||
assertEquals("greeting", promptRef.name)
|
||||
assertEquals("name", request.argument.name)
|
||||
assertEquals("A", request.argument.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should validate CompleteRequest with resource reference`() {
|
||||
val request = CompleteRequest(
|
||||
ref = ResourceReference(uri = "github://repos/{owner}/{repo}"),
|
||||
argument = CompleteRequest.Argument(name = "repo", value = "t")
|
||||
)
|
||||
|
||||
assertEquals("completion/complete", request.method.value)
|
||||
assertIs<ResourceReference>(request.ref)
|
||||
val resourceRef = request.ref
|
||||
assertEquals("github://repos/{owner}/{repo}", resourceRef.uri)
|
||||
assertEquals("repo", request.argument.name)
|
||||
assertEquals("t", request.argument.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize CompleteRequest correctly`() {
|
||||
val request = CompleteRequest(
|
||||
ref = PromptReference(name = "test"),
|
||||
argument = CompleteRequest.Argument(name = "arg", value = "")
|
||||
)
|
||||
|
||||
val json = McpJson.encodeToString(request)
|
||||
val decoded = McpJson.decodeFromString<CompleteRequest>(json)
|
||||
|
||||
assertEquals("completion/complete", decoded.method.value)
|
||||
assertIs<PromptReference>(decoded.ref)
|
||||
val promptRef = decoded.ref
|
||||
assertEquals("test", promptRef.name)
|
||||
assertEquals("arg", decoded.argument.name)
|
||||
assertEquals("", decoded.argument.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should validate CompleteRequest with complex URIs`() {
|
||||
val request = CompleteRequest(
|
||||
ref = ResourceReference(uri = "api://v1/{tenant}/{resource}/{id}"),
|
||||
argument = CompleteRequest.Argument(name = "id", value = "123")
|
||||
)
|
||||
|
||||
val resourceRef = request.ref as ResourceReference
|
||||
assertEquals("api://v1/{tenant}/{resource}/{id}", resourceRef.uri)
|
||||
assertEquals("id", request.argument.name)
|
||||
assertEquals("123", request.argument.value)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk
|
||||
|
||||
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.put
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertIs
|
||||
|
||||
class TypesUtilTest {
|
||||
|
||||
// ErrorCode Serializer Tests
|
||||
@Test
|
||||
fun `should serialize and deserialize ErrorCode Defined correctly`() {
|
||||
val errorCode: ErrorCode = ErrorCode.Defined.InvalidRequest
|
||||
|
||||
val json = McpJson.encodeToString(errorCode)
|
||||
val decoded = McpJson.decodeFromString<ErrorCode>(json)
|
||||
|
||||
assertEquals(ErrorCode.Defined.InvalidRequest, decoded)
|
||||
assertEquals(-32600, decoded.code)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize ErrorCode Unknown correctly`() {
|
||||
val errorCode: ErrorCode = ErrorCode.Unknown(1001)
|
||||
|
||||
val json = McpJson.encodeToString(errorCode)
|
||||
val decoded = McpJson.decodeFromString<ErrorCode>(json)
|
||||
|
||||
assertIs<ErrorCode.Unknown>(decoded)
|
||||
assertEquals(1001, decoded.code)
|
||||
}
|
||||
|
||||
// Method Serializer Tests
|
||||
@Test
|
||||
fun `should serialize and deserialize Method Defined correctly`() {
|
||||
val method: Method = Method.Defined.Initialize
|
||||
|
||||
val json = McpJson.encodeToString(method)
|
||||
val decoded = McpJson.decodeFromString<Method>(json)
|
||||
|
||||
assertEquals(Method.Defined.Initialize, decoded)
|
||||
assertEquals("initialize", decoded.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize Method Custom correctly`() {
|
||||
val method: Method = Method.Custom("custom/method")
|
||||
|
||||
val json = McpJson.encodeToString(method)
|
||||
val decoded = McpJson.decodeFromString<Method>(json)
|
||||
|
||||
assertIs<Method.Custom>(decoded)
|
||||
assertEquals("custom/method", decoded.value)
|
||||
}
|
||||
|
||||
// StopReason Serializer Tests
|
||||
@Test
|
||||
fun `should serialize and deserialize StopReason EndTurn correctly`() {
|
||||
val stopReason: StopReason = StopReason.EndTurn
|
||||
|
||||
val json = McpJson.encodeToString(stopReason)
|
||||
val decoded = McpJson.decodeFromString<StopReason>(json)
|
||||
|
||||
assertEquals(StopReason.EndTurn, decoded)
|
||||
assertEquals("endTurn", decoded.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize StopReason Other correctly`() {
|
||||
val stopReason: StopReason = StopReason.Other("custom_reason")
|
||||
|
||||
val json = McpJson.encodeToString(stopReason)
|
||||
val decoded = McpJson.decodeFromString<StopReason>(json)
|
||||
|
||||
assertIs<StopReason.Other>(decoded)
|
||||
assertEquals("custom_reason", decoded.value)
|
||||
}
|
||||
|
||||
// Reference Polymorphic Serializer Tests
|
||||
@Test
|
||||
fun `should deserialize ResourceReference polymorphically`() {
|
||||
val json = """{"type": "ref/resource", "uri": "file:///test.txt"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<Reference>(json)
|
||||
|
||||
assertIs<ResourceReference>(decoded)
|
||||
assertEquals("ref/resource", decoded.type)
|
||||
assertEquals("file:///test.txt", decoded.uri)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize PromptReference polymorphically`() {
|
||||
val json = """{"type": "ref/prompt", "name": "test-prompt"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<Reference>(json)
|
||||
|
||||
assertIs<PromptReference>(decoded)
|
||||
assertEquals("ref/prompt", decoded.type)
|
||||
assertEquals("test-prompt", decoded.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize UnknownReference for invalid type`() {
|
||||
val json = """{"type": "unknown_ref", "data": "test"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<Reference>(json)
|
||||
|
||||
assertIs<UnknownReference>(decoded)
|
||||
assertEquals("unknown_ref", decoded.type)
|
||||
}
|
||||
|
||||
// PromptMessageContent Polymorphic Serializer Tests
|
||||
@Test
|
||||
fun `should deserialize TextContent polymorphically`() {
|
||||
val json = """{"type": "text", "text": "Hello world"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<PromptMessageContent>(json)
|
||||
|
||||
assertIs<TextContent>(decoded)
|
||||
assertEquals("text", decoded.type)
|
||||
assertEquals("Hello world", decoded.text)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize ImageContent polymorphically`() {
|
||||
val json = """{"type": "image", "data": "aW1hZ2U=", "mimeType": "image/png"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<PromptMessageContent>(json)
|
||||
|
||||
assertIs<ImageContent>(decoded)
|
||||
assertEquals("image", decoded.type)
|
||||
assertEquals("aW1hZ2U=", decoded.data)
|
||||
assertEquals("image/png", decoded.mimeType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize AudioContent polymorphically`() {
|
||||
val json = """{"type": "audio", "data": "YXVkaW8=", "mimeType": "audio/mp3"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<PromptMessageContent>(json)
|
||||
|
||||
assertIs<AudioContent>(decoded)
|
||||
assertEquals("audio", decoded.type)
|
||||
assertEquals("YXVkaW8=", decoded.data)
|
||||
assertEquals("audio/mp3", decoded.mimeType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize EmbeddedResource polymorphically`() {
|
||||
val json =
|
||||
"""{"type": "resource", "resource": {"uri": "file:///test.txt", "mimeType": "text/plain", "text": "content"}}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<PromptMessageContent>(json)
|
||||
|
||||
assertIs<EmbeddedResource>(decoded)
|
||||
assertEquals("resource", decoded.type)
|
||||
assertIs<TextResourceContents>(decoded.resource)
|
||||
val textResource = decoded.resource
|
||||
assertEquals("file:///test.txt", textResource.uri)
|
||||
assertEquals("content", textResource.text)
|
||||
}
|
||||
|
||||
// ResourceContents Polymorphic Serializer Tests
|
||||
@Test
|
||||
fun `should deserialize TextResourceContents polymorphically`() {
|
||||
val json = """{"uri": "file:///test.txt", "mimeType": "text/plain", "text": "file content"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<ResourceContents>(json)
|
||||
|
||||
assertIs<TextResourceContents>(decoded)
|
||||
assertEquals("file:///test.txt", decoded.uri)
|
||||
assertEquals("file content", decoded.text)
|
||||
assertEquals("text/plain", decoded.mimeType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize BlobResourceContents polymorphically`() {
|
||||
val json = """{"uri": "file:///binary.dat", "mimeType": "application/octet-stream", "blob": "YmluYXJ5"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<ResourceContents>(json)
|
||||
|
||||
assertIs<BlobResourceContents>(decoded)
|
||||
assertEquals("file:///binary.dat", decoded.uri)
|
||||
assertEquals("YmluYXJ5", decoded.blob)
|
||||
assertEquals("application/octet-stream", decoded.mimeType)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize UnknownResourceContents for missing fields`() {
|
||||
val json = """{"uri": "file:///unknown.dat", "mimeType": "unknown/type"}"""
|
||||
|
||||
val decoded = McpJson.decodeFromString<ResourceContents>(json)
|
||||
|
||||
assertIs<UnknownResourceContents>(decoded)
|
||||
assertEquals("file:///unknown.dat", decoded.uri)
|
||||
assertEquals("unknown/type", decoded.mimeType)
|
||||
}
|
||||
|
||||
// RequestId Serializer Tests
|
||||
@Test
|
||||
fun `should serialize and deserialize RequestId StringId correctly`() {
|
||||
val requestId: RequestId = RequestId.StringId("test-id")
|
||||
|
||||
val json = McpJson.encodeToString(requestId)
|
||||
val decoded = McpJson.decodeFromString<RequestId>(json)
|
||||
|
||||
assertIs<RequestId.StringId>(decoded)
|
||||
assertEquals("test-id", decoded.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should serialize and deserialize RequestId NumberId correctly`() {
|
||||
val requestId: RequestId = RequestId.NumberId(42L)
|
||||
|
||||
val json = McpJson.encodeToString(requestId)
|
||||
val decoded = McpJson.decodeFromString<RequestId>(json)
|
||||
|
||||
assertIs<RequestId.NumberId>(decoded)
|
||||
assertEquals(42L, decoded.value)
|
||||
}
|
||||
|
||||
// Utility Functions Tests
|
||||
@Test
|
||||
fun `should create CallToolResult ok correctly`() {
|
||||
val result = CallToolResult.ok("Success message")
|
||||
|
||||
assertEquals(listOf(TextContent("Success message")), result.content)
|
||||
assertEquals(false, result.isError)
|
||||
assertEquals(EmptyJsonObject, result._meta)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should create CallToolResult error correctly`() {
|
||||
val result = CallToolResult.error("Error message")
|
||||
|
||||
assertEquals(listOf(TextContent("Error message")), result.content)
|
||||
assertEquals(true, result.isError)
|
||||
assertEquals(EmptyJsonObject, result._meta)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should create CallToolResult with custom meta`() {
|
||||
val meta = buildJsonObject { put("custom", "value") }
|
||||
val result = CallToolResult.ok("Success", meta)
|
||||
|
||||
assertEquals(listOf(TextContent("Success")), result.content)
|
||||
assertEquals(false, result.isError)
|
||||
assertEquals(meta, result._meta)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk.client
|
||||
|
||||
import io.modelcontextprotocol.kotlin.sdk.Implementation
|
||||
import io.modelcontextprotocol.kotlin.sdk.ListToolsResult
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.io.asSink
|
||||
import kotlinx.io.asSource
|
||||
import kotlinx.io.buffered
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.net.Socket
|
||||
|
||||
class ClientIntegrationTest {
|
||||
|
||||
fun createTransport(): StdioClientTransport {
|
||||
val socket = Socket("localhost", 3000)
|
||||
|
||||
return StdioClientTransport(
|
||||
socket.inputStream.asSource().buffered(),
|
||||
socket.outputStream.asSink().buffered()
|
||||
)
|
||||
}
|
||||
|
||||
@Disabled("This test requires a running server")
|
||||
@Test
|
||||
fun testRequestTools() = runTest {
|
||||
val client = Client(
|
||||
Implementation("test", "1.0"),
|
||||
)
|
||||
|
||||
val transport = createTransport()
|
||||
try {
|
||||
client.connect(transport)
|
||||
|
||||
val response: ListToolsResult? = client.listTools()
|
||||
println(response?.tools)
|
||||
|
||||
} finally {
|
||||
transport.close()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,908 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk.client
|
||||
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.spyk
|
||||
import io.modelcontextprotocol.kotlin.sdk.ClientCapabilities
|
||||
import io.modelcontextprotocol.kotlin.sdk.CreateElicitationRequest
|
||||
import io.modelcontextprotocol.kotlin.sdk.CreateElicitationResult
|
||||
import io.modelcontextprotocol.kotlin.sdk.CreateMessageRequest
|
||||
import io.modelcontextprotocol.kotlin.sdk.CreateMessageResult
|
||||
import io.modelcontextprotocol.kotlin.sdk.EmptyJsonObject
|
||||
import io.modelcontextprotocol.kotlin.sdk.Implementation
|
||||
import io.modelcontextprotocol.kotlin.sdk.InMemoryTransport
|
||||
import io.modelcontextprotocol.kotlin.sdk.InitializeRequest
|
||||
import io.modelcontextprotocol.kotlin.sdk.InitializeResult
|
||||
import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage
|
||||
import io.modelcontextprotocol.kotlin.sdk.JSONRPCRequest
|
||||
import io.modelcontextprotocol.kotlin.sdk.JSONRPCResponse
|
||||
import io.modelcontextprotocol.kotlin.sdk.LATEST_PROTOCOL_VERSION
|
||||
import io.modelcontextprotocol.kotlin.sdk.ListResourcesRequest
|
||||
import io.modelcontextprotocol.kotlin.sdk.ListResourcesResult
|
||||
import io.modelcontextprotocol.kotlin.sdk.ListRootsRequest
|
||||
import io.modelcontextprotocol.kotlin.sdk.ListToolsRequest
|
||||
import io.modelcontextprotocol.kotlin.sdk.ListToolsResult
|
||||
import io.modelcontextprotocol.kotlin.sdk.LoggingLevel
|
||||
import io.modelcontextprotocol.kotlin.sdk.LoggingMessageNotification
|
||||
import io.modelcontextprotocol.kotlin.sdk.Method
|
||||
import io.modelcontextprotocol.kotlin.sdk.Role
|
||||
import io.modelcontextprotocol.kotlin.sdk.Root
|
||||
import io.modelcontextprotocol.kotlin.sdk.RootsListChangedNotification
|
||||
import io.modelcontextprotocol.kotlin.sdk.SUPPORTED_PROTOCOL_VERSIONS
|
||||
import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities
|
||||
import io.modelcontextprotocol.kotlin.sdk.TextContent
|
||||
import io.modelcontextprotocol.kotlin.sdk.Tool
|
||||
import io.modelcontextprotocol.kotlin.sdk.server.Server
|
||||
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
|
||||
import io.modelcontextprotocol.kotlin.sdk.shared.AbstractTransport
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.TimeoutCancellationException
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.joinAll
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.put
|
||||
import kotlinx.serialization.json.putJsonObject
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertInstanceOf
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
class ClientTest {
|
||||
@Test
|
||||
fun `should initialize with matching protocol version`() = runTest {
|
||||
var initialised = false
|
||||
val clientTransport = object : AbstractTransport() {
|
||||
override suspend fun start() {}
|
||||
|
||||
override suspend fun send(message: JSONRPCMessage) {
|
||||
if (message !is JSONRPCRequest) return
|
||||
initialised = true
|
||||
val result = InitializeResult(
|
||||
protocolVersion = LATEST_PROTOCOL_VERSION,
|
||||
capabilities = ServerCapabilities(),
|
||||
serverInfo = Implementation(
|
||||
name = "test",
|
||||
version = "1.0"
|
||||
)
|
||||
)
|
||||
|
||||
val response = JSONRPCResponse(
|
||||
id = message.id,
|
||||
result = result
|
||||
)
|
||||
|
||||
_onMessage.invoke(response)
|
||||
}
|
||||
|
||||
override suspend fun close() {
|
||||
}
|
||||
}
|
||||
|
||||
val client = Client(
|
||||
clientInfo = Implementation(
|
||||
name = "test client",
|
||||
version = "1.0"
|
||||
),
|
||||
options = ClientOptions(
|
||||
capabilities = ClientCapabilities(
|
||||
sampling = EmptyJsonObject
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
client.connect(clientTransport)
|
||||
assertTrue(initialised)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should initialize with supported older protocol version`() = runTest {
|
||||
val OLD_VERSION = SUPPORTED_PROTOCOL_VERSIONS[1]
|
||||
val clientTransport = object : AbstractTransport() {
|
||||
override suspend fun start() {}
|
||||
|
||||
override suspend fun send(message: JSONRPCMessage) {
|
||||
if (message !is JSONRPCRequest) return
|
||||
check(message.method == Method.Defined.Initialize.value)
|
||||
|
||||
val result = InitializeResult(
|
||||
protocolVersion = OLD_VERSION,
|
||||
capabilities = ServerCapabilities(),
|
||||
serverInfo = Implementation(
|
||||
name = "test",
|
||||
version = "1.0"
|
||||
)
|
||||
)
|
||||
|
||||
val response = JSONRPCResponse(
|
||||
id = message.id,
|
||||
result = result
|
||||
)
|
||||
_onMessage.invoke(response)
|
||||
}
|
||||
|
||||
override suspend fun close() {
|
||||
}
|
||||
}
|
||||
|
||||
val client = Client(
|
||||
clientInfo = Implementation(
|
||||
name = "test client",
|
||||
version = "1.0"
|
||||
),
|
||||
options = ClientOptions(
|
||||
capabilities = ClientCapabilities(
|
||||
sampling = EmptyJsonObject
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
client.connect(clientTransport)
|
||||
assertEquals(
|
||||
Implementation("test", "1.0"),
|
||||
client.serverVersion
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should reject unsupported protocol version`() = runTest {
|
||||
var closed = false
|
||||
val clientTransport = object : AbstractTransport() {
|
||||
override suspend fun start() {}
|
||||
|
||||
override suspend fun send(message: JSONRPCMessage) {
|
||||
if (message !is JSONRPCRequest) return
|
||||
check(message.method == Method.Defined.Initialize.value)
|
||||
|
||||
val result = InitializeResult(
|
||||
protocolVersion = "invalid-version",
|
||||
capabilities = ServerCapabilities(),
|
||||
serverInfo = Implementation(
|
||||
name = "test",
|
||||
version = "1.0"
|
||||
)
|
||||
)
|
||||
|
||||
val response = JSONRPCResponse(
|
||||
id = message.id,
|
||||
result = result
|
||||
)
|
||||
|
||||
_onMessage.invoke(response)
|
||||
}
|
||||
|
||||
override suspend fun close() {
|
||||
closed = true
|
||||
}
|
||||
}
|
||||
|
||||
val client = Client(
|
||||
clientInfo = Implementation(
|
||||
name = "test client",
|
||||
version = "1.0"
|
||||
),
|
||||
options = ClientOptions()
|
||||
)
|
||||
|
||||
assertFailsWith<IllegalStateException>("Server's protocol version is not supported: invalid-version") {
|
||||
client.connect(clientTransport)
|
||||
}
|
||||
|
||||
assertTrue(closed)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should reject due to non cancellation exception`() = runTest {
|
||||
var closed = false
|
||||
val clientTransport = object : AbstractTransport() {
|
||||
override suspend fun start() {}
|
||||
|
||||
override suspend fun send(message: JSONRPCMessage) {
|
||||
if (message !is JSONRPCRequest) return
|
||||
check(message.method == Method.Defined.Initialize.value)
|
||||
|
||||
val result = InitializeResult(
|
||||
protocolVersion = LATEST_PROTOCOL_VERSION,
|
||||
capabilities = ServerCapabilities(),
|
||||
serverInfo = Implementation(
|
||||
name = "test",
|
||||
version = "1.0"
|
||||
)
|
||||
)
|
||||
|
||||
val response = JSONRPCResponse(
|
||||
id = message.id,
|
||||
result = result
|
||||
)
|
||||
|
||||
_onMessage.invoke(response)
|
||||
}
|
||||
|
||||
override suspend fun close() {
|
||||
closed = true
|
||||
}
|
||||
}
|
||||
|
||||
val mockClient = spyk(
|
||||
Client(
|
||||
clientInfo = Implementation(
|
||||
name = "test client",
|
||||
version = "1.0"
|
||||
),
|
||||
options = ClientOptions()
|
||||
)
|
||||
)
|
||||
|
||||
coEvery{
|
||||
mockClient.request<InitializeResult>(any())
|
||||
} throws IllegalStateException("Test error")
|
||||
|
||||
val exception = assertFailsWith<IllegalStateException> {
|
||||
mockClient.connect(clientTransport)
|
||||
}
|
||||
|
||||
assertEquals("Error connecting to transport: Test error", exception.message)
|
||||
|
||||
assertTrue(closed)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should respect server capabilities`() = runTest {
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
resources = ServerCapabilities.Resources(null, null),
|
||||
tools = ServerCapabilities.Tools(null)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
server.setRequestHandler<InitializeRequest>(Method.Defined.Initialize) { request, _ ->
|
||||
InitializeResult(
|
||||
protocolVersion = LATEST_PROTOCOL_VERSION,
|
||||
capabilities = ServerCapabilities(
|
||||
resources = ServerCapabilities.Resources(null, null),
|
||||
tools = ServerCapabilities.Tools(null)
|
||||
),
|
||||
serverInfo = Implementation(name = "test", version = "1.0")
|
||||
)
|
||||
}
|
||||
|
||||
server.setRequestHandler<ListResourcesRequest>(Method.Defined.ResourcesList) { request, _ ->
|
||||
ListResourcesResult(resources = emptyList(), nextCursor = null)
|
||||
}
|
||||
|
||||
server.setRequestHandler<ListToolsRequest>(Method.Defined.ToolsList) { request, _ ->
|
||||
ListToolsResult(tools = emptyList(), nextCursor = null)
|
||||
}
|
||||
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
options = ClientOptions(
|
||||
capabilities = ClientCapabilities(sampling = EmptyJsonObject),
|
||||
)
|
||||
)
|
||||
|
||||
listOf(
|
||||
launch {
|
||||
client.connect(clientTransport)
|
||||
},
|
||||
launch {
|
||||
server.connect(serverTransport)
|
||||
}
|
||||
).joinAll()
|
||||
|
||||
// Server supports resources and tools, but not prompts
|
||||
val caps = client.serverCapabilities
|
||||
assertEquals(ServerCapabilities.Resources(null, null), caps?.resources)
|
||||
assertEquals(ServerCapabilities.Tools(null), caps?.tools)
|
||||
assertTrue(caps?.prompts == null) // or check that prompts are absent
|
||||
|
||||
// These should not throw
|
||||
client.listResources()
|
||||
client.listTools()
|
||||
|
||||
// This should fail because prompts are not supported
|
||||
val ex = assertFailsWith<IllegalStateException> {
|
||||
client.listPrompts()
|
||||
}
|
||||
assertTrue(ex.message?.contains("Server does not support prompts") == true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should respect client notification capabilities`() = runTest {
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
ServerOptions(capabilities = ServerCapabilities())
|
||||
)
|
||||
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
options = ClientOptions(
|
||||
capabilities = ClientCapabilities(
|
||||
roots = ClientCapabilities.Roots(listChanged = true)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
|
||||
listOf(
|
||||
launch {
|
||||
client.connect(clientTransport)
|
||||
println("Client connected")
|
||||
},
|
||||
launch {
|
||||
server.connect(serverTransport)
|
||||
println("Server connected")
|
||||
}
|
||||
).joinAll()
|
||||
|
||||
// This should not throw because the client supports roots.listChanged
|
||||
client.sendRootsListChanged()
|
||||
|
||||
// Create a new client without the roots.listChanged capability
|
||||
val clientWithoutCapability = Client(
|
||||
clientInfo = Implementation(name = "test client without capability", version = "1.0"),
|
||||
options = ClientOptions(
|
||||
capabilities = ClientCapabilities(),
|
||||
// enforceStrictCapabilities = true // TODO()
|
||||
)
|
||||
)
|
||||
|
||||
clientWithoutCapability.connect(clientTransport)
|
||||
// Using the same transport pair might not be realistic - in a real scenario you'd create another pair.
|
||||
// Adjust if necessary.
|
||||
|
||||
// This should fail
|
||||
val ex = assertFailsWith<IllegalStateException> {
|
||||
clientWithoutCapability.sendRootsListChanged()
|
||||
}
|
||||
assertTrue(ex.message?.startsWith("Client does not support") == true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should respect server notification capabilities`() = runTest {
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
logging = EmptyJsonObject,
|
||||
resources = ServerCapabilities.Resources(listChanged = true, subscribe = null)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
options = ClientOptions(
|
||||
capabilities = ClientCapabilities()
|
||||
)
|
||||
)
|
||||
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
|
||||
listOf(
|
||||
launch {
|
||||
client.connect(clientTransport)
|
||||
println("Client connected")
|
||||
},
|
||||
launch {
|
||||
server.connect(serverTransport)
|
||||
println("Server connected")
|
||||
}
|
||||
).joinAll()
|
||||
|
||||
// These should not throw
|
||||
val jsonObject = buildJsonObject {
|
||||
put("name", "John")
|
||||
put("age", 30)
|
||||
put("isStudent", false)
|
||||
}
|
||||
server.sendLoggingMessage(
|
||||
LoggingMessageNotification(
|
||||
params = LoggingMessageNotification.Params(
|
||||
level = LoggingLevel.info,
|
||||
data = jsonObject
|
||||
)
|
||||
)
|
||||
)
|
||||
server.sendResourceListChanged()
|
||||
|
||||
// This should fail because the server doesn't have the tools capability
|
||||
val ex = assertFailsWith<IllegalStateException> {
|
||||
server.sendToolListChanged()
|
||||
}
|
||||
assertTrue(ex.message?.contains("Server does not support notifying of tool list changes") == true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle client cancelling a request`() = runTest {
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
ServerOptions(
|
||||
capabilities = ServerCapabilities(resources = ServerCapabilities.Resources(listChanged = null, subscribe = null))
|
||||
)
|
||||
)
|
||||
|
||||
val def = CompletableDeferred<Unit>()
|
||||
val defTimeOut = CompletableDeferred<Unit>()
|
||||
server.setRequestHandler<ListResourcesRequest>(Method.Defined.ResourcesList) { _, extra ->
|
||||
// Simulate delay
|
||||
def.complete(Unit)
|
||||
try {
|
||||
delay(1000)
|
||||
} catch (e: CancellationException) {
|
||||
defTimeOut.complete(Unit)
|
||||
throw e
|
||||
}
|
||||
fail("Shouldn't have been called")
|
||||
ListResourcesResult(resources = emptyList())
|
||||
}
|
||||
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
options = ClientOptions(capabilities = ClientCapabilities())
|
||||
)
|
||||
|
||||
listOf(
|
||||
launch {
|
||||
client.connect(clientTransport)
|
||||
println("Client connected")
|
||||
},
|
||||
launch {
|
||||
server.connect(serverTransport)
|
||||
println("Server connected")
|
||||
}
|
||||
).joinAll()
|
||||
|
||||
val defCancel = CompletableDeferred<Unit>()
|
||||
val job = launch {
|
||||
try {
|
||||
client.listResources()
|
||||
} catch (e: CancellationException) {
|
||||
defCancel.complete(Unit)
|
||||
assertEquals("Cancelled by test", e.message)
|
||||
}
|
||||
}
|
||||
def.await()
|
||||
runCatching { job.cancel("Cancelled by test") }
|
||||
defCancel.await()
|
||||
defTimeOut.await()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle request timeout`() = runTest {
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
ServerOptions(
|
||||
capabilities = ServerCapabilities(resources = ServerCapabilities.Resources(listChanged = null, subscribe = null))
|
||||
)
|
||||
)
|
||||
|
||||
server.setRequestHandler<ListResourcesRequest>(Method.Defined.ResourcesList) { _, extra ->
|
||||
// Simulate a delayed response
|
||||
// Wait ~100ms unless canceled
|
||||
try {
|
||||
withTimeout(100L) {
|
||||
// Just delay here, if timeout is 0 on the client side, this won't return in time
|
||||
delay(100)
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
// If aborted, just rethrow or return early
|
||||
}
|
||||
ListResourcesResult(resources = emptyList())
|
||||
}
|
||||
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
options = ClientOptions(capabilities = ClientCapabilities())
|
||||
)
|
||||
|
||||
listOf(
|
||||
launch {
|
||||
client.connect(clientTransport)
|
||||
println("Client connected")
|
||||
},
|
||||
launch {
|
||||
server.connect(serverTransport)
|
||||
println("Server connected")
|
||||
}
|
||||
).joinAll()
|
||||
|
||||
// Request with 1 msec timeout should fail immediately
|
||||
val ex = assertFailsWith<Exception> {
|
||||
withTimeout(1) {
|
||||
client.listResources()
|
||||
}
|
||||
}
|
||||
assertTrue(ex is TimeoutCancellationException)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should only allow setRequestHandler for declared capabilities`() = runTest {
|
||||
val client = Client(
|
||||
clientInfo = Implementation(
|
||||
name = "test client",
|
||||
version = "1.0"
|
||||
),
|
||||
options = ClientOptions(
|
||||
capabilities = ClientCapabilities(
|
||||
sampling = EmptyJsonObject
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
client.setRequestHandler<CreateMessageRequest>(Method.Defined.SamplingCreateMessage) { request, _ ->
|
||||
CreateMessageResult(
|
||||
model = "test-model",
|
||||
role = Role.assistant,
|
||||
content = TextContent(
|
||||
text = "Test response"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
assertFailsWith<IllegalStateException>("Client does not support roots capability (required for RootsList)") {
|
||||
client.setRequestHandler<ListRootsRequest>(Method.Defined.RootsList) { _, _ -> null }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `JSONRPCRequest with ToolsList method and default params returns list of tools`() = runTest {
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
tools = ServerCapabilities.Tools(null)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
server.setRequestHandler<InitializeRequest>(Method.Defined.Initialize) { request, _ ->
|
||||
InitializeResult(
|
||||
protocolVersion = LATEST_PROTOCOL_VERSION,
|
||||
capabilities = ServerCapabilities(
|
||||
resources = ServerCapabilities.Resources(null, null),
|
||||
tools = ServerCapabilities.Tools(null)
|
||||
),
|
||||
serverInfo = Implementation(name = "test", version = "1.0")
|
||||
)
|
||||
}
|
||||
val serverListToolsResult = ListToolsResult(
|
||||
tools = listOf(
|
||||
Tool(
|
||||
name = "testTool",
|
||||
title = "testTool title",
|
||||
description = "testTool description",
|
||||
annotations = null,
|
||||
inputSchema = Tool.Input(),
|
||||
outputSchema = null
|
||||
)
|
||||
), nextCursor = null
|
||||
)
|
||||
|
||||
server.setRequestHandler<ListToolsRequest>(Method.Defined.ToolsList) { request, _ ->
|
||||
serverListToolsResult
|
||||
}
|
||||
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
options = ClientOptions(
|
||||
capabilities = ClientCapabilities(sampling = EmptyJsonObject),
|
||||
)
|
||||
)
|
||||
|
||||
var receivedMessage: JSONRPCMessage? = null
|
||||
clientTransport.onMessage { msg ->
|
||||
receivedMessage = msg
|
||||
}
|
||||
|
||||
listOf(
|
||||
launch {
|
||||
client.connect(clientTransport)
|
||||
},
|
||||
launch {
|
||||
server.connect(serverTransport)
|
||||
}
|
||||
).joinAll()
|
||||
|
||||
val serverCapabilities = client.serverCapabilities
|
||||
assertEquals(ServerCapabilities.Tools(null), serverCapabilities?.tools)
|
||||
|
||||
val request = JSONRPCRequest(
|
||||
method = Method.Defined.ToolsList.value
|
||||
)
|
||||
clientTransport.send(request)
|
||||
|
||||
assertInstanceOf<JSONRPCResponse>(receivedMessage)
|
||||
val receivedAsResponse = receivedMessage as JSONRPCResponse
|
||||
assertEquals(request.id, receivedAsResponse.id)
|
||||
assertEquals(request.jsonrpc, receivedAsResponse.jsonrpc)
|
||||
assertEquals(serverListToolsResult, receivedAsResponse.result)
|
||||
assertEquals(null, receivedAsResponse.error)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `listRoots returns list of roots`() = runTest {
|
||||
val client = Client(
|
||||
Implementation(name = "test client", version = "1.0"),
|
||||
ClientOptions(
|
||||
capabilities = ClientCapabilities(
|
||||
roots = ClientCapabilities.Roots(null)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val clientRoots = listOf(
|
||||
Root(uri = "file:///test-root", name = "testRoot")
|
||||
)
|
||||
|
||||
client.addRoots(clientRoots)
|
||||
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
|
||||
val server = Server(
|
||||
serverInfo = Implementation(name = "test server", version = "1.0"),
|
||||
options = ServerOptions(
|
||||
capabilities = ServerCapabilities()
|
||||
)
|
||||
)
|
||||
|
||||
listOf(
|
||||
launch { client.connect(clientTransport) },
|
||||
launch { server.connect(serverTransport) }
|
||||
).joinAll()
|
||||
|
||||
val clientCapabilities = server.clientCapabilities
|
||||
assertEquals(ClientCapabilities.Roots(null), clientCapabilities?.roots)
|
||||
|
||||
val listRootsResult = server.listRoots()
|
||||
|
||||
assertEquals(listRootsResult.roots, clientRoots)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `addRoot should throw when roots capability is not supported`() = runTest {
|
||||
val client = Client(
|
||||
Implementation(name = "test client", version = "1.0"),
|
||||
ClientOptions(
|
||||
capabilities = ClientCapabilities()
|
||||
)
|
||||
)
|
||||
|
||||
// Verify that adding a root throws an exception
|
||||
val exception = assertThrows<IllegalStateException> {
|
||||
client.addRoot(uri = "file:///test-root1", name = "testRoot1")
|
||||
}
|
||||
assertEquals("Client does not support roots capability.", exception.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeRoot should throw when roots capability is not supported`() = runTest {
|
||||
val client = Client(
|
||||
Implementation(name = "test client", version = "1.0"),
|
||||
ClientOptions(
|
||||
capabilities = ClientCapabilities()
|
||||
)
|
||||
)
|
||||
|
||||
// Verify that removing a root throws an exception
|
||||
val exception = assertThrows<IllegalStateException> {
|
||||
client.removeRoot(uri = "file:///test-root1")
|
||||
}
|
||||
assertEquals("Client does not support roots capability.", exception.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeRoot should remove a root`() = runTest {
|
||||
val client = Client(
|
||||
Implementation(name = "test client", version = "1.0"),
|
||||
ClientOptions(
|
||||
capabilities = ClientCapabilities(
|
||||
roots = ClientCapabilities.Roots(null)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Add some roots
|
||||
client.addRoots(
|
||||
listOf(
|
||||
Root(uri = "file:///test-root1", name = "testRoot1"),
|
||||
Root(uri = "file:///test-root2", name = "testRoot2"),
|
||||
)
|
||||
)
|
||||
|
||||
// Remove a root
|
||||
val result = client.removeRoot("file:///test-root1")
|
||||
|
||||
// Verify the root was removed
|
||||
assertTrue(result, "Root should be removed successfully")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeRoots should remove multiple roots`() = runTest {
|
||||
val client = Client(
|
||||
Implementation(name = "test client", version = "1.0"),
|
||||
ClientOptions(
|
||||
capabilities = ClientCapabilities(
|
||||
roots = ClientCapabilities.Roots(null)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Add some roots
|
||||
client.addRoots(
|
||||
listOf(
|
||||
Root(uri = "file:///test-root1", name = "testRoot1"),
|
||||
Root(uri = "file:///test-root2", name = "testRoot2"),
|
||||
)
|
||||
)
|
||||
|
||||
// Remove multiple roots
|
||||
val result = client.removeRoots(
|
||||
listOf("file:///test-root1", "file:///test-root2")
|
||||
)
|
||||
|
||||
// Verify the root was removed
|
||||
assertEquals(2, result, "Both roots should be removed")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `sendRootsListChanged should notify server`() = runTest {
|
||||
val client = Client(
|
||||
Implementation(name = "test client", version = "1.0"),
|
||||
ClientOptions(
|
||||
capabilities = ClientCapabilities(
|
||||
roots = ClientCapabilities.Roots(listChanged = true)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
|
||||
val server = Server(
|
||||
serverInfo = Implementation(name = "test server", version = "1.0"),
|
||||
options = ServerOptions(
|
||||
capabilities = ServerCapabilities()
|
||||
)
|
||||
)
|
||||
|
||||
// Track notifications
|
||||
var rootListChangedNotificationReceived = false
|
||||
server.setNotificationHandler<RootsListChangedNotification>(Method.Defined.NotificationsRootsListChanged) {
|
||||
rootListChangedNotificationReceived = true
|
||||
CompletableDeferred(Unit)
|
||||
}
|
||||
|
||||
listOf(
|
||||
launch { client.connect(clientTransport) },
|
||||
launch { server.connect(serverTransport) }
|
||||
).joinAll()
|
||||
|
||||
client.sendRootsListChanged()
|
||||
|
||||
assertTrue(
|
||||
rootListChangedNotificationReceived,
|
||||
"Notification should be sent when sendRootsListChanged is called"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should reject server elicitation when elicitation capability is not supported`() = runTest {
|
||||
val client = Client(
|
||||
Implementation(name = "test client", version = "1.0"),
|
||||
ClientOptions(
|
||||
capabilities = ClientCapabilities()
|
||||
)
|
||||
)
|
||||
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
|
||||
val server = Server(
|
||||
serverInfo = Implementation(name = "test server", version = "1.0"),
|
||||
options = ServerOptions(
|
||||
capabilities = ServerCapabilities()
|
||||
)
|
||||
)
|
||||
|
||||
listOf(
|
||||
launch { client.connect(clientTransport) },
|
||||
launch { server.connect(serverTransport) }
|
||||
).joinAll()
|
||||
|
||||
// Verify that creating an elicitation throws an exception
|
||||
val exception = assertThrows<IllegalStateException> {
|
||||
server.createElicitation(
|
||||
message = "Please provide your GitHub username",
|
||||
requestedSchema = CreateElicitationRequest.RequestedSchema(
|
||||
properties = buildJsonObject {
|
||||
putJsonObject("name") {
|
||||
put("type", "string")
|
||||
}
|
||||
},
|
||||
required = listOf("name")
|
||||
)
|
||||
)
|
||||
}
|
||||
assertEquals(
|
||||
"Client does not support elicitation (required for elicitation/create)",
|
||||
exception.message
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should handle server elicitation`() = runTest {
|
||||
val client = Client(
|
||||
Implementation(name = "test client", version = "1.0"),
|
||||
ClientOptions(
|
||||
capabilities = ClientCapabilities(
|
||||
elicitation = EmptyJsonObject,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val elicitationMessage = "Please provide your GitHub username"
|
||||
val requestedSchema = CreateElicitationRequest.RequestedSchema(
|
||||
properties = buildJsonObject {
|
||||
putJsonObject("name") {
|
||||
put("type", "string")
|
||||
}
|
||||
},
|
||||
required = listOf("name")
|
||||
)
|
||||
|
||||
val elicitationResultAction = CreateElicitationResult.Action.accept
|
||||
val elicitationResultContent = buildJsonObject {
|
||||
put("name", "octocat")
|
||||
}
|
||||
|
||||
client.setElicitationHandler { request ->
|
||||
assertEquals(elicitationMessage, request.message)
|
||||
assertEquals(requestedSchema, request.requestedSchema)
|
||||
|
||||
CreateElicitationResult(
|
||||
action = elicitationResultAction,
|
||||
content = elicitationResultContent
|
||||
)
|
||||
}
|
||||
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
|
||||
val server = Server(
|
||||
serverInfo = Implementation(name = "test server", version = "1.0"),
|
||||
options = ServerOptions(
|
||||
capabilities = ServerCapabilities()
|
||||
)
|
||||
)
|
||||
|
||||
listOf(
|
||||
launch { client.connect(clientTransport) },
|
||||
launch { server.connect(serverTransport) }
|
||||
).joinAll()
|
||||
|
||||
val result = server.createElicitation(
|
||||
message = elicitationMessage,
|
||||
requestedSchema = requestedSchema
|
||||
)
|
||||
|
||||
assertEquals(elicitationResultAction, result.action)
|
||||
assertEquals(elicitationResultContent, result.content)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk.client
|
||||
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.io.asSink
|
||||
import kotlinx.io.asSource
|
||||
import kotlinx.io.buffered
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class StdioClientTransportTest : BaseTransportTest() {
|
||||
@Test
|
||||
fun `should start then close cleanly`() = runTest {
|
||||
// Run process "/usr/bin/tee"
|
||||
val processBuilder = ProcessBuilder("/usr/bin/tee")
|
||||
val process = processBuilder.start()
|
||||
|
||||
val input = process.inputStream.asSource().buffered()
|
||||
val output = process.outputStream.asSink().buffered()
|
||||
|
||||
val client = StdioClientTransport(
|
||||
input = input,
|
||||
output = output
|
||||
)
|
||||
|
||||
testClientOpenClose(client)
|
||||
|
||||
process.destroy()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should read messages`() = runTest {
|
||||
val processBuilder = ProcessBuilder("/usr/bin/tee")
|
||||
val process = processBuilder.start()
|
||||
|
||||
val input = process.inputStream.asSource().buffered()
|
||||
val output = process.outputStream.asSink().buffered()
|
||||
|
||||
val client = StdioClientTransport(
|
||||
input = input,
|
||||
output = output
|
||||
)
|
||||
|
||||
testClientRead(client)
|
||||
|
||||
process.waitFor()
|
||||
process.destroy()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,368 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk.client
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.engine.mock.MockEngine
|
||||
import io.ktor.client.engine.mock.MockRequestHandler
|
||||
import io.ktor.client.engine.mock.respond
|
||||
import io.ktor.client.plugins.sse.SSE
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpHeaders
|
||||
import io.ktor.http.HttpMethod
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.http.content.TextContent
|
||||
import io.ktor.http.headersOf
|
||||
import io.ktor.utils.io.ByteReadChannel
|
||||
import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage
|
||||
import io.modelcontextprotocol.kotlin.sdk.JSONRPCNotification
|
||||
import io.modelcontextprotocol.kotlin.sdk.JSONRPCRequest
|
||||
import io.modelcontextprotocol.kotlin.sdk.RequestId
|
||||
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import org.junit.jupiter.api.assertDoesNotThrow
|
||||
import kotlin.test.Ignore
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class StreamableHttpClientTransportTest {
|
||||
|
||||
private fun createTransport(handler: MockRequestHandler): StreamableHttpClientTransport {
|
||||
val mockEngine = MockEngine(handler)
|
||||
val httpClient = HttpClient(mockEngine) {
|
||||
install(SSE) {
|
||||
reconnectionTime = 1.seconds
|
||||
}
|
||||
}
|
||||
|
||||
return StreamableHttpClientTransport(httpClient, url = "http://localhost:8080/mcp")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSendJsonRpcMessage() = runTest {
|
||||
val message = JSONRPCRequest(
|
||||
id = RequestId.StringId("test-id"),
|
||||
method = "test",
|
||||
params = buildJsonObject { }
|
||||
)
|
||||
|
||||
val transport = createTransport { request ->
|
||||
assertEquals(HttpMethod.Post, request.method)
|
||||
assertEquals("http://localhost:8080/mcp", request.url.toString())
|
||||
assertEquals(ContentType.Application.Json, request.body.contentType)
|
||||
|
||||
val body = (request.body as TextContent).text
|
||||
val decodedMessage = McpJson.decodeFromString<JSONRPCMessage>(body)
|
||||
assertEquals(message, decodedMessage)
|
||||
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.Accepted
|
||||
)
|
||||
}
|
||||
|
||||
transport.start()
|
||||
transport.send(message)
|
||||
transport.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testStoreSessionId() = runTest {
|
||||
val initMessage = JSONRPCRequest(
|
||||
id = RequestId.StringId("test-id"),
|
||||
method = "initialize",
|
||||
params = buildJsonObject {
|
||||
put("clientInfo", buildJsonObject {
|
||||
put("name", JsonPrimitive("test-client"))
|
||||
put("version", JsonPrimitive("1.0"))
|
||||
})
|
||||
put("protocolVersion", JsonPrimitive("2025-06-18"))
|
||||
}
|
||||
)
|
||||
|
||||
val transport = createTransport { request ->
|
||||
when (val msg = McpJson.decodeFromString<JSONRPCMessage>((request.body as TextContent).text)) {
|
||||
is JSONRPCRequest if msg.method == "initialize" -> respond(
|
||||
content = "", status = HttpStatusCode.OK,
|
||||
headers = headersOf("mcp-session-id", "test-session-id")
|
||||
)
|
||||
|
||||
is JSONRPCNotification if msg.method == "test" -> {
|
||||
assertEquals("test-session-id", request.headers["mcp-session-id"])
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.Accepted
|
||||
)
|
||||
}
|
||||
|
||||
else -> error("Unexpected message: $msg")
|
||||
}
|
||||
}
|
||||
|
||||
transport.start()
|
||||
transport.send(initMessage)
|
||||
|
||||
assertEquals("test-session-id", transport.sessionId)
|
||||
|
||||
transport.send(JSONRPCNotification(method = "test"))
|
||||
|
||||
transport.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTerminateSession() = runTest {
|
||||
// transport.sessionId = "test-session-id"
|
||||
|
||||
val transport = createTransport { request ->
|
||||
assertEquals(HttpMethod.Delete, request.method)
|
||||
assertEquals("test-session-id", request.headers["mcp-session-id"])
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.OK
|
||||
)
|
||||
}
|
||||
|
||||
transport.start()
|
||||
transport.terminateSession()
|
||||
|
||||
assertNull(transport.sessionId)
|
||||
transport.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTerminateSessionHandle405() = runTest {
|
||||
// transport.sessionId = "test-session-id"
|
||||
|
||||
val transport = createTransport { request ->
|
||||
assertEquals(HttpMethod.Delete, request.method)
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.MethodNotAllowed
|
||||
)
|
||||
}
|
||||
|
||||
transport.start()
|
||||
// Should not throw for 405
|
||||
assertDoesNotThrow {
|
||||
transport.terminateSession()
|
||||
}
|
||||
|
||||
// Session ID should still be cleared
|
||||
assertNull(transport.sessionId)
|
||||
transport.close()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProtocolVersionHeader() = runTest {
|
||||
val transport = createTransport { request ->
|
||||
assertEquals("2025-06-18", request.headers["mcp-protocol-version"])
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.Accepted
|
||||
)
|
||||
}
|
||||
transport.protocolVersion = "2025-06-18"
|
||||
|
||||
transport.start()
|
||||
transport.send(JSONRPCNotification(method = "test"))
|
||||
transport.close()
|
||||
}
|
||||
|
||||
@Ignore("Engine doesn't support SSECapability: https://youtrack.jetbrains.com/issue/KTOR-8177/MockEngine-Add-SSE-support")
|
||||
@Test
|
||||
fun testNotificationSchemaE2E() = runTest {
|
||||
val receivedMessages = mutableListOf<JSONRPCMessage>()
|
||||
var sseStarted = false
|
||||
|
||||
val transport = createTransport { request ->
|
||||
when (request.method) {
|
||||
HttpMethod.Post if request.body.toString().contains("notifications/initialized") -> {
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.Accepted,
|
||||
headers = headersOf("mcp-session-id", "notification-test-session")
|
||||
)
|
||||
}
|
||||
|
||||
// Handle SSE connection
|
||||
HttpMethod.Get -> {
|
||||
sseStarted = true
|
||||
val sseContent = buildString {
|
||||
// Server sends various notifications
|
||||
appendLine("event: message")
|
||||
appendLine("id: 1")
|
||||
appendLine("""data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":"upload-123","progress":50,"total":100}}""")
|
||||
appendLine()
|
||||
|
||||
appendLine("event: message")
|
||||
appendLine("id: 2")
|
||||
appendLine("""data: {"jsonrpc":"2.0","method":"notifications/resources/list_changed"}""")
|
||||
appendLine()
|
||||
|
||||
appendLine("event: message")
|
||||
appendLine("id: 3")
|
||||
appendLine("""data: {"jsonrpc":"2.0","method":"notifications/tools/list_changed"}""")
|
||||
appendLine()
|
||||
}
|
||||
respond(
|
||||
content = ByteReadChannel(sseContent),
|
||||
status = HttpStatusCode.OK,
|
||||
headers = headersOf(
|
||||
HttpHeaders.ContentType, ContentType.Text.EventStream.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Handle regular notifications
|
||||
HttpMethod.Post -> {
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.Accepted
|
||||
)
|
||||
}
|
||||
|
||||
else -> respond("", HttpStatusCode.OK)
|
||||
}
|
||||
}
|
||||
|
||||
transport.onMessage { message ->
|
||||
receivedMessages.add(message)
|
||||
}
|
||||
|
||||
transport.start()
|
||||
|
||||
// Test 1: Send initialized notification to trigger SSE
|
||||
val initializedNotification = JSONRPCNotification(
|
||||
method = "notifications/initialized",
|
||||
params = buildJsonObject {
|
||||
put("protocolVersion", JsonPrimitive("1.0"))
|
||||
put("capabilities", buildJsonObject {
|
||||
put("tools", JsonPrimitive(true))
|
||||
put("resources", JsonPrimitive(true))
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
transport.send(initializedNotification)
|
||||
|
||||
// Verify SSE was triggered
|
||||
assertTrue(sseStarted, "SSE should start after initialized notification")
|
||||
|
||||
// Test 2: Verify received notifications
|
||||
assertEquals(3, receivedMessages.size)
|
||||
assertTrue(receivedMessages.all { it is JSONRPCNotification })
|
||||
|
||||
val notifications = receivedMessages.filterIsInstance<JSONRPCNotification>()
|
||||
|
||||
// Verify progress notification
|
||||
val progressNotif = notifications[0]
|
||||
assertEquals("notifications/progress", progressNotif.method)
|
||||
val progressParams = progressNotif.params as JsonObject
|
||||
assertEquals("upload-123", (progressParams["progressToken"] as JsonPrimitive).content)
|
||||
assertEquals(50, (progressParams["progress"] as JsonPrimitive).content.toInt())
|
||||
|
||||
// Verify list changed notifications
|
||||
assertEquals("notifications/resources/list_changed", notifications[1].method)
|
||||
assertEquals("notifications/tools/list_changed", notifications[2].method)
|
||||
|
||||
// Test 3: Send various client notifications
|
||||
val clientNotifications = listOf(
|
||||
JSONRPCNotification(
|
||||
method = "notifications/progress",
|
||||
params = buildJsonObject {
|
||||
put("progressToken", JsonPrimitive("download-456"))
|
||||
put("progress", JsonPrimitive(75))
|
||||
}
|
||||
),
|
||||
JSONRPCNotification(
|
||||
method = "notifications/cancelled",
|
||||
params = buildJsonObject {
|
||||
put("requestId", JsonPrimitive("req-789"))
|
||||
put("reason", JsonPrimitive("user_cancelled"))
|
||||
}
|
||||
),
|
||||
JSONRPCNotification(
|
||||
method = "notifications/message",
|
||||
params = buildJsonObject {
|
||||
put("level", JsonPrimitive("info"))
|
||||
put("message", JsonPrimitive("Operation completed"))
|
||||
put("data", buildJsonObject {
|
||||
put("duration", JsonPrimitive(1234))
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
// Send all client notifications
|
||||
clientNotifications.forEach { notification ->
|
||||
transport.send(notification)
|
||||
}
|
||||
|
||||
// Verify session ID is maintained
|
||||
assertEquals("notification-test-session", transport.sessionId)
|
||||
transport.close()
|
||||
}
|
||||
|
||||
@Ignore("Engine doesn't support SSECapability: https://youtrack.jetbrains.com/issue/KTOR-8177/MockEngine-Add-SSE-support")
|
||||
@Test
|
||||
fun testNotificationWithResumptionToken() = runTest {
|
||||
var resumptionTokenReceived: String? = null
|
||||
var lastEventIdSent: String? = null
|
||||
|
||||
val transport = createTransport { request ->
|
||||
// Capture Last-Event-ID header
|
||||
lastEventIdSent = request.headers["Last-Event-ID"]
|
||||
|
||||
when (request.method) {
|
||||
HttpMethod.Get -> {
|
||||
val sseContent = buildString {
|
||||
appendLine("event: message")
|
||||
appendLine("id: resume-100")
|
||||
appendLine("""data: {"jsonrpc":"2.0","method":"notifications/resumed","params":{"fromToken":"${lastEventIdSent}"}}""")
|
||||
appendLine()
|
||||
}
|
||||
respond(
|
||||
content = ByteReadChannel(sseContent),
|
||||
status = HttpStatusCode.OK,
|
||||
headers = headersOf(
|
||||
HttpHeaders.ContentType, ContentType.Text.EventStream.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
else -> respond("", HttpStatusCode.Accepted)
|
||||
}
|
||||
}
|
||||
|
||||
transport.start()
|
||||
|
||||
// Send notification with resumption token
|
||||
transport.send(
|
||||
message = JSONRPCNotification(
|
||||
method = "notifications/test",
|
||||
params = buildJsonObject {
|
||||
put("data", JsonPrimitive("test-data"))
|
||||
}
|
||||
),
|
||||
resumptionToken = "previous-token-99",
|
||||
onResumptionToken = { token ->
|
||||
resumptionTokenReceived = token
|
||||
}
|
||||
)
|
||||
|
||||
// Wait for response
|
||||
delay(1.seconds)
|
||||
|
||||
// Verify resumption token was sent in header
|
||||
assertEquals("previous-token-99", lastEventIdSent)
|
||||
|
||||
// Verify new resumption token was received
|
||||
assertEquals("resume-100", resumptionTokenReceived)
|
||||
transport.close()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,469 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk.server
|
||||
|
||||
import io.modelcontextprotocol.kotlin.sdk.CallToolResult
|
||||
import io.modelcontextprotocol.kotlin.sdk.GetPromptResult
|
||||
import io.modelcontextprotocol.kotlin.sdk.Implementation
|
||||
import io.modelcontextprotocol.kotlin.sdk.InMemoryTransport
|
||||
import io.modelcontextprotocol.kotlin.sdk.Method
|
||||
import io.modelcontextprotocol.kotlin.sdk.Prompt
|
||||
import io.modelcontextprotocol.kotlin.sdk.PromptListChangedNotification
|
||||
import io.modelcontextprotocol.kotlin.sdk.ReadResourceResult
|
||||
import io.modelcontextprotocol.kotlin.sdk.ResourceListChangedNotification
|
||||
import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities
|
||||
import io.modelcontextprotocol.kotlin.sdk.TextContent
|
||||
import io.modelcontextprotocol.kotlin.sdk.TextResourceContents
|
||||
import io.modelcontextprotocol.kotlin.sdk.Tool
|
||||
import io.modelcontextprotocol.kotlin.sdk.ToolListChangedNotification
|
||||
import io.modelcontextprotocol.kotlin.sdk.client.Client
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ServerTest {
|
||||
|
||||
@Test
|
||||
fun `removeTool should remove a tool`() = runTest {
|
||||
// Create server with tools capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
tools = ServerCapabilities.Tools(null)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Add a tool
|
||||
server.addTool("test-tool", "Test Tool", Tool.Input()) { request ->
|
||||
CallToolResult(listOf(TextContent("Test result")))
|
||||
}
|
||||
|
||||
// Setup client
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
)
|
||||
|
||||
// Connect client and server
|
||||
launch { client.connect(clientTransport) }
|
||||
launch { server.connect(serverTransport) }
|
||||
|
||||
// Remove the tool
|
||||
val result = server.removeTool("test-tool")
|
||||
|
||||
// Verify the tool was removed
|
||||
assertTrue(result, "Tool should be removed successfully")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeTool should return false when tool does not exist`() = runTest {
|
||||
// Create server with tools capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
tools = ServerCapabilities.Tools(null)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Setup client
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
)
|
||||
|
||||
// Track notifications
|
||||
var toolListChangedNotificationReceived = false
|
||||
client.setNotificationHandler<ToolListChangedNotification>(Method.Defined.NotificationsToolsListChanged) {
|
||||
toolListChangedNotificationReceived = true
|
||||
CompletableDeferred(Unit)
|
||||
}
|
||||
|
||||
// Connect client and server
|
||||
launch { client.connect(clientTransport) }
|
||||
launch { server.connect(serverTransport) }
|
||||
|
||||
// Try to remove a non-existent tool
|
||||
val result = server.removeTool("non-existent-tool")
|
||||
|
||||
// Verify the result
|
||||
assertFalse(result, "Removing non-existent tool should return false")
|
||||
assertFalse(toolListChangedNotificationReceived, "No notification should be sent when tool doesn't exist")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeTool should throw when tools capability is not supported`() = runTest {
|
||||
// Create server without tools capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities()
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Verify that removing a tool throws an exception
|
||||
val exception = assertThrows<IllegalStateException> {
|
||||
server.removeTool("test-tool")
|
||||
}
|
||||
assertEquals("Server does not support tools capability.", exception.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeTools should remove multiple tools`() = runTest {
|
||||
// Create server with tools capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
tools = ServerCapabilities.Tools(null)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Add tools
|
||||
server.addTool("test-tool-1", "Test Tool 1") { request ->
|
||||
CallToolResult(listOf(TextContent("Test result 1")))
|
||||
}
|
||||
server.addTool("test-tool-2", "Test Tool 2") { request ->
|
||||
CallToolResult(listOf(TextContent("Test result 2")))
|
||||
}
|
||||
|
||||
// Setup client
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
)
|
||||
|
||||
// Connect client and server
|
||||
launch { client.connect(clientTransport) }
|
||||
launch { server.connect(serverTransport) }
|
||||
|
||||
// Remove the tools
|
||||
val result = server.removeTools(listOf("test-tool-1", "test-tool-2"))
|
||||
|
||||
// Verify the tools were removed
|
||||
assertEquals(2, result, "Both tools should be removed")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removePrompt should remove a prompt`() = runTest {
|
||||
// Create server with prompts capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
prompts = ServerCapabilities.Prompts(listChanged = false)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Add a prompt
|
||||
val testPrompt = Prompt("test-prompt", "Test Prompt", null)
|
||||
server.addPrompt(testPrompt) { request ->
|
||||
GetPromptResult(
|
||||
description = "Test prompt description",
|
||||
messages = listOf()
|
||||
)
|
||||
}
|
||||
|
||||
// Setup client
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
)
|
||||
|
||||
// Connect client and server
|
||||
launch { client.connect(clientTransport) }
|
||||
launch { server.connect(serverTransport) }
|
||||
|
||||
// Remove the prompt
|
||||
val result = server.removePrompt(testPrompt.name)
|
||||
|
||||
// Verify the prompt was removed
|
||||
assertTrue(result, "Prompt should be removed successfully")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removePrompts should remove multiple prompts and send notification`() = runTest {
|
||||
// Create server with prompts capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
prompts = ServerCapabilities.Prompts(listChanged = false)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Add prompts
|
||||
val testPrompt1 = Prompt("test-prompt-1", "Test Prompt 1", null)
|
||||
val testPrompt2 = Prompt("test-prompt-2", "Test Prompt 2", null)
|
||||
server.addPrompt(testPrompt1) { request ->
|
||||
GetPromptResult(
|
||||
description = "Test prompt description 1",
|
||||
messages = listOf()
|
||||
)
|
||||
}
|
||||
server.addPrompt(testPrompt2) { request ->
|
||||
GetPromptResult(
|
||||
description = "Test prompt description 2",
|
||||
messages = listOf()
|
||||
)
|
||||
}
|
||||
|
||||
// Setup client
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
)
|
||||
|
||||
// Connect client and server
|
||||
launch { client.connect(clientTransport) }
|
||||
launch { server.connect(serverTransport) }
|
||||
|
||||
// Remove the prompts
|
||||
val result = server.removePrompts(listOf(testPrompt1.name, testPrompt2.name))
|
||||
|
||||
// Verify the prompts were removed
|
||||
assertEquals(2, result, "Both prompts should be removed")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeResource should remove a resource and send notification`() = runTest {
|
||||
// Create server with resources capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
resources = ServerCapabilities.Resources(null, null)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Add a resource
|
||||
val testResourceUri = "test://resource"
|
||||
server.addResource(
|
||||
uri = testResourceUri,
|
||||
name = "Test Resource",
|
||||
description = "A test resource",
|
||||
mimeType = "text/plain"
|
||||
) { request ->
|
||||
ReadResourceResult(
|
||||
contents = listOf(
|
||||
TextResourceContents(
|
||||
text = "Test resource content",
|
||||
uri = testResourceUri,
|
||||
mimeType = "text/plain",
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Setup client
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
)
|
||||
|
||||
// Connect client and server
|
||||
launch { client.connect(clientTransport) }
|
||||
launch { server.connect(serverTransport) }
|
||||
|
||||
// Remove the resource
|
||||
val result = server.removeResource(testResourceUri)
|
||||
|
||||
// Verify the resource was removed
|
||||
assertTrue(result, "Resource should be removed successfully")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeResources should remove multiple resources and send notification`() = runTest {
|
||||
// Create server with resources capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
resources = ServerCapabilities.Resources(null, null)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Add resources
|
||||
val testResourceUri1 = "test://resource1"
|
||||
val testResourceUri2 = "test://resource2"
|
||||
server.addResource(
|
||||
uri = testResourceUri1,
|
||||
name = "Test Resource 1",
|
||||
description = "A test resource 1",
|
||||
mimeType = "text/plain"
|
||||
) { request ->
|
||||
ReadResourceResult(
|
||||
contents = listOf(
|
||||
TextResourceContents(
|
||||
text = "Test resource content 1",
|
||||
uri = testResourceUri1,
|
||||
mimeType = "text/plain",
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
server.addResource(
|
||||
uri = testResourceUri2,
|
||||
name = "Test Resource 2",
|
||||
description = "A test resource 2",
|
||||
mimeType = "text/plain"
|
||||
) { request ->
|
||||
ReadResourceResult(
|
||||
contents = listOf(
|
||||
TextResourceContents(
|
||||
text = "Test resource content 2",
|
||||
uri = testResourceUri2,
|
||||
mimeType = "text/plain",
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Setup client
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
)
|
||||
|
||||
// Connect client and server
|
||||
launch { client.connect(clientTransport) }
|
||||
launch { server.connect(serverTransport) }
|
||||
|
||||
// Remove the resources
|
||||
val result = server.removeResources(listOf(testResourceUri1, testResourceUri2))
|
||||
|
||||
// Verify the resources were removed
|
||||
assertEquals(2, result, "Both resources should be removed")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removePrompt should return false when prompt does not exist`() = runTest {
|
||||
// Create server with prompts capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
prompts = ServerCapabilities.Prompts(listChanged = false)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Setup client
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
)
|
||||
|
||||
// Track notifications
|
||||
var promptListChangedNotificationReceived = false
|
||||
client.setNotificationHandler<PromptListChangedNotification>(Method.Defined.NotificationsPromptsListChanged) {
|
||||
promptListChangedNotificationReceived = true
|
||||
CompletableDeferred(Unit)
|
||||
}
|
||||
|
||||
// Connect client and server
|
||||
launch { client.connect(clientTransport) }
|
||||
launch { server.connect(serverTransport) }
|
||||
|
||||
// Try to remove a non-existent prompt
|
||||
val result = server.removePrompt("non-existent-prompt")
|
||||
|
||||
// Verify the result
|
||||
assertFalse(result, "Removing non-existent prompt should return false")
|
||||
assertFalse(promptListChangedNotificationReceived, "No notification should be sent when prompt doesn't exist")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removePrompt should throw when prompts capability is not supported`() = runTest {
|
||||
// Create server without prompts capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities()
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Verify that removing a prompt throws an exception
|
||||
val exception = assertThrows<IllegalStateException> {
|
||||
server.removePrompt("test-prompt")
|
||||
}
|
||||
assertEquals("Server does not support prompts capability.", exception.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeResource should return false when resource does not exist`() = runTest {
|
||||
// Create server with resources capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities(
|
||||
resources = ServerCapabilities.Resources(null, null)
|
||||
)
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Setup client
|
||||
val (clientTransport, serverTransport) = InMemoryTransport.createLinkedPair()
|
||||
val client = Client(
|
||||
clientInfo = Implementation(name = "test client", version = "1.0"),
|
||||
)
|
||||
|
||||
// Track notifications
|
||||
var resourceListChangedNotificationReceived = false
|
||||
client.setNotificationHandler<ResourceListChangedNotification>(Method.Defined.NotificationsResourcesListChanged) {
|
||||
resourceListChangedNotificationReceived = true
|
||||
CompletableDeferred(Unit)
|
||||
}
|
||||
|
||||
// Connect client and server
|
||||
launch { client.connect(clientTransport) }
|
||||
launch { server.connect(serverTransport) }
|
||||
|
||||
// Try to remove a non-existent resource
|
||||
val result = server.removeResource("non-existent-resource")
|
||||
|
||||
// Verify the result
|
||||
assertFalse(result, "Removing non-existent resource should return false")
|
||||
assertFalse(resourceListChangedNotificationReceived, "No notification should be sent when resource doesn't exist")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `removeResource should throw when resources capability is not supported`() = runTest {
|
||||
// Create server without resources capability
|
||||
val serverOptions = ServerOptions(
|
||||
capabilities = ServerCapabilities()
|
||||
)
|
||||
val server = Server(
|
||||
Implementation(name = "test server", version = "1.0"),
|
||||
serverOptions
|
||||
)
|
||||
|
||||
// Verify that removing a resource throws an exception
|
||||
val exception = assertThrows<IllegalStateException> {
|
||||
server.removeResource("test://resource")
|
||||
}
|
||||
assertEquals("Server does not support resources capability.", exception.message)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk.server
|
||||
|
||||
import io.modelcontextprotocol.kotlin.sdk.InitializedNotification
|
||||
import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage
|
||||
import io.modelcontextprotocol.kotlin.sdk.PingRequest
|
||||
import io.modelcontextprotocol.kotlin.sdk.shared.ReadBuffer
|
||||
import io.modelcontextprotocol.kotlin.sdk.shared.serializeMessage
|
||||
import io.modelcontextprotocol.kotlin.sdk.toJSON
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.io.Sink
|
||||
import kotlinx.io.Source
|
||||
import kotlinx.io.asSink
|
||||
import kotlinx.io.asSource
|
||||
import kotlinx.io.buffered
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.PipedInputStream
|
||||
import java.io.PipedOutputStream
|
||||
|
||||
class StdioServerTransportTest {
|
||||
private lateinit var input: PipedInputStream
|
||||
private lateinit var inputWriter: PipedOutputStream
|
||||
private lateinit var outputBuffer: ReadBuffer
|
||||
private lateinit var output: ByteArrayOutputStream
|
||||
|
||||
// We'll store the wrapped streams that meet the constructor requirements
|
||||
private lateinit var bufferedInput: Source
|
||||
private lateinit var printOutput: Sink
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
// Simulate an input stream that we can push data into using inputWriter.
|
||||
input = PipedInputStream()
|
||||
inputWriter = PipedOutputStream(input)
|
||||
|
||||
outputBuffer = ReadBuffer()
|
||||
|
||||
// A custom ByteArrayOutputStream that appends all written data into outputBuffer
|
||||
output = object : ByteArrayOutputStream() {
|
||||
override fun write(b: ByteArray, off: Int, len: Int) {
|
||||
super.write(b, off, len)
|
||||
outputBuffer.append(b.copyOfRange(off, off + len))
|
||||
}
|
||||
}
|
||||
|
||||
bufferedInput = input.asSource().buffered()
|
||||
|
||||
printOutput = output.asSink().buffered()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should start then close cleanly`() {
|
||||
runBlocking {
|
||||
val server = StdioServerTransport(bufferedInput, printOutput)
|
||||
server.onError { error ->
|
||||
throw error
|
||||
}
|
||||
|
||||
var didClose = false
|
||||
server.onClose {
|
||||
didClose = true
|
||||
}
|
||||
|
||||
server.start()
|
||||
assertFalse(didClose, "Should not have closed yet")
|
||||
|
||||
server.close()
|
||||
assertTrue(didClose, "Should have closed after calling close()")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should not read until started`() {
|
||||
runBlocking {
|
||||
val server = StdioServerTransport(bufferedInput, printOutput)
|
||||
server.onError { error ->
|
||||
throw error
|
||||
}
|
||||
|
||||
var didRead = false
|
||||
val readMessage = CompletableDeferred<JSONRPCMessage>()
|
||||
|
||||
server.onMessage { message ->
|
||||
didRead = true
|
||||
readMessage.complete(message)
|
||||
}
|
||||
|
||||
val message = PingRequest().toJSON()
|
||||
|
||||
// Push a message before the server started
|
||||
val serialized = serializeMessage(message)
|
||||
inputWriter.write(serialized)
|
||||
inputWriter.flush()
|
||||
|
||||
assertFalse(didRead, "Should not have read message before start")
|
||||
|
||||
server.start()
|
||||
val received = readMessage.await()
|
||||
assertEquals(message, received)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should read multiple messages`() {
|
||||
runBlocking {
|
||||
val server = StdioServerTransport(bufferedInput, printOutput)
|
||||
server.onError { error ->
|
||||
throw error
|
||||
}
|
||||
|
||||
val messages = listOf(
|
||||
PingRequest().toJSON(),
|
||||
InitializedNotification().toJSON(),
|
||||
)
|
||||
|
||||
val readMessages = mutableListOf<JSONRPCMessage>()
|
||||
val finished = CompletableDeferred<Unit>()
|
||||
|
||||
server.onMessage { message ->
|
||||
readMessages.add(message)
|
||||
if (message == messages[1]) {
|
||||
finished.complete(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
// Push both messages before starting the server
|
||||
for (m in messages) {
|
||||
inputWriter.write(serializeMessage(m))
|
||||
}
|
||||
inputWriter.flush()
|
||||
|
||||
server.start()
|
||||
finished.await()
|
||||
|
||||
assertEquals(messages, readMessages)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun PipedOutputStream.write(s: String) {
|
||||
write(s.toByteArray())
|
||||
}
|
||||
Loading…
Reference in a new issue