From 1159332022c7bb87ecf9df268b62ad6d226642da Mon Sep 17 00:00:00 2001 From: Konstantin Pavlov <1517853+kpavlov@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:07:54 +0200 Subject: [PATCH] Update samples to use new schema Refactor samples to use `kotlin-sdk.types`, update integration tests to assert `meta` is null, and adjust coroutine logic. --- .../sample/client/MCPClient.kt | 12 +++++---- .../sample/server/server.kt | 24 ++++++++--------- .../test/kotlin/SseServerIntegrationTest.kt | 26 +++++++++++-------- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/samples/kotlin-mcp-client/src/main/kotlin/io/modelcontextprotocol/sample/client/MCPClient.kt b/samples/kotlin-mcp-client/src/main/kotlin/io/modelcontextprotocol/sample/client/MCPClient.kt index 0a0817e7..8360316e 100644 --- a/samples/kotlin-mcp-client/src/main/kotlin/io/modelcontextprotocol/sample/client/MCPClient.kt +++ b/samples/kotlin-mcp-client/src/main/kotlin/io/modelcontextprotocol/sample/client/MCPClient.kt @@ -9,12 +9,13 @@ import com.anthropic.models.messages.Tool import com.anthropic.models.messages.ToolUnion import com.fasterxml.jackson.core.type.TypeReference import com.fasterxml.jackson.databind.ObjectMapper -import io.modelcontextprotocol.kotlin.sdk.EmptyJsonObject -import io.modelcontextprotocol.kotlin.sdk.Implementation -import io.modelcontextprotocol.kotlin.sdk.TextContent import io.modelcontextprotocol.kotlin.sdk.client.Client import io.modelcontextprotocol.kotlin.sdk.client.StdioClientTransport +import io.modelcontextprotocol.kotlin.sdk.types.EmptyJsonObject +import io.modelcontextprotocol.kotlin.sdk.types.Implementation +import io.modelcontextprotocol.kotlin.sdk.types.TextContent import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.yield import kotlinx.io.asSink import kotlinx.io.asSource import kotlinx.io.buffered @@ -137,8 +138,8 @@ class MCPClient : AutoCloseable { "type": "tool_result", "tool_name": $toolName, "result": ${ - result?.content?.joinToString("\n") { - (it as TextContent).text ?: "" + result.content.joinToString("\n") { + (it as TextContent).text } } """.trimIndent(), @@ -173,6 +174,7 @@ class MCPClient : AutoCloseable { if (message.lowercase() == "quit") break val response = processQuery(message) println("\n$response") + yield() } } diff --git a/samples/kotlin-mcp-server/src/main/kotlin/io/modelcontextprotocol/sample/server/server.kt b/samples/kotlin-mcp-server/src/main/kotlin/io/modelcontextprotocol/sample/server/server.kt index a593377f..e707743d 100644 --- a/samples/kotlin-mcp-server/src/main/kotlin/io/modelcontextprotocol/sample/server/server.kt +++ b/samples/kotlin-mcp-server/src/main/kotlin/io/modelcontextprotocol/sample/server/server.kt @@ -14,23 +14,22 @@ import io.ktor.server.routing.routing import io.ktor.server.sse.SSE import io.ktor.server.sse.sse import io.ktor.util.collections.ConcurrentMap -import io.modelcontextprotocol.kotlin.sdk.CallToolResult -import io.modelcontextprotocol.kotlin.sdk.GetPromptResult -import io.modelcontextprotocol.kotlin.sdk.Implementation -import io.modelcontextprotocol.kotlin.sdk.PromptArgument -import io.modelcontextprotocol.kotlin.sdk.PromptMessage -import io.modelcontextprotocol.kotlin.sdk.ReadResourceResult -import io.modelcontextprotocol.kotlin.sdk.Role -import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities -import io.modelcontextprotocol.kotlin.sdk.TextContent -import io.modelcontextprotocol.kotlin.sdk.TextResourceContents -import io.modelcontextprotocol.kotlin.sdk.Tool import io.modelcontextprotocol.kotlin.sdk.server.Server import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions import io.modelcontextprotocol.kotlin.sdk.server.ServerSession import io.modelcontextprotocol.kotlin.sdk.server.SseServerTransport import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport import io.modelcontextprotocol.kotlin.sdk.server.mcp +import io.modelcontextprotocol.kotlin.sdk.types.CallToolResult +import io.modelcontextprotocol.kotlin.sdk.types.GetPromptResult +import io.modelcontextprotocol.kotlin.sdk.types.Implementation +import io.modelcontextprotocol.kotlin.sdk.types.PromptArgument +import io.modelcontextprotocol.kotlin.sdk.types.PromptMessage +import io.modelcontextprotocol.kotlin.sdk.types.ReadResourceResult +import io.modelcontextprotocol.kotlin.sdk.types.Role +import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities +import io.modelcontextprotocol.kotlin.sdk.types.TextContent +import io.modelcontextprotocol.kotlin.sdk.types.TextResourceContents import kotlinx.coroutines.Job import kotlinx.coroutines.runBlocking import kotlinx.io.asSink @@ -66,7 +65,7 @@ fun configureServer(): Server { GetPromptResult( messages = listOf( PromptMessage( - role = Role.user, + role = Role.User, content = TextContent( "Develop a kotlin project named ${request.arguments?.get("Project Name")}", ), @@ -80,7 +79,6 @@ fun configureServer(): Server { server.addTool( name = "kotlin-sdk-tool", description = "A test tool", - inputSchema = Tool.Input(), ) { _ -> CallToolResult( content = listOf(TextContent("Hello, world!")), diff --git a/samples/kotlin-mcp-server/src/test/kotlin/SseServerIntegrationTest.kt b/samples/kotlin-mcp-server/src/test/kotlin/SseServerIntegrationTest.kt index 7f8b6a9a..9cbeddac 100644 --- a/samples/kotlin-mcp-server/src/test/kotlin/SseServerIntegrationTest.kt +++ b/samples/kotlin-mcp-server/src/test/kotlin/SseServerIntegrationTest.kt @@ -1,13 +1,14 @@ -import io.modelcontextprotocol.kotlin.sdk.EmptyJsonObject -import io.modelcontextprotocol.kotlin.sdk.ReadResourceRequest -import io.modelcontextprotocol.kotlin.sdk.TextContent -import io.modelcontextprotocol.kotlin.sdk.TextResourceContents import io.modelcontextprotocol.kotlin.sdk.client.Client +import io.modelcontextprotocol.kotlin.sdk.types.ReadResourceRequest +import io.modelcontextprotocol.kotlin.sdk.types.ReadResourceRequestParams +import io.modelcontextprotocol.kotlin.sdk.types.TextContent +import io.modelcontextprotocol.kotlin.sdk.types.TextResourceContents import kotlinx.coroutines.runBlocking import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertIs import kotlin.test.assertNotNull +import kotlin.test.assertNull import kotlin.test.assertTrue class SseServerIntegrationTest { @@ -20,7 +21,7 @@ class SseServerIntegrationTest { val listToolsResult = client.listTools() // then - assertEquals(expected = EmptyJsonObject, actual = listToolsResult._meta) + assertNull(listToolsResult.meta) val tools = listToolsResult.tools assertEquals(actual = tools.size, expected = 1) @@ -33,7 +34,7 @@ class SseServerIntegrationTest { val listPromptsResult = client.listPrompts() // then - assertEquals(expected = EmptyJsonObject, actual = listPromptsResult._meta) + assertNull(listPromptsResult.meta) val prompts = listPromptsResult.prompts @@ -45,7 +46,7 @@ class SseServerIntegrationTest { val listResourcesResult = client.listResources() // then - assertEquals(expected = EmptyJsonObject, actual = listResourcesResult._meta) + assertNull(listResourcesResult.meta) val resources = listResourcesResult.resources assertEquals(expected = listOf("Web Search"), actual = resources.map { it.name }) @@ -55,11 +56,11 @@ class SseServerIntegrationTest { fun `should get resource`(): Unit = runBlocking { val testResourceUri = "https://search.com/" val getResourcesResult = client.readResource( - ReadResourceRequest(uri = testResourceUri), + ReadResourceRequest(ReadResourceRequestParams(uri = testResourceUri)), ) // then - assertEquals(expected = EmptyJsonObject, actual = getResourcesResult._meta) + assertEquals(expected = null, actual = getResourcesResult.meta) val contents = getResourcesResult.contents assertEquals(expected = 1, actual = contents.size) assertTrue { @@ -72,11 +73,14 @@ class SseServerIntegrationTest { @Test fun `should call tool`(): Unit = runBlocking { // when - val toolResult = client.callTool("kotlin-sdk-tool", EmptyJsonObject) + val toolResult = client.callTool( + name = "kotlin-sdk-tool", + arguments = emptyMap(), + ) // then assertNotNull(toolResult) - assertEquals(expected = EmptyJsonObject, actual = toolResult._meta) + assertNull(toolResult.meta) val content = toolResult.content.single() assertIs(content, "Tool result should be a text content")