diff --git a/api/kotlin-sdk.api b/api/kotlin-sdk.api index 4f0b20c..8235882 100644 --- a/api/kotlin-sdk.api +++ b/api/kotlin-sdk.api @@ -1,3 +1,34 @@ +public final class io/modelcontextprotocol/kotlin/sdk/AudioContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal { + public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/AudioContent$Companion; + public static final field TYPE Ljava/lang/String; + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/modelcontextprotocol/kotlin/sdk/AudioContent; + public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/AudioContent;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/AudioContent; + public fun equals (Ljava/lang/Object;)Z + public final fun getData ()Ljava/lang/String; + public final fun getMimeType ()Ljava/lang/String; + public fun getType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public synthetic class io/modelcontextprotocol/kotlin/sdk/AudioContent$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/AudioContent$$serializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/AudioContent; + 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/AudioContent;)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/AudioContent$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + public final class io/modelcontextprotocol/kotlin/sdk/BlobResourceContents : io/modelcontextprotocol/kotlin/sdk/ResourceContents { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/BlobResourceContents$Companion; public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V @@ -1665,6 +1696,14 @@ public final class io/modelcontextprotocol/kotlin/sdk/PromptMessageContent$Compa public final fun serializer ()Lkotlinx/serialization/KSerializer; } +public abstract interface class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal : io/modelcontextprotocol/kotlin/sdk/PromptMessageContent { + public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal$Companion; +} + +public final class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + public abstract interface class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage : io/modelcontextprotocol/kotlin/sdk/PromptMessageContent { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage$Companion; } @@ -2404,13 +2443,15 @@ public final class io/modelcontextprotocol/kotlin/sdk/TextResourceContents$Compa public final class io/modelcontextprotocol/kotlin/sdk/Tool { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/Tool$Companion; - public fun (Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;)V + public fun (Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; public final fun component3 ()Lio/modelcontextprotocol/kotlin/sdk/Tool$Input; - public final fun copy (Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;)Lio/modelcontextprotocol/kotlin/sdk/Tool; - public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/Tool;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/Tool; + public final fun component4 ()Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;)Lio/modelcontextprotocol/kotlin/sdk/Tool; + public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/Tool;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/Tool; public fun equals (Ljava/lang/Object;)Z + public final fun getAnnotations ()Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations; public final fun getDescription ()Ljava/lang/String; public final fun getInputSchema ()Lio/modelcontextprotocol/kotlin/sdk/Tool$Input; public final fun getName ()Ljava/lang/String; @@ -2465,6 +2506,42 @@ public final class io/modelcontextprotocol/kotlin/sdk/Tool$Input$Companion { public final fun serializer ()Lkotlinx/serialization/KSerializer; } +public final class io/modelcontextprotocol/kotlin/sdk/ToolAnnotations { + public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations$Companion; + public fun (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/Boolean; + public final fun component3 ()Ljava/lang/Boolean; + public final fun component4 ()Ljava/lang/Boolean; + public final fun component5 ()Ljava/lang/Boolean; + public final fun copy (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;)Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations; + public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations; + public fun equals (Ljava/lang/Object;)Z + public final fun getDestructiveHint ()Ljava/lang/Boolean; + public final fun getIdempotentHint ()Ljava/lang/Boolean; + public final fun getOpenWorldHint ()Ljava/lang/Boolean; + public final fun getReadOnlyHint ()Ljava/lang/Boolean; + public final fun getTitle ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public synthetic class io/modelcontextprotocol/kotlin/sdk/ToolAnnotations$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations$$serializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations; + 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/ToolAnnotations;)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/ToolAnnotations$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + 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 ()V @@ -2778,8 +2855,8 @@ public class io/modelcontextprotocol/kotlin/sdk/server/Server : io/modelcontextp public final fun addResource (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function2;)V public static synthetic fun addResource$default (Lio/modelcontextprotocol/kotlin/sdk/server/Server;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V public final fun addResources (Ljava/util/List;)V - public final fun addTool (Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lkotlin/jvm/functions/Function2;)V - public static synthetic fun addTool$default (Lio/modelcontextprotocol/kotlin/sdk/server/Server;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V + public final fun addTool (Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Lkotlin/jvm/functions/Function2;)V + public static synthetic fun addTool$default (Lio/modelcontextprotocol/kotlin/sdk/server/Server;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V public final fun addTools (Ljava/util/List;)V protected fun assertCapabilityForMethod (Lio/modelcontextprotocol/kotlin/sdk/Method;)V protected fun assertNotificationCapability (Lio/modelcontextprotocol/kotlin/sdk/Method;)V diff --git a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt index e24419e..f5a603c 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt @@ -145,6 +145,7 @@ public open class Server( name: String, description: String, inputSchema: Tool.Input = Tool.Input(), + toolAnnotations: ToolAnnotations? = null, handler: suspend (CallToolRequest) -> CallToolResult ) { if (capabilities.tools == null) { @@ -152,7 +153,7 @@ public open class Server( throw IllegalStateException("Server does not support tools capability. Enable it in ServerOptions.") } logger.info { "Registering tool: $name" } - tools[name] = RegisteredTool(Tool(name, description, inputSchema), handler) + tools[name] = RegisteredTool(Tool(name, description, inputSchema, toolAnnotations), handler) } /** diff --git a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt index c5e5456..e70bb96 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt @@ -993,6 +993,58 @@ public class PromptListChangedNotification : ServerNotification { } /* Tools */ +/** + * Additional properties describing a Tool to clients. + * + * NOTE: all properties in ToolAnnotations are **hints**. + * They are not guaranteed to provide a faithful description of + * tool behavior (including descriptive properties like `title`). + * + * Clients should never make tool use decisions based on ToolAnnotations + * received from untrusted servers. + */ +@Serializable +public data class ToolAnnotations( + /** + * A human-readable title for the tool. + */ + val title: String?, + /** + * If true, the tool does not modify its environment. + * + * Default: false + */ + val readOnlyHint: Boolean? = false, + /** + * If true, the tool may perform destructive updates to its environment. + * If false, the tool performs only additive updates. + * + * (This property is meaningful only when `readOnlyHint == false`) + * + * Default: true + */ + val destructiveHint: Boolean? = true, + /** + * If true, calling the tool repeatedly with the same arguments + * will have no additional effect on the its environment. + * + * (This property is meaningful only when `readOnlyHint == false`) + * + * Default: false + */ + val idempotentHint: Boolean? = false, + /** + * If true, this tool may interact with an "open world" of external + * entities. If false, the tool's domain of interaction is closed. + * For example, the world of a web search tool is open, whereas that + * of a memory tool is not. + * + * Default: true + */ + val openWorldHint: Boolean? = true, +) + + /** * Definition for a tool the client can call. */ @@ -1010,6 +1062,11 @@ public data class Tool( * A JSON object defining the expected parameters for the tool. */ val inputSchema: Input, + + /** + * Optional additional tool information. + */ + val annotations: ToolAnnotations?, ) { @Serializable public data class Input( diff --git a/src/commonTest/kotlin/ToolSerializationTest.kt b/src/commonTest/kotlin/ToolSerializationTest.kt index 90c5c10..cc32290 100644 --- a/src/commonTest/kotlin/ToolSerializationTest.kt +++ b/src/commonTest/kotlin/ToolSerializationTest.kt @@ -2,6 +2,7 @@ package io.modelcontextprotocol.kotlin.sdk import io.kotest.assertions.json.shouldEqualJson import io.modelcontextprotocol.kotlin.sdk.shared.McpJson +import kotlinx.atomicfu.atomicArrayOfNulls import kotlinx.serialization.encodeToString import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.buildJsonObject @@ -32,6 +33,7 @@ class ToolSerializationTest { val getWeatherTool = Tool( name = "get_weather", description = "Get the current weather in a given location", + annotations = null, inputSchema = Tool.Input( properties = buildJsonObject { put("location", buildJsonObject { diff --git a/src/jvmTest/kotlin/client/ClientTest.kt b/src/jvmTest/kotlin/client/ClientTest.kt index 4630a34..88d97eb 100644 --- a/src/jvmTest/kotlin/client/ClientTest.kt +++ b/src/jvmTest/kotlin/client/ClientTest.kt @@ -580,6 +580,7 @@ class ClientTest { Tool( name = "testTool", description = "testTool description", + annotations = null, inputSchema = Tool.Input() ) ), nextCursor = null