feat(server): add support for tool structured content and output schema (#146)
Fixes #139
This commit is contained in:
parent
675cc73c6d
commit
12f686fa4b
5 changed files with 123 additions and 20 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -186,12 +186,30 @@ 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.
|
||||
*/
|
||||
|
|
@ -199,17 +217,12 @@ public open class Server(
|
|||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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")
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -587,7 +587,8 @@ class ClientTest {
|
|||
name = "testTool",
|
||||
description = "testTool description",
|
||||
annotations = null,
|
||||
inputSchema = Tool.Input()
|
||||
inputSchema = Tool.Input(),
|
||||
outputSchema = null
|
||||
)
|
||||
), nextCursor = null
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue