diff --git a/AGENTS.md b/AGENTS.md index 7b723e8..1646c55 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -92,6 +92,10 @@ Follow these rules to keep changes safe, comprehensible, and easy to maintain. - **mockk**: Mocking library - **Ktor MockEngine**: For HTTP client mocking (`io.ktor:ktor-client-mock`) - **Java tests**: Use JUnit5, Mockito, AssertJ core +- **Serialization test utilities** (`io.modelcontextprotocol.kotlin.test.utils`): + - `verifySerialization(value, json, expectedJson)` — serializes, asserts match, round-trips back; use for most serialization tests + - `verifyDeserialization(json, payload)` — deserializes from JSON, re-serializes, asserts match; returns the object for further assertions + - Always test both empty/null/omitted and non-null cases for nullable fields; `McpJson` has `explicitNulls = false` so null properties must be absent from JSON, not `null` ### Kotest Patterns diff --git a/kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/InitializeTest.kt b/kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/InitializeTest.kt index 69c0878..3da2a8b 100644 --- a/kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/InitializeTest.kt +++ b/kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/InitializeTest.kt @@ -189,6 +189,34 @@ class InitializeTest { ) } + @Test + fun `should serialize InitializeResult without meta - meta must be omitted`() { + val result = InitializeResult( + protocolVersion = "2025-03-26", + capabilities = ServerCapabilities(tools = ServerCapabilities.Tools(listChanged = false)), + serverInfo = Implementation(name = "test-server", version = "1.0.0"), + ) + + verifySerialization( + result, + McpJson, + """ + { + "protocolVersion": "2025-03-26", + "capabilities": { + "tools": { + "listChanged": false + } + }, + "serverInfo": { + "name": "test-server", + "version": "1.0.0" + } + } + """.trimIndent(), + ) + } + @Test fun `should deserialize InitializeResult from JSON`() { val json = """ diff --git a/kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/JsonRpcTest.kt b/kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/JsonRpcTest.kt index db111fe..7de360d 100644 --- a/kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/JsonRpcTest.kt +++ b/kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/JsonRpcTest.kt @@ -265,6 +265,26 @@ class JsonRpcTest { ) } + @Test + fun `should serialize JSONRPCResponse with EmptyResult - null meta must be omitted`() { + val response = JSONRPCResponse( + id = RequestId("call-2"), + result = EmptyResult(), // meta = null by default + ) + + verifySerialization( + response, + McpJson, + """ + { + "id": "call-2", + "result": {}, + "jsonrpc": "2.0" + } + """.trimIndent(), + ) + } + @Test fun `should deserialize JSONRPCResponse with EmptyResult`() { val json = """