Skip to content

Commit f821629

Browse files
committed
bump multiple dependencies to latest stable versions, including Kotlin, Vaadin, and Ktor, and update related configurations across projects
1 parent e87412b commit f821629

File tree

10 files changed

+128
-128
lines changed

10 files changed

+128
-128
lines changed

projects/mcp/brave/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ repositories {
99

1010
dependencies {
1111
implementation(libs.mcp.kotlin)
12+
implementation(libs.ktor.server.cio)
1213
implementation(libs.slf4j)
1314
}
1415

projects/mcp/brave/gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
[versions]
55
kotlin = "2.2.21"
66
mcp = "0.8.0"
7+
ktor = "3.3.3"
78
slf4j = "2.0.9"
89

910
[libraries]
1011
mcp-kotlin = { group = "io.modelcontextprotocol", name = "kotlin-sdk", version.ref = "mcp" }
12+
ktor-server-cio = { group = "io.ktor", name = "ktor-server-cio", version.ref = "ktor" }
1113
slf4j = { group = "org.slf4j", name = "slf4j-nop", version.ref = "slf4j"}
1214

1315
[plugins]

projects/mcp/brave/src/main/kotlin/io/github/devcrocod/example/main.kt

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
package io.github.devcrocod.example
22

3-
import io.ktor.server.application.Application
4-
import io.ktor.server.cio.CIO
5-
import io.ktor.server.engine.embeddedServer
6-
import io.ktor.server.request.receiveText
7-
import io.ktor.server.response.respondText
8-
import io.ktor.server.routing.post
9-
import io.ktor.server.routing.routing
10-
import io.modelcontextprotocol.kotlin.sdk.Implementation
3+
import io.ktor.server.application.*
4+
import io.ktor.server.cio.*
5+
import io.ktor.server.engine.*
6+
import io.ktor.server.request.*
7+
import io.ktor.server.response.*
8+
import io.ktor.server.routing.*
119
import io.modelcontextprotocol.kotlin.sdk.client.Client
1210
import io.modelcontextprotocol.kotlin.sdk.client.StdioClientTransport
11+
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
1312
import kotlinx.coroutines.runBlocking
1413
import kotlinx.io.asSink
1514
import kotlinx.io.asSource
@@ -58,7 +57,7 @@ fun Application.module() {
5857
logger.info("The following question has been received: $question")
5958

6059
// Request a list of available tools from the server.
61-
val tools = runBlocking { client.listTools()?.tools } ?: emptyList()
60+
val tools = client.listTools().tools
6261
if (tools.isEmpty()) {
6362
call.respondText("Tools not found")
6463
return@post
@@ -68,8 +67,8 @@ fun Application.module() {
6867
val toolName = tools.first().name
6968

7069
// Call the tool, passing the "query" field with the question text as an argument
71-
val toolResult = runBlocking { client.callTool(toolName, mapOf("query" to question)) }
72-
val resultContent = toolResult?.content?.toString() ?: "No result"
70+
val toolResult = client.callTool(toolName, mapOf("query" to question))
71+
val resultContent = toolResult.content.toString()
7372

7473
// Returning the result to the client
7574
call.respondText(resultContent)

projects/mcp/mcp-demo/composeApp/src/desktopMain/kotlin/io/github/devcrocod/MCPClient.kt

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,15 @@ import com.openai.client.OpenAIClient
44
import com.openai.client.okhttp.OpenAIOkHttpClient
55
import com.openai.core.JsonValue
66
import com.openai.models.*
7-
import com.openai.models.chat.completions.ChatCompletionAssistantMessageParam
8-
import com.openai.models.chat.completions.ChatCompletionCreateParams
9-
import com.openai.models.chat.completions.ChatCompletionMessageParam
10-
import com.openai.models.chat.completions.ChatCompletionSystemMessageParam
11-
import com.openai.models.chat.completions.ChatCompletionTool
12-
import com.openai.models.chat.completions.ChatCompletionUserMessageParam
7+
import com.openai.models.chat.completions.*
138
import io.ktor.client.*
149
import io.ktor.client.plugins.contentnegotiation.*
1510
import io.ktor.client.plugins.sse.*
1611
import io.ktor.serialization.kotlinx.json.*
17-
import io.modelcontextprotocol.kotlin.sdk.Implementation
18-
import io.modelcontextprotocol.kotlin.sdk.Tool
1912
import io.modelcontextprotocol.kotlin.sdk.client.Client
2013
import io.modelcontextprotocol.kotlin.sdk.client.mcpSse
14+
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
15+
import io.modelcontextprotocol.kotlin.sdk.types.Tool
2116
import kotlinx.coroutines.runBlocking
2217
import kotlinx.serialization.json.Json
2318
import kotlin.jvm.optionals.getOrNull
@@ -31,7 +26,7 @@ import kotlin.jvm.optionals.getOrNull
3126
*/
3227
private fun List<Tool>.toListChatCompletionTools(): List<ChatCompletionTool> {
3328
return this.map { tool ->
34-
ChatCompletionTool.builder()
29+
val functionTool = ChatCompletionFunctionTool.builder()
3530
.function(
3631
FunctionDefinition.builder()
3732
.name(tool.name)
@@ -46,6 +41,7 @@ private fun List<Tool>.toListChatCompletionTools(): List<ChatCompletionTool> {
4641
.build()
4742
)
4843
.build()
44+
ChatCompletionTool.ofFunction(functionTool)
4945
}
5046
}
5147

@@ -86,9 +82,9 @@ class MCPClient : AutoCloseable {
8682
println("Connected to the MCP server: ${mcpClient.serverVersion}")
8783

8884
// Getting a list of available tools
89-
val tools = mcpClient.listTools()?.tools
90-
availableTools = tools?.toListChatCompletionTools() ?: emptyList()
91-
println("Available tools: ${tools?.map { it.name } ?: "No tools found"}")
85+
val tools = mcpClient.listTools().tools
86+
availableTools = tools.toListChatCompletionTools()
87+
println("Available tools: ${tools.map { it.name }}")
9288
}
9389

9490
/**
@@ -136,8 +132,9 @@ class MCPClient : AutoCloseable {
136132
}
137133
// Process any tool calls returned by the assistant
138134
for (toolCall in choice.message().toolCalls().getOrNull() ?: emptyList()) {
139-
val toolName = toolCall.function().name()
140-
val args = Json {}.decodeFromString<Map<String, String>>(toolCall.function().arguments())
135+
val functionToolCall = toolCall.asFunction()
136+
val toolName = functionToolCall.function().name()
137+
val args = Json {}.decodeFromString<Map<String, String>>(functionToolCall.function().arguments())
141138

142139
// Call the MCP tool with parsed arguments
143140
val result = mcpClient.callTool(toolName, args)
@@ -160,8 +157,8 @@ class MCPClient : AutoCloseable {
160157
.content(
161158
"""
162159
"type": "tool_result",
163-
"tool_use_id": ${toolCall.id()},
164-
"result": ${result?.content?.joinToString()}
160+
"tool_use_id": ${functionToolCall.id()},
161+
"result": ${result.content.joinToString()}
165162
""".trimIndent()
166163
)
167164
.build()

projects/mcp/mcp-demo/gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle
1919
kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" }
2020
mcp-kotlin = { group = "io.modelcontextprotocol", name = "kotlin-sdk", version.ref = "mcp" }
2121
slf4j = { group = "org.slf4j", name = "slf4j-nop", version.ref = "slf4j" }
22+
ktor-server-cio = { group = "io.ktor", name = "ktor-server-cio", version.ref = "ktor" }
2223
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
2324
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
2425
ktor-serialization = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }

projects/mcp/mcp-demo/server/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies {
1717
implementation(libs.ktor.client.content.negotation)
1818
implementation(libs.ktor.serialization)
1919
implementation(libs.ktor.client.logging)
20+
implementation(libs.ktor.server.cio)
2021
}
2122

2223
java {

projects/mcp/mcp-demo/server/src/main/kotlin/io/github/devcrocod/example/server.kt

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@ import io.ktor.serialization.kotlinx.json.*
99
import io.ktor.server.application.*
1010
import io.ktor.server.cio.*
1111
import io.ktor.server.engine.*
12+
import io.ktor.server.response.*
1213
import io.ktor.server.routing.*
1314
import io.ktor.server.sse.*
1415
import io.ktor.util.collections.*
1516
import io.ktor.utils.io.streams.*
16-
import io.modelcontextprotocol.kotlin.sdk.*
17-
import io.modelcontextprotocol.kotlin.sdk.server.Server
18-
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
19-
import io.modelcontextprotocol.kotlin.sdk.server.SseServerTransport
20-
import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport
17+
import io.modelcontextprotocol.kotlin.sdk.server.*
18+
import io.modelcontextprotocol.kotlin.sdk.types.*
2119
import kotlinx.coroutines.Job
2220
import kotlinx.coroutines.runBlocking
2321
import kotlinx.io.asSink
@@ -75,17 +73,14 @@ fun configureServer(): Server {
7573
For example, an investor may want to use the full-quote quote endpoint to get a sense of what a stock is trading at before placing a trade.
7674
Or, an investor may want to use the full-quote quote endpoint to track the performance of a stock over time.
7775
""".trimIndent(),
78-
inputSchema = Tool.Input(
76+
inputSchema = ToolSchema(
7977
properties = JsonObject(mapOf("symbol" to JsonPrimitive("string"))),
8078
required = listOf("symbol")
8179
)
8280
) { request ->
83-
val symbol = request.arguments["symbol"]
84-
if (symbol == null) {
85-
return@addTool CallToolResult(
86-
content = listOf(TextContent("The 'symbol' parameter is required."))
87-
)
88-
}
81+
val symbol = request.arguments?.get("symbol") ?: return@addTool CallToolResult(
82+
content = listOf(TextContent("The 'symbol' parameter is required."))
83+
)
8984
val price = httpClient.getCurrentPrice(symbol.jsonPrimitive.content)
9085
if (price != null) {
9186
CallToolResult(
@@ -119,7 +114,7 @@ fun configureServer(): Server {
119114
For example, an investor might look for stocks that are in an uptrend or a downtrend.
120115
Investors can also use the FMP Daily Chart endpoint to identify support and resistance levels.
121116
""".trimIndent(),
122-
inputSchema = Tool.Input(
117+
inputSchema = ToolSchema(
123118
properties = JsonObject(
124119
mapOf(
125120
"symbol" to JsonPrimitive("string"),
@@ -130,9 +125,9 @@ fun configureServer(): Server {
130125
required = listOf("symbol")
131126
)
132127
) { request ->
133-
val symbol = request.arguments["symbol"]
134-
val from = request.arguments["from"]?.jsonPrimitive?.contentOrNull
135-
val to = request.arguments["to"]?.jsonPrimitive?.contentOrNull
128+
val symbol = request.arguments?.get("symbol")
129+
val from = request.arguments?.get("from")?.jsonPrimitive?.contentOrNull
130+
val to = request.arguments?.get("to")?.jsonPrimitive?.contentOrNull
136131
if (symbol == null) {
137132
return@addTool CallToolResult(
138133
content = listOf(TextContent("The 'symbol' parameter is required."))
@@ -177,7 +172,7 @@ fun `run mcp server using stdio`() {
177172
)
178173

179174
runBlocking {
180-
server.connect(transport)
175+
server.createSession(transport)
181176
val done = Job()
182177
server.onClose {
183178
done.complete()
@@ -194,28 +189,32 @@ fun `run mcp server using stdio`() {
194189
* @param port The port number on which the SSE server should be started.
195190
*/
196191
fun `run sse mcp server`(port: Int): Unit = runBlocking {
197-
val servers = ConcurrentMap<String, Server>()
192+
val serverSessions = ConcurrentMap<String, ServerSession>()
198193

199194
val server = configureServer()
200-
embeddedServer(CIO, host = "0.0.0.0", port = port) {
195+
196+
embeddedServer(CIO, host = "127.0.0.1", port = port) {
201197
install(SSE)
202198
routing {
203199
sse("/sse") {
204200
val transport = SseServerTransport("/message", this)
205-
206-
servers[transport.sessionId] = server
201+
val serverSession = server.createSession(transport)
202+
serverSessions[transport.sessionId] = serverSession
207203

208204
server.onClose {
209-
servers.remove(transport.sessionId)
205+
serverSessions.remove(transport.sessionId)
210206
}
211-
212-
server.connect(transport)
213207
}
214208
post("/message") {
215-
val sessionId: String = call.request.queryParameters["sessionId"]!!
216-
val transport = servers[sessionId]?.transport as? SseServerTransport
209+
val sessionId = call.request.queryParameters["sessionId"]
210+
if (sessionId == null) {
211+
call.respond(HttpStatusCode.BadRequest, "Missing sessionId parameter")
212+
return@post
213+
}
214+
215+
val transport = serverSessions[sessionId]?.transport as? SseServerTransport
217216
if (transport == null) {
218-
call.respond("Session not found", null)
217+
call.respond(HttpStatusCode.NotFound, "Session not found")
219218
return@post
220219
}
221220

0 commit comments

Comments
 (0)