Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.modelcontextprotocol.kotlin.sdk.types.ElicitationCompleteNotification
import io.modelcontextprotocol.kotlin.sdk.types.ElicitationCompleteNotificationParams
import io.modelcontextprotocol.kotlin.sdk.types.GetPromptRequest
import io.modelcontextprotocol.kotlin.sdk.types.GetPromptRequestParams
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.ListRootsRequest
import io.modelcontextprotocol.kotlin.sdk.types.ListRootsResult
import io.modelcontextprotocol.kotlin.sdk.types.LoggingLevel
Expand Down Expand Up @@ -70,6 +71,8 @@ class ClientConnectionTest : AbstractServerFeaturesTest() {
val pingComplete = CompletableDeferred<Unit>()
val rootsResult = CompletableDeferred<ListRootsResult>()
val sessionId = CompletableDeferred<String>()
val clientImplementation = CompletableDeferred<Implementation?>()
val clientCapabilities = CompletableDeferred<ClientCapabilities?>()
val toolListChanged =
onClientNotification<ToolListChangedNotification>(Method.Defined.NotificationsToolsListChanged)
val resourceListChanged =
Expand Down Expand Up @@ -120,6 +123,12 @@ class ClientConnectionTest : AbstractServerFeaturesTest() {
elicitationComplete.await().params.elicitationId shouldBe "elicit-123"
}
capturedSessionId.shouldNotBeBlank()
withClue("clientImplementation should expose the connected client's name and version") {
clientImplementation.await() shouldBe Implementation(name = "test client", version = "1.0")
}
withClue("clientCapabilities should expose what the client advertised at initialize") {
clientCapabilities.await() shouldBe getClientCapabilities()
}
}
}
}
Expand All @@ -142,6 +151,8 @@ class ClientConnectionTest : AbstractServerFeaturesTest() {
ElicitationCompleteNotification(ElicitationCompleteNotificationParams(elicitationId = "elicit-123")),
)
cap.sessionId.complete(sessionId)
cap.clientImplementation.complete(clientImplementation)
cap.clientCapabilities.complete(clientCapabilities)
}

@Test
Expand Down
2 changes: 2 additions & 0 deletions kotlin-sdk-server/api/kotlin-sdk-server.api
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ public abstract interface class io/modelcontextprotocol/kotlin/sdk/server/Client
public static synthetic fun createElicitation$default (Lio/modelcontextprotocol/kotlin/sdk/server/ClientConnection;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/shared/RequestOptions;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public abstract fun createMessage (Lio/modelcontextprotocol/kotlin/sdk/types/CreateMessageRequest;Lio/modelcontextprotocol/kotlin/sdk/shared/RequestOptions;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun createMessage$default (Lio/modelcontextprotocol/kotlin/sdk/server/ClientConnection;Lio/modelcontextprotocol/kotlin/sdk/types/CreateMessageRequest;Lio/modelcontextprotocol/kotlin/sdk/shared/RequestOptions;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public abstract fun getClientCapabilities ()Lio/modelcontextprotocol/kotlin/sdk/types/ClientCapabilities;
public abstract fun getClientImplementation ()Lio/modelcontextprotocol/kotlin/sdk/types/Implementation;
public abstract fun getSessionId ()Ljava/lang/String;
public abstract fun listRoots (Lio/modelcontextprotocol/kotlin/sdk/types/ListRootsRequest;Lio/modelcontextprotocol/kotlin/sdk/shared/RequestOptions;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun listRoots$default (Lio/modelcontextprotocol/kotlin/sdk/server/ClientConnection;Lio/modelcontextprotocol/kotlin/sdk/types/ListRootsRequest;Lio/modelcontextprotocol/kotlin/sdk/shared/RequestOptions;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.modelcontextprotocol.kotlin.sdk.server

import io.github.oshai.kotlinlogging.KotlinLogging
import io.modelcontextprotocol.kotlin.sdk.shared.RequestOptions
import io.modelcontextprotocol.kotlin.sdk.types.ClientCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.CreateMessageRequest
import io.modelcontextprotocol.kotlin.sdk.types.CreateMessageResult
import io.modelcontextprotocol.kotlin.sdk.types.ElicitRequest
Expand All @@ -11,6 +12,7 @@ import io.modelcontextprotocol.kotlin.sdk.types.ElicitRequestURLParams
import io.modelcontextprotocol.kotlin.sdk.types.ElicitResult
import io.modelcontextprotocol.kotlin.sdk.types.ElicitationCompleteNotification
import io.modelcontextprotocol.kotlin.sdk.types.EmptyResult
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.IncludeContext
import io.modelcontextprotocol.kotlin.sdk.types.ListRootsRequest
import io.modelcontextprotocol.kotlin.sdk.types.ListRootsResult
Expand Down Expand Up @@ -41,6 +43,19 @@ public interface ClientConnection {
*/
public val sessionId: String

/**
* The client's reported [Implementation] (name and version) after initialization.
*/
public val clientImplementation: Implementation?
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These could be non-null properties


/**
* The client's reported [ClientCapabilities] after initialization.
*
* Consult before invoking [createMessage], [listRoots], or [createElicitation]
Comment on lines +47 to +54
* to fall back gracefully when a capability is not advertised.
*/
public val clientCapabilities: ClientCapabilities?
Comment on lines +46 to +57

/**
* Sends a server-side notification to the client.
*
Expand Down Expand Up @@ -179,6 +194,10 @@ internal class ClientConnectionImpl(private val session: ServerSession) : Client

override val sessionId: String get() = session.sessionId

override val clientImplementation: Implementation? get() = session.clientVersion

override val clientCapabilities: ClientCapabilities? get() = session.clientCapabilities

private suspend fun <T : RequestResult> request(request: Request, options: RequestOptions? = null): T {
logger.trace { "Sending request to client for session $sessionId: $request" }
return session.request(request, options)
Expand Down
Loading