Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.modelcontextprotocol.kotlin.sdk.integration.kotlin

import io.kotest.assertions.json.shouldEqualJson
import io.modelcontextprotocol.kotlin.sdk.ExperimentalMcpApi
import io.modelcontextprotocol.kotlin.sdk.types.CallToolRequest
import io.modelcontextprotocol.kotlin.sdk.types.CallToolRequestParams
import io.modelcontextprotocol.kotlin.sdk.types.CallToolResult
Expand All @@ -9,6 +10,7 @@ import io.modelcontextprotocol.kotlin.sdk.types.ImageContent
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
import io.modelcontextprotocol.kotlin.sdk.types.ToolSchema
import io.modelcontextprotocol.kotlin.sdk.types.buildCallToolResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
Expand All @@ -28,6 +30,7 @@ import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue

@OptIn(ExperimentalMcpApi::class)
abstract class AbstractToolIntegrationTest : KotlinTestBase() {
private val testToolName = "echo"
private val testToolDescription = "A simple echo tool that returns the input text"
Expand Down Expand Up @@ -84,12 +87,12 @@ abstract class AbstractToolIntegrationTest : KotlinTestBase() {
) { request ->
val text = (request.params.arguments?.get("text") as? JsonPrimitive)?.content ?: "No text provided"

CallToolResult(
content = listOf(TextContent(text = "Echo: $text")),
structuredContent = buildJsonObject {
buildCallToolResult {
textContent("Echo: $text")
structuredContent {
put("result", text)
},
)
}
}
}
}

Expand All @@ -112,12 +115,12 @@ abstract class AbstractToolIntegrationTest : KotlinTestBase() {
) { request ->
val text = (request.params.arguments?.get("text") as? JsonPrimitive)?.content ?: "No text provided"

CallToolResult(
content = listOf(TextContent(text = "Echo: $text")),
structuredContent = buildJsonObject {
buildCallToolResult {
textContent("Echo: $text")
structuredContent {
put("result", text)
},
)
}
}
}

server.addTool(
Expand Down Expand Up @@ -164,9 +167,7 @@ abstract class AbstractToolIntegrationTest : KotlinTestBase() {
val delay = (request.params.arguments?.get("delay") as? JsonPrimitive)?.content?.toIntOrNull() ?: 1000

// simulate slow operation
runBlocking {
delay(delay.toLong())
}
delay(delay.toLong())

CallToolResult(
content = listOf(TextContent(text = "Completed after ${delay}ms delay")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import io.ktor.server.routing.delete
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
import io.modelcontextprotocol.kotlin.sdk.ExperimentalMcpApi
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.shared.AbstractTransport
import io.modelcontextprotocol.kotlin.sdk.shared.TransportSendOptions
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.JSONRPCError
Expand All @@ -40,6 +40,7 @@ import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
import io.modelcontextprotocol.kotlin.sdk.types.TextResourceContents
import io.modelcontextprotocol.kotlin.sdk.types.ToolSchema
import io.modelcontextprotocol.kotlin.sdk.types.buildCallToolResult
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.channels.Channel
Expand All @@ -59,6 +60,7 @@ import java.util.concurrent.ConcurrentHashMap

private val logger = KotlinLogging.logger {}

@OptIn(ExperimentalMcpApi::class)
class KotlinServerForTsClient {
private val serverTransports = ConcurrentHashMap<String, HttpServerTransport>()
private val jsonFormat = Json { ignoreUnknownKeys = true }
Expand Down Expand Up @@ -226,12 +228,12 @@ class KotlinServerForTsClient {
),
) { request ->
val name = (request.params.arguments?.get("name") as? JsonPrimitive)?.content ?: "World"
CallToolResult(
content = listOf(TextContent("Hello, $name!")),
structuredContent = buildJsonObject {
buildCallToolResult {
textContent("Hello, $name!")
structuredContent {
put("greeting", JsonPrimitive("Hello, $name!"))
},
)
}
}
}

server.addTool(
Expand All @@ -252,13 +254,13 @@ class KotlinServerForTsClient {
) { request ->
val name = (request.params.arguments?.get("name") as? JsonPrimitive)?.content ?: "World"

CallToolResult(
content = listOf(TextContent("Multiple greetings sent to $name!")),
structuredContent = buildJsonObject {
buildCallToolResult {
textContent("Multiple greetings sent to $name!")
structuredContent {
put("greeting", JsonPrimitive("Multiple greetings sent to $name!"))
put("notificationCount", JsonPrimitive(3))
},
)
}
}
}

server.addPrompt(
Expand Down
Loading
Loading