diff --git a/build.gradle.kts b/build.gradle.kts index 6a997a70..e3563cc2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -220,10 +220,6 @@ kotlin { } } - iosArm64() - iosX64() - iosSimulatorArm64() - js(IR) { nodejs { testTask { @@ -238,6 +234,31 @@ kotlin { nodejs() } + // Tier 1 + macosX64() + macosArm64() + iosArm64() + iosX64() + iosSimulatorArm64() + + // Tier 2 + linuxX64() + linuxArm64() + watchosSimulatorArm64() + watchosX64() +// watchosArm32() not supported by libs.kotlin.logging + watchosArm64() + tvosSimulatorArm64() + tvosX64() + tvosArm64() + + // Tier 3 + androidNativeArm32() + androidNativeArm64() + androidNativeX86() + androidNativeX64() + mingwX64() + explicitApi = ExplicitApiMode.Strict jvmToolchain(21) @@ -262,7 +283,6 @@ kotlin { implementation(libs.kotlin.test) implementation(libs.ktor.server.test.host) implementation(libs.kotlinx.coroutines.test) - implementation(libs.kotest.assertions.json) } } diff --git a/src/commonTest/kotlin/AudioContentSerializationTest.kt b/src/commonTest/kotlin/AudioContentSerializationTest.kt index 6745972c..8e89887e 100644 --- a/src/commonTest/kotlin/AudioContentSerializationTest.kt +++ b/src/commonTest/kotlin/AudioContentSerializationTest.kt @@ -1,20 +1,20 @@ 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.buildJsonObject +import kotlinx.serialization.json.decodeFromJsonElement +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.put import kotlin.test.Test import kotlin.test.assertEquals class AudioContentSerializationTest { - private val audioContentJson = """ - { - "data": "base64-encoded-audio-data", - "mimeType": "audio/wav", - "type": "audio" - } - """.trimIndent() + private val audioContentJson = buildJsonObject { + put("data", "base64-encoded-audio-data") + put("mimeType", "audio/wav") + put("type", "audio") + } private val audioContent = AudioContent( data = "base64-encoded-audio-data", @@ -23,12 +23,17 @@ class AudioContentSerializationTest { @Test fun `should serialize audio content`() { - McpJson.encodeToString(audioContent) shouldEqualJson audioContentJson + val actual = McpJson.encodeToJsonElement(audioContent) + assertEquals( + audioContentJson, + actual, + "Expected $actual to be equal to $audioContentJson" + ) } @Test fun `should deserialize audio content`() { - val content = McpJson.decodeFromString(audioContentJson) + val content = McpJson.decodeFromJsonElement(audioContentJson) assertEquals(expected = audioContent, actual = content) } } \ No newline at end of file diff --git a/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt b/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt index 6e2ac447..70a0cd66 100644 --- a/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt +++ b/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/ToolSerializationTest.kt @@ -1,51 +1,53 @@ package io.modelcontextprotocol.kotlin.sdk -import io.kotest.assertions.json.shouldEqualJson import io.modelcontextprotocol.kotlin.sdk.shared.McpJson import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.decodeFromJsonElement +import kotlinx.serialization.json.encodeToJsonElement import kotlin.test.Test import kotlin.test.assertEquals class ToolSerializationTest { // 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"] - }, - "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() + private val getWeatherToolJson = buildJsonObject { + put("name", JsonPrimitive("get_weather")) + put("description", JsonPrimitive("Get the current weather in a given location")) + put("inputSchema", buildJsonObject { + put("properties", buildJsonObject { + put("location", buildJsonObject { + put("type", JsonPrimitive("string")) + put("description", JsonPrimitive("The city and state, e.g. San Francisco, CA")) + }) + }) + put("required", JsonArray(listOf(JsonPrimitive("location")))) + put("type", JsonPrimitive("object")) + }) + put("outputSchema", buildJsonObject { + put("type", JsonPrimitive("object")) + put("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")) + }) + }) + put( + "required", + JsonArray(listOf(JsonPrimitive("temperature"), JsonPrimitive("conditions"), JsonPrimitive("humidity"))) + ) + }) + } val getWeatherTool = Tool( name = "get_weather", @@ -81,12 +83,18 @@ class ToolSerializationTest { @Test fun `should serialize get_weather tool`() { - McpJson.encodeToString(getWeatherTool) shouldEqualJson getWeatherToolJson + val actual = McpJson.encodeToJsonElement(getWeatherTool) + + assertEquals( + getWeatherToolJson, + actual, + "Expected $actual to be equal to $getWeatherToolJson" + ) } @Test fun `should deserialize get_weather tool`() { - val tool = McpJson.decodeFromString(getWeatherToolJson) + val tool = McpJson.decodeFromJsonElement(getWeatherToolJson) assertEquals(expected = getWeatherTool, actual = tool) } @@ -95,6 +103,11 @@ class ToolSerializationTest { val json = Json(from = McpJson) { encodeDefaults = false } - json.encodeToString(getWeatherTool) shouldEqualJson getWeatherToolJson + val actual = json.encodeToJsonElement(getWeatherTool) + assertEquals( + getWeatherToolJson, + actual, + "Expected $actual to be equal to $getWeatherToolJson" + ) } } diff --git a/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/ReadBufferTest.kt b/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/ReadBufferTest.kt index 6890aef6..8e6f4f65 100644 --- a/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/ReadBufferTest.kt +++ b/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/ReadBufferTest.kt @@ -4,7 +4,6 @@ import io.ktor.utils.io.charsets.Charsets import io.ktor.utils.io.core.toByteArray import io.modelcontextprotocol.kotlin.sdk.JSONRPCMessage import io.modelcontextprotocol.kotlin.sdk.JSONRPCNotification -import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlin.test.Test import kotlin.test.assertEquals diff --git a/src/iosMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.ios.kt b/src/nativeMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.native.kt similarity index 100% rename from src/iosMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.ios.kt rename to src/nativeMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.native.kt