feat: add tool annotations according to 2025-03-26 spec (#71)

* feat: add tool annotations

* chore: commit api dump

* fix import and api

---------

Co-authored-by: devcrocod <devcrocod@gmail.com>
Co-authored-by: Leonid Stashevsky <e5l@users.noreply.github.com>
This commit is contained in:
SeanChinJunKai 2025-07-07 14:52:16 +08:00 • committed by GitHub
commit 89c20379ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 105 additions and 7 deletions

View file

@ -2439,13 +2439,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 <init> (Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;)V
public fun <init> (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 +2502,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 <init> (Ljava/lang/String;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;)V
public synthetic fun <init> (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 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;
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 <init> ()V
@ -2824,8 +2862,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

View file

@ -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
@ -183,6 +184,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 +192,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)
}
/**

View file

@ -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(

View file

@ -2,7 +2,6 @@ package io.modelcontextprotocol.kotlin.sdk
import io.kotest.assertions.json.shouldEqualJson
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.buildJsonObject
@ -33,6 +32,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 {

View file

@ -583,6 +583,7 @@ class ClientTest {
Tool(
name = "testTool",
description = "testTool description",
annotations = null,
inputSchema = Tool.Input()
)
), nextCursor = null