samples: update mcp-kotlin to 0.10.0 across sample projects (#645)

## Update mcp-kotlin to 0.10.0 across sample projects

## How Has This Been Tested?
Locally, added ServerIntegrationTest to simple-streamable-server

## Breaking Changes
No

## Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [x] Documentation update
- [x] Test update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed
This commit is contained in:
Konstantin Pavlov 2026-03-30 23:47:31 +03:00 • committed by GitHub
commit ad072325c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 453 additions and 233 deletions

View file

@ -2,7 +2,7 @@
anthropic = "2.18.0" anthropic = "2.18.0"
kotlin = "2.2.21" kotlin = "2.2.21"
ktor = "3.2.3" ktor = "3.2.3"
mcp-kotlin = "0.9.0" mcp-kotlin = "0.10.0"
shadow = "9.4.1" shadow = "9.4.1"
slf4j = "2.0.17" slf4j = "2.0.17"

File diff suppressed because one or more lines are too long

View file

@ -22,6 +22,15 @@ dependencies {
implementation(libs.ktor.server.sse) implementation(libs.ktor.server.sse)
implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.slf4j.simple) implementation(libs.slf4j.simple)
testImplementation(libs.mcp.kotlin.client)
testImplementation(libs.ktor.client.cio)
testImplementation(libs.junit.jupiter)
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
} }
kotlin { kotlin {

View file

@ -1,7 +1,8 @@
[versions] [versions]
kotlin = "2.2.21" kotlin = "2.2.21"
ktor = "3.2.3" ktor = "3.2.3"
mcp-kotlin = "0.9.0" junit = "6.0.3"
mcp-kotlin = "0.10.0"
slf4j = "2.0.17" slf4j = "2.0.17"
shadow = "9.4.1" shadow = "9.4.1"
@ -13,7 +14,10 @@ ktor-server-content-negotiation = { group = "io.ktor", name = "ktor-server-conte
ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json" } ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json" }
ktor-server-auth = { group = "io.ktor", name = "ktor-server-auth" } ktor-server-auth = { group = "io.ktor", name = "ktor-server-auth" }
ktor-server-sse = { group = "io.ktor", name = "ktor-server-sse" } ktor-server-sse = { group = "io.ktor", name = "ktor-server-sse" }
mcp-kotlin-client = { group = "io.modelcontextprotocol", name = "kotlin-sdk-client", version.ref = "mcp-kotlin" }
mcp-kotlin-server = { group = "io.modelcontextprotocol", name = "kotlin-sdk-server", version.ref = "mcp-kotlin" } mcp-kotlin-server = { group = "io.modelcontextprotocol", name = "kotlin-sdk-server", version.ref = "mcp-kotlin" }
ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio" }
junit-jupiter = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" }
slf4j-simple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" } slf4j-simple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" }
[plugins] [plugins]

View file

@ -0,0 +1,146 @@
package io.modelcontextprotocol.sample.server
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.plugins.sse.SSE
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import io.modelcontextprotocol.kotlin.sdk.client.Client
import io.modelcontextprotocol.kotlin.sdk.client.mcpStreamableHttp
import io.modelcontextprotocol.kotlin.sdk.types.GetPromptRequest
import io.modelcontextprotocol.kotlin.sdk.types.GetPromptRequestParams
import io.modelcontextprotocol.kotlin.sdk.types.ReadResourceRequest
import io.modelcontextprotocol.kotlin.sdk.types.ReadResourceRequestParams
import io.modelcontextprotocol.kotlin.sdk.types.Role
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
import io.modelcontextprotocol.kotlin.sdk.types.TextResourceContents
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertNotNull
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ServerIntegrationTest {
private val server = embeddedServer(Netty, host = "127.0.0.1", port = 0) {
configureServer()
}
private val httpClient = HttpClient(CIO) {
install(SSE)
}
private lateinit var mcpClient: Client
@BeforeAll
suspend fun beforeAll() {
server.start(wait = false)
val port = server.engine.resolvedConnectors().single().port
mcpClient = httpClient.mcpStreamableHttp(
url = "http://127.0.0.1:$port/mcp",
)
}
@AfterAll
suspend fun afterAll() {
mcpClient.close()
httpClient.close()
server.stop(500, 1000)
}
@Test
fun `should negotiate server capabilities`() {
val capabilities = mcpClient.serverCapabilities
assertNotNull(capabilities)
assertNotNull(capabilities.tools)
assertNotNull(capabilities.prompts)
assertNotNull(capabilities.resources)
assertNotNull(capabilities.logging)
}
@Test
fun `should report server version`() {
val version = mcpClient.serverVersion
assertNotNull(version)
assertEquals("simple-streamable-http-server", version.name)
assertEquals("1.0.0", version.version)
}
@Test
suspend fun `should list tools`() {
val result = mcpClient.listTools()
val toolNames = result.tools.map { it.name }.sorted()
assertEquals(listOf("greet", "multi-greet"), toolNames)
}
@Test
suspend fun `should call greet tool`() {
val result = mcpClient.callTool(name = "greet", arguments = mapOf("name" to "Alice"))
val content = result.content.single()
assertIs<TextContent>(content)
assertEquals("Hello, Alice!", content.text)
}
@Test
suspend fun `should call greet tool with default name`() {
val result = mcpClient.callTool(name = "greet", arguments = emptyMap())
val content = result.content.single()
assertIs<TextContent>(content)
assertEquals("Hello, World!", content.text)
}
@Test
suspend fun `should call multi-greet tool with logging notifications`() {
val result = mcpClient.callTool(name = "multi-greet", arguments = mapOf("name" to "Bob"))
val content = result.content.single()
assertIs<TextContent>(content)
assertEquals("Good morning, Bob!", content.text)
}
@Test
suspend fun `should list prompts`() {
val result = mcpClient.listPrompts()
assertEquals(listOf("greeting-template"), result.prompts.map { it.name })
}
@Test
suspend fun `should get greeting template prompt`() {
val result = mcpClient.getPrompt(
GetPromptRequest(
GetPromptRequestParams(
name = "greeting-template",
arguments = mapOf("name" to "Charlie"),
),
),
)
val message = result.messages.single()
assertEquals(Role.User, message.role)
val content = message.content
assertIs<TextContent>(content)
assertEquals("Please greet Charlie in a friendly manner.", content.text)
}
@Test
suspend fun `should list resources`() {
val result = mcpClient.listResources()
assertEquals(listOf("Default Greeting"), result.resources.map { it.name })
}
@Test
suspend fun `should read default greeting resource`() {
val result = mcpClient.readResource(
ReadResourceRequest(
ReadResourceRequestParams(uri = "https://example.com/greetings/default"),
),
)
val content = result.contents.single()
assertIs<TextResourceContents>(content)
assertEquals("Hello, world!", content.text)
assertEquals("text/plain", content.mimeType)
}
}

View file

@ -0,0 +1,6 @@
org.slf4j.simpleLogger.defaultLogLevel=INFO
org.slf4j.simpleLogger.showThreadName=true
org.slf4j.simpleLogger.showDateTime=false
# Log level for specific packages or classes
org.slf4j.simpleLogger.log.io.modelcontextprotocol.sample.server=DEBUG