Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 48 additions & 10 deletions api/kotlin-sdk.api
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,10 @@ public final class io/modelcontextprotocol/kotlin/sdk/CallToolRequest$Companion

public final class io/modelcontextprotocol/kotlin/sdk/CallToolResult : io/modelcontextprotocol/kotlin/sdk/CallToolResultBase {
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/CallToolResult$Companion;
public fun <init> (Ljava/util/List;Ljava/lang/Boolean;Lkotlinx/serialization/json/JsonObject;)V
public synthetic fun <init> (Ljava/util/List;Ljava/lang/Boolean;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/util/List;Lkotlinx/serialization/json/JsonObject;Ljava/lang/Boolean;Lkotlinx/serialization/json/JsonObject;)V
public synthetic fun <init> (Ljava/util/List;Lkotlinx/serialization/json/JsonObject;Ljava/lang/Boolean;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun getContent ()Ljava/util/List;
public fun getStructuredContent ()Lkotlinx/serialization/json/JsonObject;
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
public fun isError ()Ljava/lang/Boolean;
}
Expand All @@ -120,6 +121,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/CallToolResult$Companion {
public abstract interface class io/modelcontextprotocol/kotlin/sdk/CallToolResultBase : io/modelcontextprotocol/kotlin/sdk/ServerResult {
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/CallToolResultBase$Companion;
public abstract fun getContent ()Ljava/util/List;
public abstract fun getStructuredContent ()Lkotlinx/serialization/json/JsonObject;
public fun isError ()Ljava/lang/Boolean;
}

Expand Down Expand Up @@ -247,9 +249,10 @@ public final class io/modelcontextprotocol/kotlin/sdk/ClientResult$Companion {

public final class io/modelcontextprotocol/kotlin/sdk/CompatibilityCallToolResult : io/modelcontextprotocol/kotlin/sdk/CallToolResultBase {
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/CompatibilityCallToolResult$Companion;
public fun <init> (Ljava/util/List;Ljava/lang/Boolean;Lkotlinx/serialization/json/JsonObject;Lkotlinx/serialization/json/JsonObject;)V
public synthetic fun <init> (Ljava/util/List;Ljava/lang/Boolean;Lkotlinx/serialization/json/JsonObject;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/util/List;Lkotlinx/serialization/json/JsonObject;Ljava/lang/Boolean;Lkotlinx/serialization/json/JsonObject;Lkotlinx/serialization/json/JsonObject;)V
public synthetic fun <init> (Ljava/util/List;Lkotlinx/serialization/json/JsonObject;Ljava/lang/Boolean;Lkotlinx/serialization/json/JsonObject;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun getContent ()Ljava/util/List;
public fun getStructuredContent ()Lkotlinx/serialization/json/JsonObject;
public final fun getToolResult ()Lkotlinx/serialization/json/JsonObject;
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
public fun isError ()Ljava/lang/Boolean;
Expand Down Expand Up @@ -2553,18 +2556,20 @@ 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;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;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 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 final fun component4 ()Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;
public final fun component5 ()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/Tool$Output;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/Tool$Output;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;
public final fun getOutputSchema ()Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand Down Expand Up @@ -2616,6 +2621,38 @@ public final class io/modelcontextprotocol/kotlin/sdk/Tool$Input$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}

public final class io/modelcontextprotocol/kotlin/sdk/Tool$Output {
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/Tool$Output$Companion;
public fun <init> ()V
public fun <init> (Lkotlinx/serialization/json/JsonObject;Ljava/util/List;)V
public synthetic fun <init> (Lkotlinx/serialization/json/JsonObject;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lkotlinx/serialization/json/JsonObject;
public final fun component2 ()Ljava/util/List;
public final fun copy (Lkotlinx/serialization/json/JsonObject;Ljava/util/List;)Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;Lkotlinx/serialization/json/JsonObject;Ljava/util/List;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;
public fun equals (Ljava/lang/Object;)Z
public final fun getProperties ()Lkotlinx/serialization/json/JsonObject;
public final fun getRequired ()Ljava/util/List;
public final fun getType ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final synthetic class io/modelcontextprotocol/kotlin/sdk/Tool$Output$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/Tool$Output$$serializer;
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;
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/Tool$Output;)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/Tool$Output$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
Expand Down Expand Up @@ -2977,8 +3014,9 @@ 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;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 addTool (Lio/modelcontextprotocol/kotlin/sdk/Tool;Lkotlin/jvm/functions/Function2;)V
public final fun addTool (Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;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/Tool$Output;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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,30 +186,43 @@ public open class Server(
_onClose()
}

/**
* Registers a single tool. The client can then call this tool.
*
* @param tool A [Tool] object describing the tool.
* @param handler A suspend function that handles executing the tool when called by the client.
* @throws IllegalStateException If the server does not support tools.
*/
public fun addTool(tool: Tool, handler: suspend (CallToolRequest) -> CallToolResult) {
if (capabilities.tools == null) {
logger.error { "Failed to add tool '${tool.name}': Server does not support tools capability" }
throw IllegalStateException("Server does not support tools capability. Enable it in ServerOptions.")
}
logger.info { "Registering tool: ${tool.name}" }
_tools.update { current -> current.put(tool.name, RegisteredTool(tool, handler)) }
}

/**
* Registers a single tool. The client can then call this tool.
*
* @param name The name of the tool.
* @param description A human-readable description of what the tool does.
* @param inputSchema The expected input schema for the tool.
* @param outputSchema The optional expected output schema for the tool.
* @param toolAnnotations Optional additional tool information.
* @param handler A suspend function that handles executing the tool when called by the client.
* @throws IllegalStateException If the server does not support tools.
*/
public fun addTool(
name: String,
description: String,
inputSchema: Tool.Input = Tool.Input(),
outputSchema: Tool.Output? = null,
toolAnnotations: ToolAnnotations? = null,
handler: suspend (CallToolRequest) -> CallToolResult
) {
if (capabilities.tools == null) {
logger.error { "Failed to add tool '$name': Server does not support tools capability" }
throw IllegalStateException("Server does not support tools capability. Enable it in ServerOptions.")
}
logger.info { "Registering tool: $name" }
_tools.update { current ->
current.put(name, RegisteredTool(Tool(name, description, inputSchema, toolAnnotations), handler))
}
val tool = Tool(name, description, inputSchema, outputSchema, toolAnnotations)
addTool(tool, handler)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,10 @@ public data class Tool(
* A JSON object defining the expected parameters for the tool.
*/
val inputSchema: Input,

/**
* An optional JSON object defining the expected output schema for the tool.
*/
val outputSchema: Output?,
/**
* Optional additional tool information.
*/
Expand All @@ -1120,6 +1123,16 @@ public data class Tool(
@EncodeDefault
val type: String = "object"
}

@Serializable
public data class Output(
val properties: JsonObject = EmptyJsonObject,
val required: List<String>? = null,
) {
@OptIn(ExperimentalSerializationApi::class)
@EncodeDefault
val type: String = "object"
}
}

/**
Expand Down Expand Up @@ -1149,6 +1162,7 @@ public class ListToolsResult(
@Serializable
public sealed interface CallToolResultBase : ServerResult {
public val content: List<PromptMessageContent>
public val structuredContent: JsonObject?
public val isError: Boolean? get() = false
}

Expand All @@ -1158,6 +1172,7 @@ public sealed interface CallToolResultBase : ServerResult {
@Serializable
public class CallToolResult(
override val content: List<PromptMessageContent>,
override val structuredContent: JsonObject? = null,
override val isError: Boolean? = false,
override val _meta: JsonObject = EmptyJsonObject,
) : CallToolResultBase
Expand All @@ -1168,6 +1183,7 @@ public class CallToolResult(
@Serializable
public class CompatibilityCallToolResult(
override val content: List<PromptMessageContent>,
override val structuredContent: JsonObject? = null,
override val isError: Boolean? = false,
override val _meta: JsonObject = EmptyJsonObject,
public val toolResult: JsonObject = EmptyJsonObject,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ class ToolSerializationTest {
}
},
"required": ["location"]
},
"outputSchema": {
"type": "object",
"properties": {
"temperature": {
"type": "number",
"description": "Temperature in celsius"
},
"conditions": {
"type": "string",
"description": "Weather conditions description"
},
"humidity": {
"type": "number",
"description": "Humidity percentage"
}
},
"required": ["temperature", "conditions", "humidity"]
}
}
""".trimIndent()
Expand All @@ -41,6 +59,23 @@ class ToolSerializationTest {
})
},
required = listOf("location")
),
outputSchema = Tool.Output(
properties = buildJsonObject {
put("temperature", buildJsonObject {
put("type", JsonPrimitive("number"))
put("description", JsonPrimitive("Temperature in celsius"))
})
put("conditions", buildJsonObject {
put("type", JsonPrimitive("string"))
put("description", JsonPrimitive("Weather conditions description"))
})
put("humidity", buildJsonObject {
put("type", JsonPrimitive("number"))
put("description", JsonPrimitive("Humidity percentage"))
})
},
required = listOf("temperature", "conditions", "humidity")
)
)

Expand Down
3 changes: 2 additions & 1 deletion src/jvmTest/kotlin/client/ClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,8 @@ class ClientTest {
name = "testTool",
description = "testTool description",
annotations = null,
inputSchema = Tool.Input()
inputSchema = Tool.Input(),
outputSchema = null
)
), nextCursor = null
)
Expand Down
Loading