Skip to content

Commit 6803c11

Browse files
alpeshalpesh
authored andcommitted
build success
1 parent 63288ea commit 6803c11

File tree

12 files changed

+1050
-31
lines changed

12 files changed

+1050
-31
lines changed

.idea/artifacts/kotlin_sdk_jvm_0_4_0.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/kotlin-sdk.api

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2730,6 +2730,18 @@ public final class io/modelcontextprotocol/kotlin/sdk/server/KtorServerKt {
27302730
public static final fun mcp (Lio/ktor/server/routing/Routing;Lkotlin/jvm/functions/Function0;)V
27312731
}
27322732

2733+
public abstract interface annotation class io/modelcontextprotocol/kotlin/sdk/server/McpParam : java/lang/annotation/Annotation {
2734+
public abstract fun description ()Ljava/lang/String;
2735+
public abstract fun required ()Z
2736+
public abstract fun type ()Ljava/lang/String;
2737+
}
2738+
2739+
public abstract interface annotation class io/modelcontextprotocol/kotlin/sdk/server/McpTool : java/lang/annotation/Annotation {
2740+
public abstract fun description ()Ljava/lang/String;
2741+
public abstract fun name ()Ljava/lang/String;
2742+
public abstract fun required ()[Ljava/lang/String;
2743+
}
2744+
27332745
public final class io/modelcontextprotocol/kotlin/sdk/server/RegisteredPrompt {
27342746
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/Prompt;Lkotlin/jvm/functions/Function2;)V
27352747
public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/Prompt;
@@ -2792,7 +2804,7 @@ public class io/modelcontextprotocol/kotlin/sdk/server/Server : io/modelcontextp
27922804
public static synthetic fun listRoots$default (Lio/modelcontextprotocol/kotlin/sdk/server/Server;Lkotlinx/serialization/json/JsonObject;Lio/modelcontextprotocol/kotlin/sdk/shared/RequestOptions;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
27932805
public fun onClose ()V
27942806
public final fun onClose (Lkotlin/jvm/functions/Function0;)V
2795-
public final fun onInitalized (Lkotlin/jvm/functions/Function0;)V
2807+
public final fun onInitialized (Lkotlin/jvm/functions/Function0;)V
27962808
public final fun ping (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
27972809
public final fun sendLoggingMessage (Lio/modelcontextprotocol/kotlin/sdk/LoggingMessageNotification;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
27982810
public final fun sendPromptListChanged (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
@@ -2801,6 +2813,10 @@ public class io/modelcontextprotocol/kotlin/sdk/server/Server : io/modelcontextp
28012813
public final fun sendToolListChanged (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
28022814
}
28032815

2816+
public final class io/modelcontextprotocol/kotlin/sdk/server/ServerAnnotationsKt {
2817+
public static final fun registerToolFromAnnotatedFunction (Lio/modelcontextprotocol/kotlin/sdk/server/Server;Ljava/lang/Object;Lkotlin/reflect/KFunction;Lio/modelcontextprotocol/kotlin/sdk/server/McpTool;)V
2818+
}
2819+
28042820
public final class io/modelcontextprotocol/kotlin/sdk/server/ServerOptions : io/modelcontextprotocol/kotlin/sdk/shared/ProtocolOptions {
28052821
public fun <init> (Lio/modelcontextprotocol/kotlin/sdk/ServerCapabilities;Z)V
28062822
public synthetic fun <init> (Lio/modelcontextprotocol/kotlin/sdk/ServerCapabilities;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V

build.gradle.kts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
55
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
66
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
77
import org.jreleaser.model.Active
8+
import org.gradle.jvm.toolchain.JavaLanguageVersion
89

910
plugins {
1011
alias(libs.plugins.kotlin.multiplatform)
@@ -197,7 +198,9 @@ kotlin {
197198

198199
explicitApi = ExplicitApiMode.Strict
199200

200-
jvmToolchain(21)
201+
jvmToolchain {
202+
languageVersion = JavaLanguageVersion.of(17) // Downgrade to JDK 17 which is more likely to be available
203+
}
201204

202205
sourceSets {
203206
commonMain {
@@ -210,6 +213,7 @@ kotlin {
210213
api(libs.ktor.server.websockets)
211214

212215
implementation(libs.kotlin.logging)
216+
implementation(libs.kotlin.reflect)
213217
}
214218
}
215219

@@ -220,6 +224,7 @@ kotlin {
220224
implementation(libs.kotlinx.coroutines.test)
221225
implementation(libs.kotlinx.coroutines.debug)
222226
implementation(libs.kotest.assertions.json)
227+
implementation(libs.kotlin.reflect)
223228
}
224229
}
225230

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ kotest = "5.9.1"
1919
# Kotlinx libraries
2020
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" }
2121
kotlin-logging = { group = "io.github.oshai", name = "kotlin-logging", version.ref = "logging" }
22+
kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" }
2223

2324
# Ktor
2425
ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktor" }

samples/weather-stdio-server/README.md

Lines changed: 72 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@ java -jar build/libs/<your-jar-name>.jar
4545
4646
## Tool Implementation
4747

48-
The project registers two MCP tools using the Kotlin MCP SDK. Below is an overview of the core tool implementations:
48+
The project provides two different approaches to register MCP tools using the Kotlin MCP SDK:
4949

50-
### 1. Weather Forecast Tool
50+
### Traditional Approach
5151

52-
This tool fetches the weather forecast for a specific latitude and longitude using the `weather.gov` API.
52+
The traditional approach uses the `addTool` method to register tools with explicit schema definitions.
5353

54-
Example tool registration in Kotlin:
54+
#### 1. Weather Forecast Tool
5555

5656
```kotlin
5757
server.addTool(
@@ -60,24 +60,22 @@ server.addTool(
6060
Get weather forecast for a specific latitude/longitude
6161
""".trimIndent(),
6262
inputSchema = Tool.Input(
63-
properties = JsonObject(
64-
mapOf(
65-
"latitude" to JsonObject(mapOf("type" to JsonPrimitive("number"))),
66-
"longitude" to JsonObject(mapOf("type" to JsonPrimitive("number"))),
67-
)
68-
),
63+
properties = buildJsonObject {
64+
putJsonObject("latitude") {
65+
put("type", "number")
66+
}
67+
putJsonObject("longitude") {
68+
put("type", "number")
69+
}
70+
},
6971
required = listOf("latitude", "longitude")
7072
)
7173
) { request ->
7274
// Implementation tool
7375
}
7476
```
7577

76-
### 2. Weather Alerts Tool
77-
78-
This tool retrieves active weather alerts for a US state.
79-
80-
Example tool registration in Kotlin:
78+
#### 2. Weather Alerts Tool
8179

8280
```kotlin
8381
server.addTool(
@@ -86,23 +84,72 @@ server.addTool(
8684
Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)
8785
""".trimIndent(),
8886
inputSchema = Tool.Input(
89-
properties = JsonObject(
90-
mapOf(
91-
"state" to JsonObject(
92-
mapOf(
93-
"type" to JsonPrimitive("string"),
94-
"description" to JsonPrimitive("Two-letter US state code (e.g. CA, NY)")
95-
)
96-
),
97-
)
98-
),
87+
properties = buildJsonObject {
88+
putJsonObject("state") {
89+
put("type", "string")
90+
put("description", "Two-letter US state code (e.g. CA, NY)")
91+
}
92+
},
9993
required = listOf("state")
10094
)
10195
) { request ->
10296
// Implementation tool
10397
}
10498
```
10599

100+
### Annotation-Based Approach
101+
102+
The project also demonstrates an alternative, more idiomatic approach using Kotlin annotations. This approach simplifies tool definition by leveraging Kotlin's type system and reflection.
103+
104+
To use the annotation-based approach, run the server with:
105+
```shell
106+
java -jar build/libs/<your-jar-name>.jar --use-annotations
107+
```
108+
109+
#### Tool implementation with annotations:
110+
111+
```kotlin
112+
class WeatherToolsAnnotated(private val httpClient: HttpClient) {
113+
114+
@McpTool(
115+
name = "get_alerts",
116+
description = "Get weather alerts for a US state"
117+
)
118+
suspend fun getAlerts(
119+
@McpParam(
120+
description = "Two-letter US state code (e.g. CA, NY)",
121+
type = "string"
122+
) state: String
123+
): CallToolResult {
124+
// Implementation
125+
}
126+
127+
@McpTool(
128+
name = "get_forecast",
129+
description = "Get weather forecast for a specific latitude/longitude"
130+
)
131+
suspend fun getForecast(
132+
@McpParam(description = "The latitude coordinate") latitude: Double,
133+
@McpParam(description = "The longitude coordinate") longitude: Double
134+
): CallToolResult {
135+
// Implementation
136+
}
137+
}
138+
```
139+
140+
Then register the tools using:
141+
142+
```kotlin
143+
val weatherTools = WeatherToolsAnnotated(httpClient)
144+
server.registerAnnotatedTools(weatherTools)
145+
```
146+
147+
This approach provides several benefits:
148+
- More idiomatic Kotlin code
149+
- Parameter types are automatically inferred from Kotlin's type system
150+
- Reduced boilerplate for tool registration
151+
- Better IDE support with autocompletion and compile-time checking
152+
106153
## Client Integration
107154

108155
### Kotlin Client Example
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package io.modelcontextprotocol.sample.server
2+
3+
import io.ktor.client.*
4+
import io.ktor.client.plugins.*
5+
import io.ktor.client.plugins.contentnegotiation.*
6+
import io.ktor.http.*
7+
import io.ktor.serialization.kotlinx.json.*
8+
import io.modelcontextprotocol.kotlin.sdk.*
9+
import io.modelcontextprotocol.kotlin.sdk.server.Server
10+
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
11+
import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport
12+
import io.modelcontextprotocol.kotlin.sdk.server.registerAnnotatedTools
13+
import kotlinx.coroutines.Job
14+
import kotlinx.coroutines.runBlocking
15+
import kotlinx.io.asSink
16+
import kotlinx.io.buffered
17+
import kotlinx.serialization.json.*
18+
19+
/**
20+
* Alternative implementation of the Weather MCP server using annotations.
21+
* This demonstrates how to use @McpTool annotations to simplify tool registration.
22+
*/
23+
fun `run annotated mcp server`() {
24+
// Base URL for the Weather API
25+
val baseUrl = "https://api.weather.gov"
26+
27+
// Create an HTTP client with a default request configuration and JSON content negotiation
28+
val httpClient = HttpClient {
29+
defaultRequest {
30+
url(baseUrl)
31+
headers {
32+
append("Accept", "application/geo+json")
33+
append("User-Agent", "WeatherApiClient/1.0")
34+
}
35+
contentType(ContentType.Application.Json)
36+
}
37+
// Install content negotiation plugin for JSON serialization/deserialization
38+
install(ContentNegotiation) {
39+
json(Json {
40+
ignoreUnknownKeys = true
41+
prettyPrint = true
42+
})
43+
}
44+
}
45+
46+
// Create the MCP Server instance
47+
val server = Server(
48+
Implementation(
49+
name = "weather-annotated",
50+
version = "1.0.0"
51+
),
52+
ServerOptions(
53+
capabilities = ServerCapabilities(tools = ServerCapabilities.Tools(listChanged = true))
54+
)
55+
)
56+
57+
// Create an instance of our annotated tools class
58+
val weatherTools = WeatherToolsAnnotated(httpClient)
59+
60+
// Register all annotated tools from the weatherTools instance
61+
server.registerAnnotatedTools(weatherTools)
62+
63+
// Create a transport using standard IO for server communication
64+
val transport = StdioServerTransport(
65+
System.`in`.asInput(),
66+
System.out.asSink().buffered()
67+
)
68+
69+
runBlocking {
70+
server.connect(transport)
71+
val done = Job()
72+
server.onClose {
73+
done.complete()
74+
}
75+
done.join()
76+
}
77+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package io.modelcontextprotocol.sample.server
2+
3+
import io.ktor.client.*
4+
import io.modelcontextprotocol.kotlin.sdk.CallToolResult
5+
import io.modelcontextprotocol.kotlin.sdk.TextContent
6+
import io.modelcontextprotocol.kotlin.sdk.server.McpParam
7+
import io.modelcontextprotocol.kotlin.sdk.server.McpTool
8+
import io.modelcontextprotocol.kotlin.sdk.server.registerAnnotatedTools
9+
10+
/**
11+
* Example class demonstrating the use of McpTool annotations.
12+
*/
13+
class WeatherToolsAnnotated(private val httpClient: HttpClient) {
14+
15+
/**
16+
* Gets weather alerts for a specified US state using the @McpTool annotation.
17+
*/
18+
@McpTool(
19+
name = "get_alerts",
20+
description = "Get weather alerts for a US state"
21+
)
22+
suspend fun getAlerts(
23+
@McpParam(
24+
description = "Two-letter US state code (e.g. CA, NY)",
25+
type = "string"
26+
) state: String
27+
): CallToolResult {
28+
if (state.isEmpty()) {
29+
return CallToolResult(
30+
content = listOf(TextContent("The 'state' parameter is required."))
31+
)
32+
}
33+
34+
val alerts = httpClient.getAlerts(state)
35+
return CallToolResult(content = alerts.map { TextContent(it) })
36+
}
37+
38+
/**
39+
* Gets weather forecast for specified coordinates using the @McpTool annotation.
40+
*/
41+
@McpTool(
42+
name = "get_forecast",
43+
description = "Get weather forecast for a specific latitude/longitude"
44+
)
45+
suspend fun getForecast(
46+
@McpParam(description = "The latitude coordinate") latitude: Double,
47+
@McpParam(description = "The longitude coordinate") longitude: Double
48+
): CallToolResult {
49+
val forecast = httpClient.getForecast(latitude, longitude)
50+
return CallToolResult(content = forecast.map { TextContent(it) })
51+
}
52+
53+
/**
54+
* Gets brief weather summary using the @McpTool annotation with default name.
55+
*/
56+
@McpTool(
57+
description = "Get a brief weather summary for a location"
58+
)
59+
suspend fun getWeatherSummary(
60+
@McpParam(description = "City name") city: String,
61+
@McpParam(description = "Temperature unit (celsius/fahrenheit)", required = false) unit: String = "celsius"
62+
): String {
63+
return "Weather summary for $city: Sunny, 25° $unit"
64+
}
65+
}
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
package io.modelcontextprotocol.sample.server
22

3-
fun main() = `run mcp server`()
3+
fun main(args: Array<String>) {
4+
val useAnnotations = args.contains("--use-annotations")
5+
6+
if (useAnnotations) {
7+
println("Starting annotated MCP Weather server...")
8+
`run annotated mcp server`()
9+
} else {
10+
println("Starting traditional MCP Weather server...")
11+
`run mcp server`()
12+
}
13+
}

0 commit comments

Comments
 (0)