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
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ subprojects {
detekt {
config = files("$rootDir/config/detekt/detekt.yml")
buildUponDefaultConfig = true
failOnSeverity.set(FailOnSeverity.Never)
failOnSeverity.set(FailOnSeverity.Error)
}
}

Expand Down
9 changes: 9 additions & 0 deletions conformance-test/detekt-baseline.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>BracesOnWhenStatements:ConformanceServer.kt:HttpServerTransport$when</ID>
<ID>BracesOnWhenStatements:ConformanceTest.kt:ConformanceTest$when</ID>
<ID>ForbiddenComment:ConformanceTest.kt:ConformanceTest.Companion$// TODO: Fix</ID>
</CurrentIssues>
</SmellBaseline>
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ private const val MESSAGE_QUEUE_CAPACITY = 256
private fun isInitializeRequest(json: JsonElement): Boolean =
json is JsonObject && json["method"]?.jsonPrimitive?.contentOrNull == "initialize"

@Suppress("CyclomaticComplexMethod", "LongMethod")
fun main(args: Array<String>) {
val port = args.getOrNull(0)?.toIntOrNull() ?: 3000

Expand Down Expand Up @@ -236,6 +237,7 @@ fun main(args: Array<String>) {
}.start(wait = true)
}

@Suppress("LongMethod")
private fun createConformanceServer(): Server {
val server = Server(
Implementation(
Expand Down Expand Up @@ -371,7 +373,9 @@ private class HttpServerTransport(private val sessionId: String) : AbstractTrans
}
}

else -> call.respond(HttpStatusCode.Accepted)
else -> {
call.respond(HttpStatusCode.Accepted)
}
}
} catch (e: CancellationException) {
throw e
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import java.net.URI
import java.util.concurrent.TimeUnit
import kotlin.io.path.createTempFile
import kotlin.properties.Delegates
import kotlin.test.fail

private val logger = KotlinLogging.logger {}

Expand Down Expand Up @@ -320,7 +321,8 @@ class ConformanceTest {
}
process.destroyForcibly()
throw AssertionError(
"❌ $capitalizedType conformance test [$transportType] '$scenario' timed out after $timeoutSeconds seconds",
"❌ $capitalizedType conformance test [$transportType] '$scenario' " +
"timed out after $timeoutSeconds seconds",
)
}

Expand All @@ -331,8 +333,9 @@ class ConformanceTest {
logger.error {
"$capitalizedType conformance test [$transportType] '$scenario' failed with exit code: $exitCode"
}
throw AssertionError(
"❌ $capitalizedType conformance test [$transportType] '$scenario' failed (exit code: $exitCode). Check test output above for details.",
fail(
"❌ $capitalizedType conformance test [$transportType] '$scenario' " +
"failed (exit code: $exitCode). Check test output above for details.",
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class WebSocketClientTransport(override val session: WebSocketSession) : WebSock
}
}

@Suppress("LongMethod")
fun main(args: Array<String>) {
require(args.isNotEmpty()) {
"Server WebSocket URL must be provided as an argument"
Expand Down
11 changes: 11 additions & 0 deletions integration-test/detekt-baseline-commonTestSourceSet.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>EmptyFunctionBlock:ClientTest.kt:ClientTest.&lt;no name provided>${ }</ID>
<ID>EmptyFunctionBlock:ClientTest.kt:ClientTest.&lt;no name provided>${}</ID>
<ID>LargeClass:ClientTest.kt:ClientTest</ID>
<ID>LongMethod:ClientTest.kt:ClientTest$@Test fun `JSONRPCRequest with ToolsList method and default params returns list of tools`</ID>
<ID>LongMethod:ClientTest.kt:ClientTest$@Test fun `should handle logging setLevel request`</ID>
</CurrentIssues>
</SmellBaseline>
47 changes: 47 additions & 0 deletions integration-test/detekt-baseline-test.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>AbstractClassCanBeConcreteClass:AbstractPromptIntegrationTest.kt:AbstractPromptIntegrationTest$AbstractPromptIntegrationTest</ID>
<ID>AbstractClassCanBeConcreteClass:AbstractResourceIntegrationTest.kt:AbstractResourceIntegrationTest$AbstractResourceIntegrationTest</ID>
<ID>AbstractClassCanBeConcreteClass:AbstractToolIntegrationTest.kt:AbstractToolIntegrationTest$AbstractToolIntegrationTest</ID>
<ID>AbstractClassCanBeConcreteClass:BaseTransportTest.kt:BaseTransportTest$BaseTransportTest</ID>
<ID>CyclomaticComplexMethod:AbstractToolIntegrationTest.kt:AbstractToolIntegrationTest$private fun setupCalculatorTool</ID>
<ID>EmptyFunctionBlock:ClientTest.kt:ClientTest.&lt;no name provided>${ }</ID>
<ID>EmptyFunctionBlock:ClientTest.kt:ClientTest.&lt;no name provided>${}</ID>
<ID>ForbiddenComment:StdioClientTransportTest.kt:StdioClientTransportTest$// TODO: fix running on windows</ID>
<ID>InjectDispatcher:AbstractKotlinClientTsServerTest.kt:AbstractKotlinClientTsServerTest$IO</ID>
<ID>InjectDispatcher:AbstractPromptIntegrationTest.kt:AbstractPromptIntegrationTest$IO</ID>
<ID>InjectDispatcher:AbstractResourceIntegrationTest.kt:AbstractResourceIntegrationTest$IO</ID>
<ID>InjectDispatcher:AbstractToolIntegrationTest.kt:AbstractToolIntegrationTest$IO</ID>
<ID>InjectDispatcher:KotlinClientTsServerEdgeCasesTestSse.kt:KotlinClientTsServerEdgeCasesTestSse$IO</ID>
<ID>InjectDispatcher:KotlinClientTsServerEdgeCasesTestStdio.kt:KotlinClientTsServerEdgeCasesTestStdio$IO</ID>
<ID>InjectDispatcher:SseIntegrationTest.kt:SseIntegrationTest$IO</ID>
<ID>InjectDispatcher:StdioClientTransportTest.kt:StdioClientTransportTest$IO</ID>
<ID>InjectDispatcher:StreamableHttpIntegrationTest.kt:StreamableHttpIntegrationTest$IO</ID>
<ID>InjectDispatcher:TsEdgeCasesTestSse.kt:TsEdgeCasesTestSse$IO</ID>
<ID>InjectDispatcher:WebSocketIntegrationTest.kt:WebSocketIntegrationTest$IO</ID>
<ID>LargeClass:AbstractToolIntegrationTest.kt:AbstractToolIntegrationTest : KotlinTestBase</ID>
<ID>LargeClass:ClientTest.kt:ClientTest</ID>
<ID>LongMethod:AbstractPromptIntegrationTest.kt:AbstractPromptIntegrationTest$@Test fun testMissingRequiredArguments</ID>
<ID>LongMethod:AbstractPromptIntegrationTest.kt:AbstractPromptIntegrationTest$override fun configureServer</ID>
<ID>LongMethod:AbstractResourceIntegrationTest.kt:AbstractResourceIntegrationTest$override fun configureServer</ID>
<ID>LongMethod:AbstractToolIntegrationTest.kt:AbstractToolIntegrationTest$private fun setupCalculatorTool</ID>
<ID>LongMethod:ClientTest.kt:ClientTest$@Test fun `JSONRPCRequest with ToolsList method and default params returns list of tools`</ID>
<ID>LongMethod:ClientTest.kt:ClientTest$@Test fun `should handle logging setLevel request`</ID>
<ID>LongMethod:KotlinServerForTsClientSse.kt:HttpServerTransport$suspend fun handleRequest</ID>
<ID>LongMethod:KotlinServerForTsClientSse.kt:KotlinServerForTsClient$fun createMcpServer: Server</ID>
<ID>LongMethod:KotlinServerForTsClientSse.kt:KotlinServerForTsClient$fun start</ID>
<ID>LongMethod:KotlinTestBase.kt:KotlinTestBase$protected fun setupServer</ID>
<ID>LongMethod:ServerResourcesNotificationSubscribeTest.kt:ServerResourcesNotificationSubscribeTest$@Test fun `should send resource notifications`</ID>
<ID>LongMethod:TsEdgeCasesTestSse.kt:TsEdgeCasesTestSse$@Test @Timeout(30, unit = TimeUnit.SECONDS) fun testComplexConcurrentRequests: Unit</ID>
<ID>MatchingDeclarationName:PromptIntegrationTestSse.kt:SchemaPromptIntegrationTestSse : AbstractPromptIntegrationTest</ID>
<ID>SleepInsteadOfDelay:KotlinServerForTsClientSse.kt:KotlinServerForTsClient$sleep(500)</ID>
<ID>ThrowsCount:AbstractPromptIntegrationTest.kt:AbstractPromptIntegrationTest$override fun configureServer</ID>
<ID>UnusedPrivateProperty:KotlinClientTsServerTestSse.kt:KotlinClientTsServerTestSse$private val host = "localhost"</ID>
<ID>UseCheckOrError:ClientTest.kt:ClientTest.&lt;no name provided>$throw IllegalStateException("Test error")</ID>
<ID>UseOrEmpty:AbstractToolIntegrationTest.kt:AbstractToolIntegrationTest$(request.params.arguments?.get("tags") as? JsonArray)?.mapNotNull { (it as? JsonPrimitive)?.content } ?: emptyList()</ID>
<ID>UseRequire:AbstractPromptIntegrationTest.kt:AbstractPromptIntegrationTest$throw IllegalArgumentException("Missing required argument: $argName")</ID>
<ID>VarCouldBeVal:KotlinClientTsServerEdgeCasesTestSse.kt:KotlinClientTsServerEdgeCasesTestSse$private lateinit var client: Client</ID>
</CurrentIssues>
</SmellBaseline>
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class InMemoryTransport : AbstractTransport() {
}

override suspend fun send(message: JSONRPCMessage, options: TransportSendOptions?) {
val other = otherTransport ?: throw IllegalStateException("Not connected")
val other = checkNotNull(otherTransport) { "Not connected" }

other._onMessage.invoke(message)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ abstract class AbstractPromptIntegrationTest : KotlinTestBase() {
),
),
) { request ->
val args = request.params.arguments ?: emptyMap()
val args = request.params.arguments.orEmpty()
val arg1 = args["requiredArg1"] ?: throw IllegalArgumentException(
"Missing required argument: requiredArg1",
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ class ServerPromptsNotificationTest : AbstractServerFeaturesTest() {
fun `addPrompt should send notification`() = runTest {
// Configure notification handler
val notifications = mutableListOf<PromptListChangedNotification>()
client.setNotificationHandler<PromptListChangedNotification>(Method.Defined.NotificationsPromptsListChanged) {
notifications.add(it)
client.setNotificationHandler<PromptListChangedNotification>(
Method.Defined.NotificationsPromptsListChanged,
) { notification ->
notifications.add(notification)
CompletableDeferred(Unit)
}

Expand Down Expand Up @@ -96,8 +98,10 @@ class ServerPromptsNotificationTest : AbstractServerFeaturesTest() {
fun `notification should not be send when removed prompt does not exists`() = runTest {
// Track notifications
val notifications = mutableListOf<PromptListChangedNotification>()
client.setNotificationHandler<PromptListChangedNotification>(Method.Defined.NotificationsPromptsListChanged) {
notifications.add(it)
client.setNotificationHandler<PromptListChangedNotification>(
Method.Defined.NotificationsPromptsListChanged,
) { notification ->
notifications.add(notification)
CompletableDeferred(Unit)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class ServerPromptsTest : AbstractServerFeaturesTest() {
server.addPrompt(testPrompt) {
GetPromptResult(
description = "Test prompt description",
messages = listOf(),
messages = emptyList(),
)
}

Expand Down Expand Up @@ -70,13 +70,13 @@ class ServerPromptsTest : AbstractServerFeaturesTest() {
server.addPrompt(testPrompt1) {
GetPromptResult(
description = "Test prompt description 1",
messages = listOf(),
messages = emptyList(),
)
}
server.addPrompt(testPrompt2) {
GetPromptResult(
description = "Test prompt description 2",
messages = listOf(),
messages = emptyList(),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ class ServerResourcesNotificationSubscribeTest : AbstractServerFeaturesTest() {
name = "Test Resource 1",
description = "A test resource 1",
mimeType = "text/plain",
) {
) { request ->
ReadResourceResult(
contents = listOf(
TextResourceContents(
text = "Test resource content 1",
uri = it.uri,
uri = request.uri,
mimeType = "text/plain",
),
),
Expand All @@ -67,12 +67,12 @@ class ServerResourcesNotificationSubscribeTest : AbstractServerFeaturesTest() {
name = "Test Resource 2",
description = "A test resource 2",
mimeType = "text/plain",
) {
) { request ->
ReadResourceResult(
contents = listOf(
TextResourceContents(
text = "Test resource content 2",
uri = it.uri,
uri = request.uri,
mimeType = "text/plain",
),
),
Expand Down Expand Up @@ -121,8 +121,8 @@ class ServerResourcesNotificationSubscribeTest : AbstractServerFeaturesTest() {
println("Thread ${Thread.currentThread().name} test 1")
// Track notifications
val notifications = ConcurrentLinkedQueue<ResourceUpdatedNotification>()
client.setNotificationHandler<ResourceUpdatedNotification>(NotificationsResourcesUpdated) {
notifications.add(it)
client.setNotificationHandler<ResourceUpdatedNotification>(NotificationsResourcesUpdated) { notification ->
notifications.add(notification)
CompletableDeferred(Unit)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class ServerResourcesNotificationTest : AbstractServerFeaturesTest() {
val notifications = mutableListOf<ResourceListChangedNotification>()
client.setNotificationHandler<ResourceListChangedNotification>(
Method.Defined.NotificationsResourcesListChanged,
) {
notifications.add(it)
) { notification ->
notifications.add(notification)
CompletableDeferred(Unit)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ class ServerToolsNotificationTest : AbstractServerFeaturesTest() {
fun `removeTools should remove multiple tools and send two notifications`() = runTest {
// Configure notification handler
val notifications = mutableListOf<ToolListChangedNotification>()
client.setNotificationHandler<ToolListChangedNotification>(Method.Defined.NotificationsToolsListChanged) {
notifications.add(it)
client.setNotificationHandler<ToolListChangedNotification>(
Method.Defined.NotificationsToolsListChanged,
) { notification ->
notifications.add(notification)
CompletableDeferred(Unit)
}

Expand Down Expand Up @@ -83,8 +85,10 @@ class ServerToolsNotificationTest : AbstractServerFeaturesTest() {
fun `notification should not be send when removed tool does not exists`() = runTest {
// Track notifications
val notifications = mutableListOf<ToolListChangedNotification>()
client.setNotificationHandler<ToolListChangedNotification>(Method.Defined.NotificationsToolsListChanged) {
notifications.add(it)
client.setNotificationHandler<ToolListChangedNotification>(
Method.Defined.NotificationsToolsListChanged,
) { notification ->
notifications.add(notification)
CompletableDeferred(Unit)
}

Expand Down
14 changes: 14 additions & 0 deletions kotlin-sdk-client/detekt-baseline-commonMainSourceSet.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>CyclomaticComplexMethod:StdioClientTransport.kt:StdioClientTransport$override suspend fun initialize</ID>
<ID>LongMethod:StdioClientTransport.kt:StdioClientTransport$override suspend fun initialize</ID>
<ID>MaxLineLength:StdioClientTransport.kt:StdioClientTransport$*</ID>
<ID>ThrowsCount:SseClientTransport.kt:SseClientTransport$private suspend fun CoroutineScope.collectMessages</ID>
<ID>ThrowsCount:StreamableHttpClientTransport.kt:StreamableHttpClientTransport$@Suppress("ReturnCount", "CyclomaticComplexMethod") override suspend fun performSend</ID>
<ID>TooGenericExceptionCaught:Client.kt:Client$error: Throwable</ID>
<ID>TooGenericExceptionCaught:SseClientTransport.kt:SseClientTransport$e: Throwable</ID>
<ID>TooGenericExceptionCaught:StdioClientTransport.kt:StdioClientTransport$e: Throwable</ID>
</CurrentIssues>
</SmellBaseline>
9 changes: 9 additions & 0 deletions kotlin-sdk-client/detekt-baseline-commonTestSourceSet.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>LongMethod:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$@Ignore @Test fun testNotificationSchemaE2E</ID>
<ID>MaxLineLength:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$"""data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":"upload-123","progress":50,"total":100}}"""</ID>
<ID>MaxLineLength:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$"""data: {"jsonrpc":"2.0","method":"notifications/resumed","params":{"fromToken":"$lastEventIdSent"}}"""</ID>
</CurrentIssues>
</SmellBaseline>
19 changes: 19 additions & 0 deletions kotlin-sdk-client/detekt-baseline-main.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>CyclomaticComplexMethod:StdioClientTransport.kt:StdioClientTransport$override suspend fun initialize</ID>
<ID>InjectDispatcher:StdioClientTransport.kt:StdioClientTransport$Default</ID>
<ID>InjectDispatcher:StreamableHttpClientTransport.kt:StreamableHttpClientTransport$Default</ID>
<ID>LongMethod:StdioClientTransport.kt:StdioClientTransport$override suspend fun initialize</ID>
<ID>MaxLineLength:StdioClientTransport.kt:StdioClientTransport$*</ID>
<ID>NoNameShadowing:StdioClientTransport.kt:StdioClientTransport$source</ID>
<ID>ThrowsCount:SseClientTransport.kt:SseClientTransport$private suspend fun CoroutineScope.collectMessages</ID>
<ID>ThrowsCount:StreamableHttpClientTransport.kt:StreamableHttpClientTransport$@Suppress("ReturnCount", "CyclomaticComplexMethod") override suspend fun performSend</ID>
<ID>TooGenericExceptionCaught:Client.kt:Client$error: Throwable</ID>
<ID>TooGenericExceptionCaught:SseClientTransport.kt:SseClientTransport$e: Throwable</ID>
<ID>TooGenericExceptionCaught:StdioClientTransport.kt:StdioClientTransport$e: Throwable</ID>
<ID>UseCheckOrError:Client.kt:Client$throw IllegalStateException( "Server does not support resource subscriptions (required for $method)", )</ID>
<ID>UseCheckOrError:Client.kt:Client$throw IllegalStateException("Client does not support roots capability.")</ID>
</CurrentIssues>
</SmellBaseline>
18 changes: 18 additions & 0 deletions kotlin-sdk-client/detekt-baseline-test.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version='1.0' encoding='UTF-8'?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>AbstractClassCanBeConcreteClass:AbstractStreamableHttpClientTest.kt:AbstractStreamableHttpClientTest$AbstractStreamableHttpClientTest</ID>
<ID>ForbiddenComment:StreamableHttpClientTest.kt:StreamableHttpClientTest$// TODO: how to get notifications via Client API?</ID>
<ID>InjectDispatcher:StdioClientTransportErrorHandlingTest.kt:StdioClientTransportErrorHandlingTest$IO</ID>
<ID>InjectDispatcher:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$Default</ID>
<ID>LongMethod:StreamableHttpClientTest.kt:StreamableHttpClientTest$@Test fun `test streamableHttpClient`</ID>
<ID>LongMethod:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$@Ignore @Test fun testNotificationSchemaE2E</ID>
<ID>LongParameterList:MockMcp.kt:MockMcp$fun handleJSONRPCRequest</ID>
<ID>LongParameterList:MockMcp.kt:MockMcp$fun handleWithResult</ID>
<ID>LongParameterList:MockMcp.kt:MockMcp$fun onInitialize</ID>
<ID>MaxLineLength:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$"""data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":"upload-123","progress":50,"total":100}}"""</ID>
<ID>MaxLineLength:StreamableHttpClientTransportTest.kt:StreamableHttpClientTransportTest$"""data: {"jsonrpc":"2.0","method":"notifications/resumed","params":{"fromToken":"$lastEventIdSent"}}"""</ID>
<ID>UseOrEmpty:ClientMetaParameterTest.kt:ClientMetaParameterTest$exception.message ?: ""</ID>
</CurrentIssues>
</SmellBaseline>
Loading
Loading