From 4ed91a076f4a01118c316d0f32d5a76001449963 Mon Sep 17 00:00:00 2001 From: Kazik Pogoda Date: Wed, 19 Feb 2025 18:09:40 +0100 Subject: [PATCH 1/2] Add kotest-assertions-json dependency + ToolSerializationTest --- build.gradle.kts | 1 + gradle/libs.versions.toml | 4 +- .../kotlin/ToolSerializationTest.kt | 47 +++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 src/commonTest/kotlin/ToolSerializationTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index 96fd3041..c203c4f6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -219,6 +219,7 @@ kotlin { implementation(libs.ktor.server.test.host) implementation(libs.kotlinx.coroutines.test) implementation(libs.kotlinx.coroutines.debug) + implementation(libs.kotest.assertions.json) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 57d552cd..2265caea 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,6 +13,7 @@ logging = "7.0.0" jreleaser = "1.15.0" binaryCompatibilityValidatorPlugin = "0.17.0" slf4j = "2.0.16" +kotest = "5.9.1" [libraries] # Kotlinx libraries @@ -32,8 +33,7 @@ kotlinx-coroutines-debug = { group = "org.jetbrains.kotlinx", name = "kotlinx-co ktor-server-test-host = { group = "io.ktor", name = "ktor-server-test-host", version.ref = "ktor" } mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } slf4j-simple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" } - - +kotest-assertions-json = { group = "io.kotest", name = "kotest-assertions-json", version.ref = "kotest" } [plugins] kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } diff --git a/src/commonTest/kotlin/ToolSerializationTest.kt b/src/commonTest/kotlin/ToolSerializationTest.kt new file mode 100644 index 00000000..a4aa2a06 --- /dev/null +++ b/src/commonTest/kotlin/ToolSerializationTest.kt @@ -0,0 +1,47 @@ +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.JsonPrimitive +import kotlinx.serialization.json.buildJsonObject +import kotlin.test.Test + +class ToolSerializationTest { + + @Test + fun `should serialize GetWeather tool`() { + val tool = Tool( + name = "get_weather", + description = "Get the current weather in a given location", + inputSchema = Tool.Input( + properties = buildJsonObject { + put("location", buildJsonObject { + put("type", JsonPrimitive("string")) + put("description", JsonPrimitive("The city and state, e.g. San Francisco, CA")) + }) + }, + required = listOf("location") + ) + ) + + // see https://docs.anthropic.com/en/docs/build-with-claude/tool-use + McpJson.encodeToString(tool) shouldEqualJson /* language=json */ """ + { + "name": "get_weather", + "description": "Get the current weather in a given location", + "inputSchema": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA" + } + }, + "required": ["location"] + } + } + """ + } + +} From 65089dc70ed4bde74ea65839a248ccca6075d6e0 Mon Sep 17 00:00:00 2001 From: Kazik Pogoda Date: Wed, 19 Feb 2025 18:26:56 +0100 Subject: [PATCH 2/2] ToolSerializationTest update --- .../kotlin/ToolSerializationTest.kt | 74 +++++++++++-------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/src/commonTest/kotlin/ToolSerializationTest.kt b/src/commonTest/kotlin/ToolSerializationTest.kt index a4aa2a06..90c5c109 100644 --- a/src/commonTest/kotlin/ToolSerializationTest.kt +++ b/src/commonTest/kotlin/ToolSerializationTest.kt @@ -6,42 +6,52 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.buildJsonObject import kotlin.test.Test +import kotlin.test.assertEquals class ToolSerializationTest { - @Test - fun `should serialize GetWeather tool`() { - val tool = Tool( - name = "get_weather", - description = "Get the current weather in a given location", - inputSchema = Tool.Input( - properties = buildJsonObject { - put("location", buildJsonObject { - put("type", JsonPrimitive("string")) - put("description", JsonPrimitive("The city and state, e.g. San Francisco, CA")) - }) - }, - required = listOf("location") - ) + // see https://docs.anthropic.com/en/docs/build-with-claude/tool-use + /* language=json */ + private val getWeatherToolJson = """ + { + "name": "get_weather", + "description": "Get the current weather in a given location", + "inputSchema": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "The city and state, e.g. San Francisco, CA" + } + }, + "required": ["location"] + } + } + """.trimIndent() + + val getWeatherTool = Tool( + name = "get_weather", + description = "Get the current weather in a given location", + inputSchema = Tool.Input( + properties = buildJsonObject { + put("location", buildJsonObject { + put("type", JsonPrimitive("string")) + put("description", JsonPrimitive("The city and state, e.g. San Francisco, CA")) + }) + }, + required = listOf("location") ) + ) - // see https://docs.anthropic.com/en/docs/build-with-claude/tool-use - McpJson.encodeToString(tool) shouldEqualJson /* language=json */ """ - { - "name": "get_weather", - "description": "Get the current weather in a given location", - "inputSchema": { - "type": "object", - "properties": { - "location": { - "type": "string", - "description": "The city and state, e.g. San Francisco, CA" - } - }, - "required": ["location"] - } - } - """ + @Test + fun `should serialize get_weather tool`() { + McpJson.encodeToString(getWeatherTool) shouldEqualJson getWeatherToolJson + } + + @Test + fun `should deserialize get_weather tool`() { + val tool = McpJson.decodeFromString(getWeatherToolJson) + assertEquals(expected = getWeatherTool, actual = tool) } -} +} \ No newline at end of file