Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:

- name: ${{ matrix.job-name }}
run: |-
./gradlew ${{ matrix.gradle-tasks }} -x :conformance-test:test --max-workers ${{ matrix.max-workers }} --continue --configure-on-demand --parallel
./gradlew ${{ matrix.gradle-tasks }} -x :conformance-test:test --max-workers ${{ matrix.max-workers }} --continue --rerun-tasks --configure-on-demand --parallel

- name: Upload Reports
if: always()
Expand Down Expand Up @@ -168,7 +168,7 @@ jobs:

- name: "Build Sample: ${{ matrix.sample }}"
working-directory: ./samples/${{ matrix.sample }}
run: ./gradlew build -Pmcp.kotlin.overrideVersion=1-SNAPSHOT
run: ./gradlew build -Pmcp.kotlin.overrideVersion=1-SNAPSHOT --rerun-tasks

- name: Upload Reports
if: ${{ !cancelled() }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/gradle-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
uses: gradle/actions/setup-gradle@v5

- name: Clean Build with Gradle
run: ./gradlew clean build -x :conformance-test:test
run: ./gradlew clean build -x :conformance-test:test --rerun-tasks

- name: Publish to Maven Central Portal
id: publish
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.McpException
import io.modelcontextprotocol.kotlin.test.utils.createSleepyProcessBuilder
import io.modelcontextprotocol.kotlin.test.utils.createTeeProcessBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
Expand All @@ -30,7 +31,7 @@ import kotlin.time.Duration.Companion.seconds
class StdioClientTransportTest : BaseTransportTest() {

@Test
fun `handle stdio error`(): Unit = runBlocking {
fun `handle stdio error`(): Unit = runBlocking(Dispatchers.IO) {
val processBuilder = createSleepyProcessBuilder()

val process = processBuilder.start()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")

package io.modelcontextprotocol.kotlin.sdk.integration.kotlin.websocket

import io.ktor.client.HttpClient
Expand All @@ -21,11 +23,9 @@ import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.server.mcpWebSocket
import io.modelcontextprotocol.kotlin.sdk.types.GetPromptRequestParams
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.withContext
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.seconds
import io.ktor.client.engine.cio.CIO as ClientCIO
import io.ktor.client.plugins.websocket.WebSockets as ClientWebSocket
import io.ktor.server.cio.CIO as ServerCIO
Expand All @@ -34,16 +34,14 @@ import io.ktor.server.websocket.WebSockets as ServerWebSockets
class OldSchemaWebSocketIntegrationTest {

@Test
fun `client should be able to connect to websocket server 2`() = runTest(timeout = 5.seconds) {
fun `client should be able to connect to websocket server 2`() = runBlocking(Dispatchers.IO) {
var server: EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration>? = null
var client: Client? = null

try {
withContext(Dispatchers.Default) {
server = initServer()
val port = server.engine.resolvedConnectors().first().port
client = initClient(serverPort = port)
}
server = initServer()
val port = server.engine.resolvedConnectors().first().port
client = initClient(serverPort = port)
} finally {
client?.close()
server?.stop(1000, 2000)
Expand All @@ -58,19 +56,17 @@ class OldSchemaWebSocketIntegrationTest {
* 3. Observe that Client A receives a response related to it.
*/
@Test
fun `single websocket connection`() = runTest(timeout = 5.seconds) {
fun `single websocket connection`() = runBlocking(Dispatchers.IO) {
var server: EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration>? = null
var client: Client? = null

try {
withContext(Dispatchers.Default) {
server = initServer()
val port = server.engine.resolvedConnectors().first().port
client = initClient("Client A", port)
server = initServer()
val port = server.engine.resolvedConnectors().first().port
client = initClient("Client A", port)

val promptA = getPrompt(client, "Client A")
assertTrue { "Client A" in promptA }
}
val promptA = getPrompt(client, "Client A")
assertTrue { "Client A" in promptA }
} finally {
client?.close()
server?.stop(1000, 2000)
Expand All @@ -86,26 +82,24 @@ class OldSchemaWebSocketIntegrationTest {
* 4. Observe that Client B (connection #2) receives a response related to sessionId#1.
*/
@Test
fun `multiple websocket connections`() = runTest(timeout = 5.seconds) {
fun `multiple websocket connections`() = runBlocking(Dispatchers.IO) {
var server: EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration>? = null
var clientA: Client? = null
var clientB: Client? = null

try {
withContext(Dispatchers.Default) {
server = initServer()
val port = server.engine.resolvedConnectors().first().port
clientA = initClient("Client A", port)
clientB = initClient("Client B", port)

// Step 3: Send a prompt request from Client A
val promptA = getPrompt(clientA, "Client A")
// Step 4: Send a prompt request from Client B
val promptB = getPrompt(clientB, "Client B")

assertTrue { "Client A" in promptA }
assertTrue { "Client B" in promptB }
}
server = initServer()
val port = server.engine.resolvedConnectors().first().port
clientA = initClient("Client A", port)
clientB = initClient("Client B", port)

// Step 3: Send a prompt request from Client A
val promptA = getPrompt(clientA, "Client A")
// Step 4: Send a prompt request from Client B
val promptB = getPrompt(clientB, "Client B")

assertTrue { "Client A" in promptA }
assertTrue { "Client B" in promptB }
} finally {
clientA?.close()
clientB?.close()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ import io.modelcontextprotocol.kotlin.sdk.types.Role
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.withContext
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.seconds
import io.ktor.client.engine.cio.CIO as ClientCIO
import io.ktor.client.plugins.websocket.WebSockets as ClientWebSocket
import io.ktor.server.cio.CIO as ServerCIO
Expand All @@ -34,16 +32,14 @@ import io.ktor.server.websocket.WebSockets as ServerWebSockets
class WebSocketIntegrationTest {

@Test
fun `client should be able to connect to websocket server 2`() = runTest(timeout = 5.seconds) {
fun `client should be able to connect to websocket server 2`() = runBlocking(Dispatchers.IO) {
var server: EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration>? = null
var client: Client? = null

try {
withContext(Dispatchers.Default) {
server = initServer()
val port = server.engine.resolvedConnectors().first().port
client = initClient(serverPort = port)
}
server = initServer()
val port = server.engine.resolvedConnectors().first().port
client = initClient(serverPort = port)
} finally {
client?.close()
server?.stop(1000, 2000)
Expand All @@ -58,19 +54,17 @@ class WebSocketIntegrationTest {
* 3. Observe that Client A receives a response related to it.
*/
@Test
fun `single websocket connection`() = runTest(timeout = 5.seconds) {
fun `single websocket connection`() = runBlocking(Dispatchers.IO) {
var server: EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration>? = null
var client: Client? = null

try {
withContext(Dispatchers.Default) {
server = initServer()
val port = server.engine.resolvedConnectors().first().port
client = initClient("Client A", port)
server = initServer()
val port = server.engine.resolvedConnectors().first().port
client = initClient("Client A", port)

val promptA = getPrompt(client, "Client A")
assertTrue { "Client A" in promptA }
}
val promptA = getPrompt(client, "Client A")
assertTrue { "Client A" in promptA }
} finally {
client?.close()
server?.stop(1000, 2000)
Expand All @@ -86,26 +80,24 @@ class WebSocketIntegrationTest {
* 4. Observe that Client B (connection #2) receives a response related to sessionId#1.
*/
@Test
fun `multiple websocket connections`() = runTest(timeout = 5.seconds) {
fun `multiple websocket connections`() = runBlocking(Dispatchers.IO) {
var server: EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration>? = null
var clientA: Client? = null
var clientB: Client? = null

try {
withContext(Dispatchers.Default) {
server = initServer()
val port = server.engine.resolvedConnectors().first().port
clientA = initClient("Client A", port)
clientB = initClient("Client B", port)

// Step 3: Send a prompt request from Client A
val promptA = getPrompt(clientA, "Client A")
// Step 4: Send a prompt request from Client B
val promptB = getPrompt(clientB, "Client B")

assertTrue { "Client A" in promptA }
assertTrue { "Client B" in promptB }
}
server = initServer()
val port = server.engine.resolvedConnectors().first().port
clientA = initClient("Client A", port)
clientB = initClient("Client B", port)

// Step 3: Send a prompt request from Client A
val promptA = getPrompt(clientA, "Client A")
// Step 4: Send a prompt request from Client B
val promptB = getPrompt(clientB, "Client B")

assertTrue { "Client A" in promptA }
assertTrue { "Client B" in promptB }
} finally {
clientA?.close()
clientB?.close()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import io.ktor.server.sse.SSE as ServerSSE

open class AbstractSseIntegrationTest {

suspend fun EmbeddedServer<*, *>.actualPort() = engine.resolvedConnectors().single().port

suspend fun initTestClient(serverPort: Int, name: String? = null): Client {
val client = Client(
Implementation(name = name ?: DEFAULT_CLIENT_NAME, version = VERSION),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")

package io.modelcontextprotocol.kotlin.sdk.integration.sse

import io.ktor.client.HttpClient
Expand Down Expand Up @@ -25,8 +27,6 @@ import io.ktor.server.sse.SSE as ServerSSE

open class OldSchemaAbstractSseIntegrationTest {

suspend fun EmbeddedServer<*, *>.actualPort() = engine.resolvedConnectors().single().port

suspend fun initTestClient(serverPort: Int, name: String? = null): Client {
val client = Client(
Implementation(name = name ?: DEFAULT_CLIENT_NAME, version = VERSION),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")

package io.modelcontextprotocol.kotlin.sdk.integration.sse

import io.ktor.server.cio.CIOApplicationEngine
Expand All @@ -6,26 +8,23 @@ import io.modelcontextprotocol.kotlin.sdk.GetPromptRequest
import io.modelcontextprotocol.kotlin.sdk.TextContent
import io.modelcontextprotocol.kotlin.sdk.client.Client
import io.modelcontextprotocol.kotlin.sdk.types.GetPromptRequestParams
import io.modelcontextprotocol.kotlin.test.utils.actualPort
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.withContext
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.seconds

class OldSchemaSseIntegrationTest : OldSchemaAbstractSseIntegrationTest() {

@Test
fun `client should be able to connect to sse server`() = runTest(timeout = 5.seconds) {
fun `client should be able to connect to sse server`() = runBlocking(Dispatchers.IO) {
var server: EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration>? = null
var client: Client? = null

try {
withContext(Dispatchers.Default) {
server = initTestServer()
val port = server.engine.resolvedConnectors().single().port
client = initTestClient(serverPort = port)
}
server = initTestServer()
val port = server.actualPort()
client = initTestClient(serverPort = port)
} finally {
client?.close()
server?.stopSuspend(1000, 2000)
Expand All @@ -40,18 +39,16 @@ class OldSchemaSseIntegrationTest : OldSchemaAbstractSseIntegrationTest() {
* 3. Observe that Client A receives a response related to it.
*/
@Test
fun `single sse connection`() = runTest(timeout = 5.seconds) {
fun `single sse connection`() = runBlocking(Dispatchers.IO) {
var server: EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration>? = null
var client: Client? = null
try {
withContext(Dispatchers.Default) {
server = initTestServer()
val port = server.engine.resolvedConnectors().single().port
client = initTestClient(port, "Client A")
server = initTestServer()
val port = server.actualPort()
client = initTestClient(port, "Client A")

val promptA = getPrompt(client, "Client A")
assertTrue { "Client A" in promptA }
}
val promptA = getPrompt(client, "Client A")
assertTrue { "Client A" in promptA }
} finally {
client?.close()
server?.stopSuspend(1000, 2000)
Expand All @@ -67,27 +64,25 @@ class OldSchemaSseIntegrationTest : OldSchemaAbstractSseIntegrationTest() {
* 4. Observe that Client B (connection #2) receives a response related to sessionId#1.
*/
@Test
fun `multiple sse connections`() = runTest(timeout = 5.seconds) {
fun `multiple sse connections`() = runBlocking(Dispatchers.IO) {
var server: EmbeddedServer<CIOApplicationEngine, CIOApplicationEngine.Configuration>? = null
var clientA: Client? = null
var clientB: Client? = null

try {
withContext(Dispatchers.Default) {
server = initTestServer()
val port = server.engine.resolvedConnectors().first().port
server = initTestServer()
val port = server.engine.resolvedConnectors().first().port

clientA = initTestClient(port, "Client A")
clientB = initTestClient(port, "Client B")
clientA = initTestClient(port, "Client A")
clientB = initTestClient(port, "Client B")

// Step 3: Send a prompt request from Client A
val promptA = getPrompt(clientA, "Client A")
// Step 4: Send a prompt request from Client B
val promptB = getPrompt(clientB, "Client B")
// Step 3: Send a prompt request from Client A
val promptA = getPrompt(clientA, "Client A")
// Step 4: Send a prompt request from Client B
val promptB = getPrompt(clientB, "Client B")

assertTrue { "Client A" in promptA }
assertTrue { "Client B" in promptB }
}
assertTrue { "Client A" in promptA }
assertTrue { "Client B" in promptB }
} finally {
clientA?.close()
clientB?.close()
Expand Down
Loading
Loading