diff --git a/kotlin-sdk-server/api/kotlin-sdk-server.api b/kotlin-sdk-server/api/kotlin-sdk-server.api index 9c4fded9..763dc1b9 100644 --- a/kotlin-sdk-server/api/kotlin-sdk-server.api +++ b/kotlin-sdk-server/api/kotlin-sdk-server.api @@ -5,33 +5,35 @@ public final class io/modelcontextprotocol/kotlin/sdk/server/KtorServerKt { public static final fun mcp (Lio/ktor/server/routing/Routing;Lkotlin/jvm/functions/Function1;)V } -public final class io/modelcontextprotocol/kotlin/sdk/server/RegisteredPrompt { +public final class io/modelcontextprotocol/kotlin/sdk/server/RegisteredPrompt : io/modelcontextprotocol/kotlin/sdk/server/Feature { public fun (Lio/modelcontextprotocol/kotlin/sdk/Prompt;Lkotlin/jvm/functions/Function2;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/Prompt; public final fun component2 ()Lkotlin/jvm/functions/Function2; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/Prompt;Lkotlin/jvm/functions/Function2;)Lio/modelcontextprotocol/kotlin/sdk/server/RegisteredPrompt; public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/server/RegisteredPrompt;Lio/modelcontextprotocol/kotlin/sdk/Prompt;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/server/RegisteredPrompt; public fun equals (Ljava/lang/Object;)Z + public fun getKey ()Ljava/lang/String; public final fun getMessageProvider ()Lkotlin/jvm/functions/Function2; public final fun getPrompt ()Lio/modelcontextprotocol/kotlin/sdk/Prompt; public fun hashCode ()I public fun toString ()Ljava/lang/String; } -public final class io/modelcontextprotocol/kotlin/sdk/server/RegisteredResource { +public final class io/modelcontextprotocol/kotlin/sdk/server/RegisteredResource : io/modelcontextprotocol/kotlin/sdk/server/Feature { public fun (Lio/modelcontextprotocol/kotlin/sdk/Resource;Lkotlin/jvm/functions/Function2;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/Resource; public final fun component2 ()Lkotlin/jvm/functions/Function2; public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/Resource;Lkotlin/jvm/functions/Function2;)Lio/modelcontextprotocol/kotlin/sdk/server/RegisteredResource; public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/server/RegisteredResource;Lio/modelcontextprotocol/kotlin/sdk/Resource;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/server/RegisteredResource; public fun equals (Ljava/lang/Object;)Z + public fun getKey ()Ljava/lang/String; public final fun getReadHandler ()Lkotlin/jvm/functions/Function2; public final fun getResource ()Lio/modelcontextprotocol/kotlin/sdk/Resource; public fun hashCode ()I public fun toString ()Ljava/lang/String; } -public final class io/modelcontextprotocol/kotlin/sdk/server/RegisteredTool { +public final class io/modelcontextprotocol/kotlin/sdk/server/RegisteredTool : io/modelcontextprotocol/kotlin/sdk/server/Feature { public fun (Lio/modelcontextprotocol/kotlin/sdk/Tool;Lkotlin/jvm/functions/Function2;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/Tool; public final fun component2 ()Lkotlin/jvm/functions/Function2; @@ -39,6 +41,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/server/RegisteredTool { public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/server/RegisteredTool;Lio/modelcontextprotocol/kotlin/sdk/Tool;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/server/RegisteredTool; public fun equals (Ljava/lang/Object;)Z public final fun getHandler ()Lkotlin/jvm/functions/Function2; + public fun getKey ()Ljava/lang/String; public final fun getTool ()Lio/modelcontextprotocol/kotlin/sdk/Tool; public fun hashCode ()I public fun toString ()Ljava/lang/String; diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/FeatureRegistry.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/FeatureRegistry.kt new file mode 100644 index 00000000..1749ef64 --- /dev/null +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/FeatureRegistry.kt @@ -0,0 +1,120 @@ +package io.modelcontextprotocol.kotlin.sdk.server + +import io.github.oshai.kotlinlogging.KotlinLogging +import kotlinx.atomicfu.atomic +import kotlinx.atomicfu.getAndUpdate +import kotlinx.atomicfu.update +import kotlinx.collections.immutable.minus +import kotlinx.collections.immutable.persistentMapOf +import kotlinx.collections.immutable.toPersistentSet + +/** + * A generic registry for managing features of a specified type. This class provides thread-safe + * operations for adding, removing, and retrieving features from the registry. + * + * @param T The type of the feature, constrained to implement the [Feature] interface. + * @param featureType A string description of the type of feature being managed. + * Used primarily for logging purposes. + */ +internal class FeatureRegistry(private val featureType: String) { + + private val logger = KotlinLogging.logger(name = "FeatureRegistry[$featureType]") + + /** + * Atomic variable used to maintain a thread-safe registry of features. + * Stores a persistent map where each feature is identified by a unique key. + */ + private val registry = atomic(persistentMapOf()) + + /** + * Provides a snapshot of all features currently registered in the registry. + * Keys represent unique identifiers for each feature, and values represent the associated features. + */ + internal val values: Map + get() = registry.value + + /** + * Adds the specified feature to the registry. + * + * @param feature The feature to be added to the registry. + */ + internal fun add(feature: T) { + logger.info { "Adding $featureType: \"${feature.key}\"" } + registry.update { current -> current.put(feature.key, feature) } + logger.info { "Added $featureType: \"${feature.key}\"" } + } + + /** + * Adds the given list of features to the registry. Each feature is mapped by its key + * and added to the current registry. + * + * @param features The list of features to add to the registry. + */ + internal fun addAll(features: List) { + logger.info { "Adding ${featureType}s: ${features.size}" } + registry.update { current -> current.putAll(features.associateBy { it.key }) } + logger.info { "Added ${featureType}s: ${features.size}" } + } + + /** + * Removes the feature associated with the given key from the registry. + * + * @param key The key of the feature to be removed. + * @return `true` if the feature was successfully removed, or `false` if the feature was not found. + */ + internal fun remove(key: FeatureKey): Boolean { + logger.info { "Removing $featureType: \"$key\"" } + val oldMap = registry.getAndUpdate { current -> current.remove(key) } + + val removed = key in oldMap + logger.info { + if (removed) { + "Removed $featureType: \"$key\"" + } else { + "$featureType not found: \"$key\"" + } + } + return key in oldMap + } + + /** + * Removes the features associated with the given keys from the registry. + * + * @param keys The list of keys whose associated features are to be removed. + * @return The number of features that were successfully removed. + */ + internal fun removeAll(keys: List): Int { + logger.info { "Removing ${featureType}s: ${keys.size}" } + val oldMap = registry.getAndUpdate { current -> current - keys.toPersistentSet() } + + val removedCount = keys.count { it in oldMap } + logger.info { + if (removedCount > 0) { + "Removed ${featureType}s: $removedCount" + } else { + "No $featureType were removed" + } + } + + return removedCount + } + + /** + * Retrieves the feature associated with the given key from the registry. + * + * @param key The key of the feature to retrieve. + * @return The feature associated with the given key, or `null` if no such feature exists in the registry. + */ + internal fun get(key: FeatureKey): T? { + logger.info { "Getting $featureType: \"$key\"" } + val feature = registry.value[key] + logger.info { + if (feature != null) { + "Got $featureType: \"$key\"" + } else { + "$featureType not found: \"$key\"" + } + } + return feature + } +} diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Features.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Features.kt new file mode 100644 index 00000000..a956f1b7 --- /dev/null +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Features.kt @@ -0,0 +1,56 @@ +package io.modelcontextprotocol.kotlin.sdk.server + +import io.modelcontextprotocol.kotlin.sdk.CallToolRequest +import io.modelcontextprotocol.kotlin.sdk.CallToolResult +import io.modelcontextprotocol.kotlin.sdk.GetPromptRequest +import io.modelcontextprotocol.kotlin.sdk.GetPromptResult +import io.modelcontextprotocol.kotlin.sdk.Prompt +import io.modelcontextprotocol.kotlin.sdk.ReadResourceRequest +import io.modelcontextprotocol.kotlin.sdk.ReadResourceResult +import io.modelcontextprotocol.kotlin.sdk.Resource +import io.modelcontextprotocol.kotlin.sdk.Tool + +internal typealias FeatureKey = String + +/** + * Represents a feature with an associated unique key. + */ +internal interface Feature { + val key: FeatureKey +} + +/** + * A wrapper class representing a registered tool on the server. + * + * @property tool The tool definition. + * @property handler A suspend function to handle the tool call requests. + */ +public data class RegisteredTool(val tool: Tool, val handler: suspend (CallToolRequest) -> CallToolResult) : Feature { + override val key: String = tool.name +} + +/** + * A wrapper class representing a registered prompt on the server. + * + * @property prompt The prompt definition. + * @property messageProvider A suspend function that returns the prompt content when requested by the client. + */ +public data class RegisteredPrompt( + val prompt: Prompt, + val messageProvider: suspend (GetPromptRequest) -> GetPromptResult, +) : Feature { + override val key: String = prompt.name +} + +/** + * A wrapper class representing a registered resource on the server. + * + * @property resource The resource definition. + * @property readHandler A suspend function to handle read requests for this resource. + */ +public data class RegisteredResource( + val resource: Resource, + val readHandler: suspend (ReadResourceRequest) -> ReadResourceResult, +) : Feature { + override val key: String = resource.uri +} diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt index 04f18f8d..6a3ee8c4 100644 --- a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt @@ -27,12 +27,8 @@ import io.modelcontextprotocol.kotlin.sdk.ToolAnnotations import io.modelcontextprotocol.kotlin.sdk.shared.ProtocolOptions import io.modelcontextprotocol.kotlin.sdk.shared.Transport import kotlinx.atomicfu.atomic -import kotlinx.atomicfu.getAndUpdate import kotlinx.atomicfu.update -import kotlinx.collections.immutable.minus import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.persistentMapOf -import kotlinx.collections.immutable.toPersistentSet import kotlinx.coroutines.CancellationException private val logger = KotlinLogging.logger {} @@ -59,7 +55,7 @@ public class ServerOptions(public val capabilities: ServerCapabilities, enforceS * this server. The provider is called each time a new session is started to support dynamic instructions. * @param block A block to configure the mcp server. */ - +@Suppress("TooManyFunctions") public open class Server( protected val serverInfo: Implementation, protected val options: ServerOptions, @@ -92,15 +88,16 @@ public open class Server( @Suppress("ktlint:standard:backing-property-naming") private var _onClose: () -> Unit = {} - private val _tools = atomic(persistentMapOf()) - private val _prompts = atomic(persistentMapOf()) - private val _resources = atomic(persistentMapOf()) + private val toolRegistry = FeatureRegistry("Tool") + private val promptRegistry = FeatureRegistry("Prompt") + private val resourceRegistry = FeatureRegistry("Resource") + public val tools: Map - get() = _tools.value + get() = toolRegistry.values public val prompts: Map - get() = _prompts.value + get() = promptRegistry.values public val resources: Map - get() = _resources.value + get() = resourceRegistry.values init { block(this) @@ -108,7 +105,7 @@ public open class Server( public suspend fun close() { logger.debug { "Closing MCP server" } - sessions.value.forEach { it.close() } + sessions.value.forEach { session -> session.close() } _onClose() } @@ -172,12 +169,12 @@ public open class Server( // Register cleanup handler to remove session from list when it closes session.onClose { logger.debug { "Removing closed session from active sessions list" } - sessions.update { list -> list - session } + sessions.update { list -> list.remove(session) } } logger.debug { "Server session connecting to transport" } session.connect(transport) logger.debug { "Server session successfully connected to transport" } - sessions.update { it.add(session) } + sessions.update { sessions -> sessions.add(session) } _onConnect() return session @@ -229,12 +226,12 @@ public open class Server( * @throws IllegalStateException If the server does not support tools. */ public fun addTool(tool: Tool, handler: suspend (CallToolRequest) -> CallToolResult) { - if (options.capabilities.tools == null) { + check(options.capabilities.tools != null) { logger.error { "Failed to add tool '${tool.name}': Server does not support tools capability" } - throw IllegalStateException("Server does not support tools capability. Enable it in ServerOptions.") + "Server does not support tools capability. Enable it in ServerOptions." } - logger.info { "Registering tool: ${tool.name}" } - _tools.update { current -> current.put(tool.name, RegisteredTool(tool, handler)) } + + toolRegistry.add(RegisteredTool(tool, handler)) } /** @@ -249,6 +246,7 @@ public open class Server( * @param handler A suspend function that handles executing the tool when called by the client. * @throws IllegalStateException If the server does not support tools. */ + @Suppress("LongParameterList") public fun addTool( name: String, description: String, @@ -269,12 +267,11 @@ public open class Server( * @throws IllegalStateException If the server does not support tools. */ public fun addTools(toolsToAdd: List) { - if (options.capabilities.tools == null) { + check(options.capabilities.tools != null) { logger.error { "Failed to add tools: Server does not support tools capability" } - throw IllegalStateException("Server does not support tools capability.") + "Server does not support tools capability." } - logger.info { "Registering ${toolsToAdd.size} tools" } - _tools.update { current -> current.putAll(toolsToAdd.associateBy { it.tool.name }) } + toolRegistry.addAll(toolsToAdd) } /** @@ -285,23 +282,11 @@ public open class Server( * @throws IllegalStateException If the server does not support tools. */ public fun removeTool(name: String): Boolean { - if (options.capabilities.tools == null) { + check(options.capabilities.tools != null) { logger.error { "Failed to remove tool '$name': Server does not support tools capability" } - throw IllegalStateException("Server does not support tools capability.") - } - logger.info { "Removing tool: $name" } - - val oldMap = _tools.getAndUpdate { current -> current.remove(name) } - - val removed = name in oldMap - logger.debug { - if (removed) { - "Tool removed: $name" - } else { - "Tool not found: $name" - } + "Server does not support tools capability." } - return removed + return toolRegistry.remove(name) } /** @@ -312,22 +297,12 @@ public open class Server( * @throws IllegalStateException If the server does not support tools. */ public fun removeTools(toolNames: List): Int { - if (options.capabilities.tools == null) { + check(options.capabilities.tools != null) { logger.error { "Failed to remove tools: Server does not support tools capability" } - throw IllegalStateException("Server does not support tools capability.") + "Server does not support tools capability." } - logger.info { "Removing ${toolNames.size} tools" } - - val oldMap = _tools.getAndUpdate { current -> current - toolNames.toPersistentSet() } - val removedCount = toolNames.count { it in oldMap } - logger.info { - if (removedCount > 0) { - "Removed $removedCount tools" - } else { - "No tools were removed" - } - } + val removedCount = toolRegistry.removeAll(toolNames) return removedCount } @@ -339,12 +314,11 @@ public open class Server( * @throws IllegalStateException If the server does not support prompts. */ public fun addPrompt(prompt: Prompt, promptProvider: suspend (GetPromptRequest) -> GetPromptResult) { - if (options.capabilities.prompts == null) { + check(options.capabilities.prompts != null) { logger.error { "Failed to add prompt '${prompt.name}': Server does not support prompts capability" } - throw IllegalStateException("Server does not support prompts capability.") + "Server does not support prompts capability." } - logger.info { "Registering prompt: ${prompt.name}" } - _prompts.update { current -> current.put(prompt.name, RegisteredPrompt(prompt, promptProvider)) } + promptRegistry.add(RegisteredPrompt(prompt, promptProvider)) } /** @@ -373,12 +347,11 @@ public open class Server( * @throws IllegalStateException If the server does not support prompts. */ public fun addPrompts(promptsToAdd: List) { - if (options.capabilities.prompts == null) { + check(options.capabilities.prompts != null) { logger.error { "Failed to add prompts: Server does not support prompts capability" } - throw IllegalStateException("Server does not support prompts capability.") + "Server does not support prompts capability." } - logger.info { "Registering ${promptsToAdd.size} prompts" } - _prompts.update { current -> current.putAll(promptsToAdd.associateBy { it.prompt.name }) } + promptRegistry.addAll(promptsToAdd) } /** @@ -389,23 +362,12 @@ public open class Server( * @throws IllegalStateException If the server does not support prompts. */ public fun removePrompt(name: String): Boolean { - if (options.capabilities.prompts == null) { + check(options.capabilities.prompts != null) { logger.error { "Failed to remove prompt '$name': Server does not support prompts capability" } - throw IllegalStateException("Server does not support prompts capability.") + "Server does not support prompts capability." } - logger.info { "Removing prompt: $name" } - - val oldMap = _prompts.getAndUpdate { current -> current.remove(name) } - val removed = name in oldMap - logger.debug { - if (removed) { - "Prompt removed: $name" - } else { - "Prompt not found: $name" - } - } - return removed + return promptRegistry.remove(name) } /** @@ -416,24 +378,12 @@ public open class Server( * @throws IllegalStateException If the server does not support prompts. */ public fun removePrompts(promptNames: List): Int { - if (options.capabilities.prompts == null) { + check(options.capabilities.prompts != null) { logger.error { "Failed to remove prompts: Server does not support prompts capability" } - throw IllegalStateException("Server does not support prompts capability.") + "Server does not support prompts capability." } - logger.info { "Removing ${promptNames.size} prompts" } - - val oldMap = _prompts.getAndUpdate { current -> current - promptNames.toPersistentSet() } - - val removedCount = promptNames.count { it in oldMap } - logger.info { - if (removedCount > 0) { - "Removed $removedCount prompts" - } else { - "No prompts were removed" - } - } - return removedCount + return promptRegistry.removeAll(promptNames) } /** @@ -453,17 +403,12 @@ public open class Server( mimeType: String = "text/html", readHandler: suspend (ReadResourceRequest) -> ReadResourceResult, ) { - if (options.capabilities.resources == null) { + check(options.capabilities.resources != null) { logger.error { "Failed to add resource '$name': Server does not support resources capability" } - throw IllegalStateException("Server does not support resources capability.") - } - logger.info { "Registering resource: $name ($uri)" } - _resources.update { current -> - current.put( - uri, - RegisteredResource(Resource(uri, name, description, mimeType), readHandler), - ) + "Server does not support resources capability." } + val resource = Resource(uri, name, description, mimeType) + resourceRegistry.add(RegisteredResource(resource, readHandler)) } /** @@ -473,12 +418,11 @@ public open class Server( * @throws IllegalStateException If the server does not support resources. */ public fun addResources(resourcesToAdd: List) { - if (options.capabilities.resources == null) { + check(options.capabilities.resources != null) { logger.error { "Failed to add resources: Server does not support resources capability" } - throw IllegalStateException("Server does not support resources capability.") + "Server does not support resources capability." } - logger.info { "Registering ${resourcesToAdd.size} resources" } - _resources.update { current -> current.putAll(resourcesToAdd.associateBy { it.resource.uri }) } + resourceRegistry.addAll(resourcesToAdd) } /** @@ -489,23 +433,11 @@ public open class Server( * @throws IllegalStateException If the server does not support resources. */ public fun removeResource(uri: String): Boolean { - if (options.capabilities.resources == null) { + check(options.capabilities.resources != null) { logger.error { "Failed to remove resource '$uri': Server does not support resources capability" } - throw IllegalStateException("Server does not support resources capability.") - } - logger.info { "Removing resource: $uri" } - - val oldMap = _resources.getAndUpdate { current -> current.remove(uri) } - - val removed = uri in oldMap - logger.debug { - if (removed) { - "Resource removed: $uri" - } else { - "Resource not found: $uri" - } + "Server does not support resources capability." } - return removed + return resourceRegistry.remove(uri) } /** @@ -516,24 +448,11 @@ public open class Server( * @throws IllegalStateException If the server does not support resources. */ public fun removeResources(uris: List): Int { - if (options.capabilities.resources == null) { + check(options.capabilities.resources != null) { logger.error { "Failed to remove resources: Server does not support resources capability" } - throw IllegalStateException("Server does not support resources capability.") + "Server does not support resources capability." } - logger.info { "Removing ${uris.size} resources" } - - val oldMap = _resources.getAndUpdate { current -> current - uris.toPersistentSet() } - - val removedCount = uris.count { it in oldMap } - - logger.info { - if (removedCount > 0) { - "Removed $removedCount resources" - } else { - "No resources were removed" - } - } - return removedCount + return resourceRegistry.removeAll(uris) } // --- Internal Handlers --- @@ -545,17 +464,17 @@ public open class Server( private suspend fun handleCallTool(request: CallToolRequest): CallToolResult { logger.debug { "Handling tool call request for tool: ${request.name}" } - // Check if tool exists - val tool = _tools.value[request.name] - ?: run { - logger.error { "Tool not found: ${request.name}" } - return CallToolResult( - content = listOf(TextContent(text = "Tool ${request.name} not found")), - isError = true, - ) - } + // Check if the tool exists + val tool = toolRegistry.get(request.name) ?: run { + logger.error { "Tool not found: ${request.name}" } + return CallToolResult( + content = listOf(TextContent(text = "Tool ${request.name} not found")), + isError = true, + ) + } - // Execute tool handler and catch any errors + @Suppress("TooGenericExceptionCaught") + // Execute the tool handler and catch any errors return try { logger.trace { "Executing tool ${request.name} with input: ${request.arguments}" } tool.handler(request) @@ -577,7 +496,7 @@ public open class Server( private suspend fun handleGetPrompt(request: GetPromptRequest): GetPromptResult { logger.debug { "Handling get prompt request for: ${request.name}" } - val prompt = prompts[request.name] + val prompt = promptRegistry.get(request.name) ?: run { logger.error { "Prompt not found: ${request.name}" } throw IllegalArgumentException("Prompt not found: ${request.name}") @@ -592,7 +511,7 @@ public open class Server( private suspend fun handleReadResource(request: ReadResourceRequest): ReadResourceResult { logger.debug { "Handling read resource request for: ${request.uri}" } - val resource = resources[request.uri] + val resource = resourceRegistry.get(request.uri) ?: run { logger.error { "Resource not found: ${request.uri}" } throw IllegalArgumentException("Resource not found: ${request.uri}") @@ -605,33 +524,3 @@ public open class Server( return ListResourceTemplatesResult(listOf()) } } - -/** - * A wrapper class representing a registered tool on the server. - * - * @property tool The tool definition. - * @property handler A suspend function to handle the tool call requests. - */ -public data class RegisteredTool(val tool: Tool, val handler: suspend (CallToolRequest) -> CallToolResult) - -/** - * A wrapper class representing a registered prompt on the server. - * - * @property prompt The prompt definition. - * @property messageProvider A suspend function that returns the prompt content when requested by the client. - */ -public data class RegisteredPrompt( - val prompt: Prompt, - val messageProvider: suspend (GetPromptRequest) -> GetPromptResult, -) - -/** - * A wrapper class representing a registered resource on the server. - * - * @property resource The resource definition. - * @property readHandler A suspend function to handle read requests for this resource. - */ -public data class RegisteredResource( - val resource: Resource, - val readHandler: suspend (ReadResourceRequest) -> ReadResourceResult, -) diff --git a/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseIntegrationTest.kt b/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseIntegrationTest.kt index 33e80705..55e833b3 100644 --- a/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseIntegrationTest.kt +++ b/kotlin-sdk-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseIntegrationTest.kt @@ -12,7 +12,7 @@ import kotlin.test.Test import kotlin.test.assertTrue import kotlin.time.Duration.Companion.seconds -class SSeIntegrationTest : AbstractSseIntegrationTest() { +class SseIntegrationTest : AbstractSseIntegrationTest() { @Test fun `client should be able to connect to sse server`() = runTest(timeout = 5.seconds) {