Skip to content

Commit 598e314

Browse files
authored
Merge branch 'main' into dependabot/gradle/io.github.oshai-kotlin-logging-7.0.11
2 parents 90aa973 + d9a3fa3 commit 598e314

File tree

20 files changed

+248
-197
lines changed

20 files changed

+248
-197
lines changed

.github/workflows/gradle-publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ name: Release
99

1010
on:
1111
release:
12-
types: [ created ]
12+
types: [ published ]
1313

1414
jobs:
1515
build:
@@ -130,4 +130,4 @@ jobs:
130130
name: jreleaser-logs
131131
path: |
132132
build/jreleaser/trace.log
133-
build/jreleaser/output.properties
133+
build/jreleaser/output.properties
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: Release Client and Server
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
build:
8+
runs-on: macos-latest
9+
environment: release
10+
11+
permissions:
12+
contents: write
13+
packages: write
14+
15+
steps:
16+
- uses: actions/checkout@v5
17+
- name: Set up JDK 21
18+
uses: actions/setup-java@v5
19+
with:
20+
java-version: '21'
21+
distribution: 'temurin'
22+
23+
- name: Setup Gradle
24+
uses: gradle/actions/setup-gradle@v4
25+
26+
- name: Verify publication configuration
27+
run: ./gradlew kotlin-sdk-server:jreleaserConfig kotlin-sdk-client:jreleaserConfig
28+
env:
29+
JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.OSSRH_USERNAME }}
30+
JRELEASER_MAVENCENTRAL_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
31+
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.GPG_PUBLIC_KEY }}
32+
JRELEASER_GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }}
33+
JRELEASER_GPG_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }}
34+
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
35+
36+
- name: Build with Gradle
37+
run: ./gradlew clean kotlin-sdk-server:assemble kotlin-sdk-client:assemble
38+
env:
39+
JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.OSSRH_USERNAME }}
40+
JRELEASER_MAVENCENTRAL_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
41+
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.GPG_PUBLIC_KEY }}
42+
JRELEASER_GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }}
43+
JRELEASER_GPG_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }}
44+
GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }}
45+
SIGNING_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }}
46+
47+
- name: Publish to Maven Central Portal
48+
id: publish
49+
run: ./gradlew kotlin-sdk-server:publish kotlin-sdk-client:publish kotlin-sdk-server:jreleaserFullRelease kotlin-sdk-client:jreleaserFullRelease --info --stacktrace -Djreleaser.verbose=true
50+
env:
51+
JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.OSSRH_USERNAME }}
52+
JRELEASER_MAVENCENTRAL_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
53+
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.GPG_PUBLIC_KEY }}
54+
JRELEASER_GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }}
55+
JRELEASER_GPG_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }}
56+
JRELEASER_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
57+
GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }}
58+
SIGNING_PASSPHRASE: ${{ secrets.SIGNING_PASSPHRASE }}

buildSrc/src/main/kotlin/mcp.jreleaser.gradle.kts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,13 @@ jreleaser {
6363
files = false
6464
}
6565
}
66+
67+
release {
68+
github {
69+
skipRelease = true
70+
skipTag = true
71+
overwrite = false
72+
token = "none"
73+
}
74+
}
6675
}

gradle/libs.versions.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ jreleaser = "1.19.0"
1717
binaryCompatibilityValidatorPlugin = "0.18.1"
1818
slf4j = "2.0.17"
1919
kotest = "5.9.1"
20+
awaitility = "4.3.0"
2021

2122
# Samples
2223
mcp-kotlin = "0.7.0"
@@ -34,6 +35,7 @@ jreleaser-gradle = { module = "org.jreleaser:jreleaser-gradle-plugin", version.r
3435
# Kotlinx libraries
3536
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" }
3637
kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "coroutines" }
38+
kotlinx-coroutines-core-wasm = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core-wasm-js", version.ref = "coroutines" }
3739
kotlinx-io-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-io-core", version.ref = "kotlinx-io" }
3840
kotlinx-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "collections-immutable" }
3941
kotlin-logging = { group = "io.github.oshai", name = "kotlin-logging", version.ref = "logging" }
@@ -45,11 +47,12 @@ ktor-server-websockets = { group = "io.ktor", name = "ktor-server-websockets", v
4547
ktor-server-core = { group = "io.ktor", name = "ktor-server-core", version.ref = "ktor" }
4648

4749
# Testing
50+
awaitility = { group = "org.awaitility", name = "awaitility-kotlin", version.ref = "awaitility" }
51+
kotest-assertions-json = { group = "io.kotest", name = "kotest-assertions-json", version.ref = "kotest" }
4852
kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutines" }
49-
ktor-server-test-host = { group = "io.ktor", name = "ktor-server-test-host", version.ref = "ktor" }
5053
ktor-client-mock = { group = "io.ktor", name = "ktor-client-mock", version.ref = "ktor" }
54+
ktor-server-test-host = { group = "io.ktor", name = "ktor-server-test-host", version.ref = "ktor" }
5155
slf4j-simple = { group = "org.slf4j", name = "slf4j-simple", version.ref = "slf4j" }
52-
kotest-assertions-json = { group = "io.kotest", name = "kotest-assertions-json", version.ref = "kotest" }
5356

5457
# Samples
5558
ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktor" }

kotlin-sdk-core/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,9 @@ kotlin {
5353
runtimeOnly(libs.slf4j.simple)
5454
}
5555
}
56+
57+
wasmJsMain.dependencies {
58+
api(libs.kotlinx.coroutines.core.wasm) // workaround for wasm server
59+
}
5660
}
5761
}

kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,10 @@ import kotlinx.serialization.json.JsonObject
3636
import kotlinx.serialization.json.JsonPrimitive
3737
import kotlinx.serialization.json.encodeToJsonElement
3838
import kotlinx.serialization.serializer
39-
import kotlin.collections.get
4039
import kotlin.reflect.KType
4140
import kotlin.reflect.typeOf
4241
import kotlin.time.Duration
43-
import kotlin.time.Duration.Companion.milliseconds
42+
import kotlin.time.Duration.Companion.seconds
4443

4544
private val LOGGER = KotlinLogging.logger { }
4645

@@ -85,7 +84,7 @@ public open class ProtocolOptions(
8584
/**
8685
* The default request timeout.
8786
*/
88-
public val DEFAULT_REQUEST_TIMEOUT: Duration = 60000.milliseconds
87+
public val DEFAULT_REQUEST_TIMEOUT: Duration = 60.seconds
8988

9089
/**
9190
* Options that can be given per request.

kotlin-sdk-test/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ kotlin {
2424
jvmTest {
2525
dependencies {
2626
implementation(kotlin("test-junit5"))
27+
implementation(libs.awaitility)
2728
runtimeOnly(libs.slf4j.simple)
2829
}
2930
}

kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/KotlinTestBase.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
1717
import io.modelcontextprotocol.kotlin.sdk.server.mcp
1818
import kotlinx.coroutines.runBlocking
1919
import kotlinx.coroutines.withTimeout
20+
import org.awaitility.kotlin.await
2021
import org.junit.jupiter.api.AfterEach
2122
import org.junit.jupiter.api.BeforeEach
2223
import kotlin.time.Duration.Companion.seconds
@@ -27,7 +28,7 @@ import io.ktor.server.sse.SSE as ServerSSE
2728
abstract class KotlinTestBase {
2829

2930
protected val host = "localhost"
30-
protected abstract val port: Int
31+
protected var port: Int = 0
3132

3233
protected lateinit var server: Server
3334
protected lateinit var client: Client
@@ -39,6 +40,12 @@ abstract class KotlinTestBase {
3940
@BeforeEach
4041
fun setUp() {
4142
setupServer()
43+
await
44+
.ignoreExceptions()
45+
.until {
46+
port = runBlocking { serverEngine.engine.resolvedConnectors().first().port }
47+
port != 0
48+
}
4249
runBlocking {
4350
setupClient()
4451
}

kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/PromptEdgeCasesTest.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import io.modelcontextprotocol.kotlin.sdk.PromptMessage
77
import io.modelcontextprotocol.kotlin.sdk.Role
88
import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities
99
import io.modelcontextprotocol.kotlin.sdk.TextContent
10-
import io.modelcontextprotocol.kotlin.sdk.integration.utils.TestUtils.runTest
10+
import kotlinx.coroutines.Dispatchers
1111
import kotlinx.coroutines.launch
1212
import kotlinx.coroutines.runBlocking
13+
import kotlinx.coroutines.test.runTest
1314
import org.junit.jupiter.api.Test
1415
import org.junit.jupiter.api.assertThrows
1516
import kotlin.test.assertEquals
@@ -18,8 +19,6 @@ import kotlin.test.assertTrue
1819

1920
class PromptEdgeCasesTest : KotlinTestBase() {
2021

21-
override val port = 3008
22-
2322
private val basicPromptName = "basic-prompt"
2423
private val basicPromptDescription = "A basic prompt for testing"
2524

@@ -183,7 +182,7 @@ class PromptEdgeCasesTest : KotlinTestBase() {
183182
}
184183

185184
@Test
186-
fun testBasicPrompt() = runTest {
185+
fun testBasicPrompt() = runBlocking(Dispatchers.IO) {
187186
val testName = "Alice"
188187
val result = client.getPrompt(
189188
GetPromptRequest(
@@ -215,7 +214,7 @@ class PromptEdgeCasesTest : KotlinTestBase() {
215214
}
216215

217216
@Test
218-
fun testComplexPromptWithManyArguments() = runTest {
217+
fun testComplexPromptWithManyArguments() = runBlocking(Dispatchers.IO) {
219218
val arguments = (1..10).associate { i -> "arg$i" to "value$i" }
220219

221220
val result = client.getPrompt(
@@ -253,7 +252,7 @@ class PromptEdgeCasesTest : KotlinTestBase() {
253252
}
254253

255254
@Test
256-
fun testLargePrompt() = runTest {
255+
fun testLargePrompt() = runBlocking(Dispatchers.IO) {
257256
val result = client.getPrompt(
258257
GetPromptRequest(
259258
name = largePromptName,
@@ -275,7 +274,7 @@ class PromptEdgeCasesTest : KotlinTestBase() {
275274
}
276275

277276
@Test
278-
fun testSpecialCharacters() = runTest {
277+
fun testSpecialCharacters() = runBlocking(Dispatchers.IO) {
279278
val result = client.getPrompt(
280279
GetPromptRequest(
281280
name = specialCharsPromptName,

kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/PromptIntegrationTest.kt

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import io.modelcontextprotocol.kotlin.sdk.PromptMessageContent
99
import io.modelcontextprotocol.kotlin.sdk.Role
1010
import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities
1111
import io.modelcontextprotocol.kotlin.sdk.TextContent
12-
import io.modelcontextprotocol.kotlin.sdk.integration.utils.TestUtils.runTest
12+
import kotlinx.coroutines.Dispatchers
1313
import kotlinx.coroutines.runBlocking
1414
import org.junit.jupiter.api.Test
1515
import org.junit.jupiter.api.assertThrows
@@ -19,7 +19,6 @@ import kotlin.test.assertTrue
1919

2020
class PromptIntegrationTest : KotlinTestBase() {
2121

22-
override val port = 3004
2322
private val testPromptName = "greeting"
2423
private val testPromptDescription = "A simple greeting prompt"
2524
private val complexPromptName = "multimodal-prompt"
@@ -219,7 +218,7 @@ class PromptIntegrationTest : KotlinTestBase() {
219218
}
220219

221220
@Test
222-
fun testListPrompts() = runTest {
221+
fun testListPrompts() = runBlocking(Dispatchers.IO) {
223222
val result = client.listPrompts()
224223

225224
assertNotNull(result, "List prompts result should not be null")
@@ -247,7 +246,7 @@ class PromptIntegrationTest : KotlinTestBase() {
247246
}
248247

249248
@Test
250-
fun testGetPrompt() = runTest {
249+
fun testGetPrompt() = runBlocking(Dispatchers.IO) {
251250
val testName = "Alice"
252251
val result = client.getPrompt(
253252
GetPromptRequest(
@@ -290,7 +289,7 @@ class PromptIntegrationTest : KotlinTestBase() {
290289
}
291290

292291
@Test
293-
fun testMissingRequiredArguments() = runTest {
292+
fun testMissingRequiredArguments() = runBlocking(Dispatchers.IO) {
294293
val promptsList = client.listPrompts()
295294
assertNotNull(promptsList, "Prompts list should not be null")
296295
val strictPrompt = promptsList.prompts.find { it.name == strictPromptName }
@@ -364,7 +363,7 @@ class PromptIntegrationTest : KotlinTestBase() {
364363
}
365364

366365
@Test
367-
fun testComplexContentTypes() = runTest {
366+
fun testComplexContentTypes() = runBlocking(Dispatchers.IO) {
368367
val topic = "artificial intelligence"
369368
val result = client.getPrompt(
370369
GetPromptRequest(
@@ -418,7 +417,7 @@ class PromptIntegrationTest : KotlinTestBase() {
418417
}
419418

420419
@Test
421-
fun testMultipleMessagesAndRoles() = runTest {
420+
fun testMultipleMessagesAndRoles() = runBlocking(Dispatchers.IO) {
422421
val topic = "climate change"
423422
val result = client.getPrompt(
424423
GetPromptRequest(

0 commit comments

Comments
 (0)