From b6743ade488729d91a2747fab7027e29c35463e3 Mon Sep 17 00:00:00 2001 From: SeanChinJunKai Date: Wed, 9 Apr 2025 16:04:12 +0800 Subject: [PATCH 1/3] feat: add tool annotations --- .../kotlin/sdk/server/Server.kt | 3 +- .../modelcontextprotocol/kotlin/sdk/types.kt | 57 +++++++++++++++++++ .../kotlin/sdk/ToolSerializationTest.kt | 2 + src/jvmTest/kotlin/client/ClientTest.kt | 1 + 4 files changed, 62 insertions(+), 1 deletion(-) 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 be1b1f03..cdee3dea 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt @@ -183,6 +183,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) { @@ -190,7 +191,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 c93fa941..8972e16c 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt @@ -1031,6 +1031,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. */ @@ -1048,6 +1100,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/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt b/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt index f2d44528..872dbc3b 100644 --- a/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt +++ b/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/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.Json import kotlinx.serialization.json.JsonPrimitive @@ -33,6 +34,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 c1251baa..f74cd0a5 100644 --- a/src/jvmTest/kotlin/client/ClientTest.kt +++ b/src/jvmTest/kotlin/client/ClientTest.kt @@ -583,6 +583,7 @@ class ClientTest { Tool( name = "testTool", description = "testTool description", + annotations = null, inputSchema = Tool.Input() ) ), nextCursor = null From 431c5736012e0c807d3a74420fdd17533e76337c Mon Sep 17 00:00:00 2001 From: SeanChinJunKai Date: Sun, 27 Apr 2025 14:53:45 +0800 Subject: [PATCH 2/3] chore: commit api dump --- api/kotlin-sdk.api | 58 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/api/kotlin-sdk.api b/api/kotlin-sdk.api index ec254cd9..e80c2598 100644 --- a/api/kotlin-sdk.api +++ b/api/kotlin-sdk.api @@ -14,7 +14,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/AudioContent : io/modelcon public fun toString ()Ljava/lang/String; } -public final synthetic class io/modelcontextprotocol/kotlin/sdk/AudioContent$$serializer : kotlinx/serialization/internal/GeneratedSerializer { +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; @@ -1708,6 +1708,14 @@ public final class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultim 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 final class io/modelcontextprotocol/kotlin/sdk/PromptReference : io/modelcontextprotocol/kotlin/sdk/Reference { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptReference$Companion; public static final field TYPE Ljava/lang/String; @@ -2439,13 +2447,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; @@ -2500,6 +2510,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 @@ -2824,8 +2870,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 From d4db2f27eaaa052a5cf00d073429e52ec2db0a4b Mon Sep 17 00:00:00 2001 From: devcrocod Date: Thu, 3 Jul 2025 18:40:27 +0200 Subject: [PATCH 3/3] fix import and api --- api/kotlin-sdk.api | 12 ++---------- .../modelcontextprotocol/kotlin/sdk/server/Server.kt | 1 + .../kotlin/sdk/ToolSerializationTest.kt | 2 -- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/api/kotlin-sdk.api b/api/kotlin-sdk.api index e80c2598..cf30f17d 100644 --- a/api/kotlin-sdk.api +++ b/api/kotlin-sdk.api @@ -14,7 +14,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/AudioContent : io/modelcon public fun toString ()Ljava/lang/String; } -public synthetic class io/modelcontextprotocol/kotlin/sdk/AudioContent$$serializer : kotlinx/serialization/internal/GeneratedSerializer { +public final 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; @@ -1708,14 +1708,6 @@ public final class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultim 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 final class io/modelcontextprotocol/kotlin/sdk/PromptReference : io/modelcontextprotocol/kotlin/sdk/Reference { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptReference$Companion; public static final field TYPE Ljava/lang/String; @@ -2531,7 +2523,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/ToolAnnotations { public fun toString ()Ljava/lang/String; } -public synthetic class io/modelcontextprotocol/kotlin/sdk/ToolAnnotations$$serializer : kotlinx/serialization/internal/GeneratedSerializer { +public final 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; 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 cdee3dea..67791e10 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt @@ -39,6 +39,7 @@ import io.modelcontextprotocol.kotlin.sdk.ResourceUpdatedNotification import io.modelcontextprotocol.kotlin.sdk.SUPPORTED_PROTOCOL_VERSIONS import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities import io.modelcontextprotocol.kotlin.sdk.Tool +import io.modelcontextprotocol.kotlin.sdk.ToolAnnotations import io.modelcontextprotocol.kotlin.sdk.ToolListChangedNotification import io.modelcontextprotocol.kotlin.sdk.shared.Protocol import io.modelcontextprotocol.kotlin.sdk.shared.ProtocolOptions diff --git a/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt b/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt index 872dbc3b..3d53a18d 100644 --- a/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt +++ b/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt @@ -2,8 +2,6 @@ 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.Json import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.buildJsonObject