Adds optional _meta field to Tool (#339)
<!-- Provide a brief summary of your changes --> ## Motivation and Context The recently released openAI [Apps SDK ](https://developers.openai.com/apps-sdk/reference/#_meta-fields-the-client-provides)adds a '__meta_' field on the Tool Descriptor. This would be in addition to it being available on Messages. It remains optional and defaults to an empty json object, following existing conventions. ## How Has This Been Tested? Unit tests for serialization added ## Breaking Changes N/A ## Types of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [X] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply. --> - [X] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [X] My code follows the repository's style guidelines - [X] New and existing tests pass locally - [X] I have added appropriate error handling - [X] I have added or updated documentation as needed ## Additional context https://developers.openai.com/apps-sdk https://developers.openai.com/apps-sdk/reference/#_meta-fields-the-client-provides --------- Co-authored-by: Pavel Gorgulov <devcrocod@gmail.com>
This commit is contained in:
parent
f462019c43
commit
e4bd866fdd
7 changed files with 50 additions and 10 deletions
|
|
@ -113,7 +113,8 @@ internal class StreamableHttpClientTest : AbstractStreamableHttpClientTest() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["temperature"]
|
"required": ["temperature"]
|
||||||
}
|
},
|
||||||
|
"_meta": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2889,17 +2889,19 @@ public final class io/modelcontextprotocol/kotlin/sdk/TextResourceContents$Compa
|
||||||
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
public final fun serializer ()Lkotlinx/serialization/KSerializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class io/modelcontextprotocol/kotlin/sdk/Tool {
|
public final class io/modelcontextprotocol/kotlin/sdk/Tool : io/modelcontextprotocol/kotlin/sdk/WithMeta {
|
||||||
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/Tool$Companion;
|
public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/Tool$Companion;
|
||||||
public fun <init> (Ljava/lang/String;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 fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Lkotlinx/serialization/json/JsonObject;)V
|
||||||
|
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
public final fun component1 ()Ljava/lang/String;
|
public final fun component1 ()Ljava/lang/String;
|
||||||
public final fun component2 ()Ljava/lang/String;
|
public final fun component2 ()Ljava/lang/String;
|
||||||
public final fun component3 ()Ljava/lang/String;
|
public final fun component3 ()Ljava/lang/String;
|
||||||
public final fun component4 ()Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;
|
public final fun component4 ()Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;
|
||||||
public final fun component5 ()Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;
|
public final fun component5 ()Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;
|
||||||
public final fun component6 ()Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;
|
public final fun component6 ()Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;
|
||||||
public final fun copy (Ljava/lang/String;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 final fun component7 ()Lkotlinx/serialization/json/JsonObject;
|
||||||
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/Tool;Ljava/lang/String;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 final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/Tool;
|
||||||
|
public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/Tool;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/Tool;
|
||||||
public fun equals (Ljava/lang/Object;)Z
|
public fun equals (Ljava/lang/Object;)Z
|
||||||
public final fun getAnnotations ()Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;
|
public final fun getAnnotations ()Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;
|
||||||
public final fun getDescription ()Ljava/lang/String;
|
public final fun getDescription ()Ljava/lang/String;
|
||||||
|
|
@ -2907,6 +2909,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/Tool {
|
||||||
public final fun getName ()Ljava/lang/String;
|
public final fun getName ()Ljava/lang/String;
|
||||||
public final fun getOutputSchema ()Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;
|
public final fun getOutputSchema ()Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;
|
||||||
public final fun getTitle ()Ljava/lang/String;
|
public final fun getTitle ()Ljava/lang/String;
|
||||||
|
public fun get_meta ()Lkotlinx/serialization/json/JsonObject;
|
||||||
public fun hashCode ()I
|
public fun hashCode ()I
|
||||||
public fun toString ()Ljava/lang/String;
|
public fun toString ()Ljava/lang/String;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1242,7 +1242,12 @@ public data class Tool(
|
||||||
* Optional additional tool information.
|
* Optional additional tool information.
|
||||||
*/
|
*/
|
||||||
val annotations: ToolAnnotations?,
|
val annotations: ToolAnnotations?,
|
||||||
) {
|
|
||||||
|
/**
|
||||||
|
* Optional metadata for the tool.
|
||||||
|
*/
|
||||||
|
override val _meta: JsonObject = EmptyJsonObject,
|
||||||
|
) : WithMeta {
|
||||||
@Serializable
|
@Serializable
|
||||||
public data class Input(val properties: JsonObject = EmptyJsonObject, val required: List<String>? = null) {
|
public data class Input(val properties: JsonObject = EmptyJsonObject, val required: List<String>? = null) {
|
||||||
@OptIn(ExperimentalSerializationApi::class)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,8 @@ class RequestSerializerTest {
|
||||||
"inputSchema": {
|
"inputSchema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {}
|
"properties": {}
|
||||||
}
|
},
|
||||||
|
"_meta": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}"""
|
}"""
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package io.modelcontextprotocol.kotlin.sdk
|
||||||
import io.kotest.assertions.json.shouldEqualJson
|
import io.kotest.assertions.json.shouldEqualJson
|
||||||
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
|
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
import kotlinx.serialization.json.JsonPrimitive
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
import kotlinx.serialization.json.buildJsonObject
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
|
|
@ -44,6 +45,9 @@ class ToolSerializationTest {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["temperature", "conditions", "humidity"]
|
"required": ["temperature", "conditions", "humidity"]
|
||||||
|
},
|
||||||
|
"_meta": {
|
||||||
|
"_for_test_only": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
@ -91,6 +95,9 @@ class ToolSerializationTest {
|
||||||
},
|
},
|
||||||
required = listOf("temperature", "conditions", "humidity"),
|
required = listOf("temperature", "conditions", "humidity"),
|
||||||
),
|
),
|
||||||
|
_meta = buildJsonObject {
|
||||||
|
put("_for_test_only", JsonPrimitive(true))
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
//region Serialize
|
//region Serialize
|
||||||
|
|
@ -411,6 +418,7 @@ class ToolSerializationTest {
|
||||||
name: String = "get_weather",
|
name: String = "get_weather",
|
||||||
title: String? = null,
|
title: String? = null,
|
||||||
outputSchema: String? = null,
|
outputSchema: String? = null,
|
||||||
|
@Suppress("LocalVariableName") _meta: String? = null,
|
||||||
): String {
|
): String {
|
||||||
val stringBuilder = StringBuilder()
|
val stringBuilder = StringBuilder()
|
||||||
|
|
||||||
|
|
@ -453,6 +461,14 @@ class ToolSerializationTest {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stringBuilder
|
||||||
|
.appendLine(",")
|
||||||
|
.append(
|
||||||
|
"""
|
||||||
|
"_meta": ${_meta ?: "{}"}
|
||||||
|
""".trimIndent(),
|
||||||
|
)
|
||||||
|
|
||||||
stringBuilder
|
stringBuilder
|
||||||
.appendLine()
|
.appendLine()
|
||||||
.appendLine("}")
|
.appendLine("}")
|
||||||
|
|
@ -464,6 +480,7 @@ class ToolSerializationTest {
|
||||||
name: String = "get_weather",
|
name: String = "get_weather",
|
||||||
title: String? = null,
|
title: String? = null,
|
||||||
outputSchema: Tool.Output? = null,
|
outputSchema: Tool.Output? = null,
|
||||||
|
@Suppress("LocalVariableName") _meta: JsonObject? = null,
|
||||||
): Tool = Tool(
|
): Tool = Tool(
|
||||||
name = name,
|
name = name,
|
||||||
title = title,
|
title = title,
|
||||||
|
|
@ -482,6 +499,7 @@ class ToolSerializationTest {
|
||||||
required = listOf("location"),
|
required = listOf("location"),
|
||||||
),
|
),
|
||||||
outputSchema = outputSchema,
|
outputSchema = outputSchema,
|
||||||
|
_meta = _meta ?: EmptyJsonObject,
|
||||||
)
|
)
|
||||||
|
|
||||||
//endregion Private Methods
|
//endregion Private Methods
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ public class io/modelcontextprotocol/kotlin/sdk/server/Server {
|
||||||
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 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 addResources (Ljava/util/List;)V
|
||||||
public final fun addTool (Lio/modelcontextprotocol/kotlin/sdk/Tool;Lkotlin/jvm/functions/Function2;)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;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Lkotlin/jvm/functions/Function2;)V
|
public final fun addTool (Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Input;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Lkotlinx/serialization/json/JsonObject;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;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)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;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/Tool$Output;Lio/modelcontextprotocol/kotlin/sdk/ToolAnnotations;Lkotlinx/serialization/json/JsonObject;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
|
||||||
public final fun addTools (Ljava/util/List;)V
|
public final fun addTools (Ljava/util/List;)V
|
||||||
public final fun close (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
public final fun close (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
public final fun connect (Lio/modelcontextprotocol/kotlin/sdk/shared/Transport;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
public final fun connect (Lio/modelcontextprotocol/kotlin/sdk/shared/Transport;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package io.modelcontextprotocol.kotlin.sdk.server
|
||||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
import io.modelcontextprotocol.kotlin.sdk.CallToolRequest
|
import io.modelcontextprotocol.kotlin.sdk.CallToolRequest
|
||||||
import io.modelcontextprotocol.kotlin.sdk.CallToolResult
|
import io.modelcontextprotocol.kotlin.sdk.CallToolResult
|
||||||
|
import io.modelcontextprotocol.kotlin.sdk.EmptyJsonObject
|
||||||
import io.modelcontextprotocol.kotlin.sdk.GetPromptRequest
|
import io.modelcontextprotocol.kotlin.sdk.GetPromptRequest
|
||||||
import io.modelcontextprotocol.kotlin.sdk.GetPromptResult
|
import io.modelcontextprotocol.kotlin.sdk.GetPromptResult
|
||||||
import io.modelcontextprotocol.kotlin.sdk.Implementation
|
import io.modelcontextprotocol.kotlin.sdk.Implementation
|
||||||
|
|
@ -30,6 +31,7 @@ import kotlinx.atomicfu.atomic
|
||||||
import kotlinx.atomicfu.update
|
import kotlinx.atomicfu.update
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
|
||||||
private val logger = KotlinLogging.logger {}
|
private val logger = KotlinLogging.logger {}
|
||||||
|
|
||||||
|
|
@ -243,6 +245,7 @@ public open class Server(
|
||||||
* @param inputSchema The expected input schema for the tool.
|
* @param inputSchema The expected input schema for the tool.
|
||||||
* @param outputSchema The optional expected output schema for the tool.
|
* @param outputSchema The optional expected output schema for the tool.
|
||||||
* @param toolAnnotations Optional additional tool information.
|
* @param toolAnnotations Optional additional tool information.
|
||||||
|
* @param _meta Optional metadata as a [JsonObject].
|
||||||
* @param handler A suspend function that handles executing the tool when called by the client.
|
* @param handler A suspend function that handles executing the tool when called by the client.
|
||||||
* @throws IllegalStateException If the server does not support tools.
|
* @throws IllegalStateException If the server does not support tools.
|
||||||
*/
|
*/
|
||||||
|
|
@ -254,9 +257,18 @@ public open class Server(
|
||||||
title: String? = null,
|
title: String? = null,
|
||||||
outputSchema: Tool.Output? = null,
|
outputSchema: Tool.Output? = null,
|
||||||
toolAnnotations: ToolAnnotations? = null,
|
toolAnnotations: ToolAnnotations? = null,
|
||||||
|
@Suppress("LocalVariableName") _meta: JsonObject? = null,
|
||||||
handler: suspend (CallToolRequest) -> CallToolResult,
|
handler: suspend (CallToolRequest) -> CallToolResult,
|
||||||
) {
|
) {
|
||||||
val tool = Tool(name, title, description, inputSchema, outputSchema, toolAnnotations)
|
val tool = Tool(
|
||||||
|
name = name,
|
||||||
|
title = title,
|
||||||
|
description = description,
|
||||||
|
inputSchema = inputSchema,
|
||||||
|
outputSchema = outputSchema,
|
||||||
|
annotations = toolAnnotations,
|
||||||
|
_meta = _meta ?: EmptyJsonObject,
|
||||||
|
)
|
||||||
addTool(tool, handler)
|
addTool(tool, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue