From 33923bc7c9f74e640f30385c4af0366fae88da8c Mon Sep 17 00:00:00 2001 From: Pavel Gorgulov Date: Thu, 2 Apr 2026 14:41:48 +0200 Subject: [PATCH] feat(docs): public api kdocs (#658) - enable rule for checking undocumented public api - add kdoc skill ## How Has This Been Tested? ./gradlew detekt ## Breaking Changes none ## Types of changes - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update ## Checklist - [x] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [x] My code follows the repository's style guidelines - [x] New and existing tests pass locally - [ ] I have added appropriate error handling - [x] I have added or updated documentation as needed --------- Co-authored-by: Konstantin Pavlov <1517853+kpavlov@users.noreply.github.com> --- .claude/skills/kdoc/SKILL.md | 74 +++++++++++++++++++ config/detekt/detekt.yml | 19 +++++ .../client/StreamableHttpClientTransport.kt | 7 +- .../kotlin/sdk/internal/utils.kt | 1 + .../kotlin/sdk/shared/Protocol.kt | 13 ++++ .../kotlin/sdk/shared/TransportSendOptions.kt | 6 ++ .../sdk/shared/WebSocketMcpTransport.kt | 1 + .../kotlin/sdk/types/PingRequest.kt | 5 ++ .../kotlin/sdk/types/capabilities.kt | 8 ++ .../kotlin/sdk/types/common.kt | 13 +++- .../kotlin/sdk/types/completion.kt | 1 + .../kotlin/sdk/types/content.kt | 14 +++- .../kotlin/sdk/types/elicitation.kt | 4 + .../kotlin/sdk/types/jsonRpc.kt | 18 ++++- .../kotlin/sdk/types/jsonUtils.kt | 2 + .../kotlin/sdk/types/methods.kt | 2 + .../kotlin/sdk/types/notification.kt | 4 + .../kotlin/sdk/types/request.kt | 25 ++++++- .../kotlin/sdk/types/resources.kt | 3 + .../kotlin/sdk/types/roots.kt | 1 + .../kotlin/sdk/types/sampling.kt | 11 ++- .../kotlin/sdk/types/schema.kt | 10 +++ .../kotlin/sdk/types/tasks.kt | 9 +++ .../sdk/utils/ResourceTemplateMatcher.kt | 2 + .../kotlin/sdk/internal/utils.jvm.kt | 1 + .../kotlin/sdk/server/SSEServerTransport.kt | 2 + .../kotlin/sdk/server/ServerSession.kt | 2 + .../server/StreamableHttpServerTransport.kt | 29 +++----- 28 files changed, 260 insertions(+), 27 deletions(-) create mode 100644 .claude/skills/kdoc/SKILL.md diff --git a/.claude/skills/kdoc/SKILL.md b/.claude/skills/kdoc/SKILL.md new file mode 100644 index 0000000..4760293 --- /dev/null +++ b/.claude/skills/kdoc/SKILL.md @@ -0,0 +1,74 @@ +--- +name: kdoc +description: "Add KDoc documentation to Kotlin public API. Use whenever the user asks to document Kotlin code, add KDoc, generate API docs, mentions undocumented public declarations, or wants to improve existing documentation. Also trigger when the user says 'add docs', 'document this class/file/module', 'write KDoc', or asks about missing documentation in Kotlin code." +--- + +# KDoc Generator + +Add KDoc comments to public Kotlin API declarations. + +## What to document + +All public declarations (no explicit `private`/`internal`/`protected`): +- Classes, interfaces, objects, sealed classes/interfaces +- Functions, extension functions +- Properties +- Enum classes and entries +- Type aliases, annotation classes + +Include `@Deprecated` elements. + +## Context + +Read the implementation, not just the signature, to write accurate descriptions. Understanding what the code actually does prevents superficial or misleading documentation. + +## KDoc format + +**Class/interface example:** + +````kotlin +/** + * Manages active client sessions and their lifecycle. + * + * Sessions are created on first connection and cleaned up + * when the transport closes. + * + * @property maxSessions upper limit on concurrent sessions + * @property timeout idle timeout before a session is evicted + */ +```` + +**Function example:** + +````kotlin +/** + * Registers a new tool with the given handler. + * + * Example: + * ```kotlin + * server.addTool( + * name = "echo", + * description = "Echoes input back", + * ) { request -> + * CallToolResult(content = listOf(TextContent("Echo: ${request.arguments}"))) + * } + * ``` + * + * @param name unique tool identifier + * @param description human-readable tool description + * @param handler suspend function invoked when the tool is called + * @return the registered tool definition + */ +```` + +## Rules + +- Summary: concise first sentence starting with a third-person verb ("Creates", "Returns", "Represents"). Expand to 2-3 sentences only when genuinely complex +- **@property** in class-level KDoc for all public properties (never as individual KDoc on the property); **@param** for function parameters +- **@return** for non-Unit return types +- **Example block**: add for DSL builders, complex functions, extension functions with non-obvious usage. Skip for trivial one-liners and simple getters +- **DSL builders**: always include an Example showing full usage with the receiver scope — this is critical for discoverability +- KDoc links (`[ClassName]`, `[methodName]`): only where it adds clear navigational value +- No **@throws** — don't document exceptions +- No **suspend** notes — coroutine nature is visible from the signature +- **Existing KDoc**: rewrite if incomplete (missing @param/@return/@property) or low quality \ No newline at end of file diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 2cb135a..4d44734 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -22,3 +22,22 @@ empty-blocks: EmptyFunctionBlock: excludes: *testFolders +comments: + UndocumentedPublicClass: + active: true + excludes: &testAndGeneratedFolders + - '**/test/**' + - '**/commonTest/**' + - '**/jvmTest/**' + - '**/jsTest/**' + - '**/iosTest/**' + - '**/generated-sources/**' + ignoreDefaultCompanionObject: true + UndocumentedPublicFunction: + active: true + excludes: *testAndGeneratedFolders + UndocumentedPublicProperty: + active: true + excludes: *testAndGeneratedFolders + searchProtectedProperty: false + ignoreEnumEntries: true diff --git a/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/StreamableHttpClientTransport.kt b/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/StreamableHttpClientTransport.kt index 80f37ae..999e25a 100644 --- a/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/StreamableHttpClientTransport.kt +++ b/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/StreamableHttpClientTransport.kt @@ -51,7 +51,9 @@ private const val MCP_PROTOCOL_VERSION_HEADER = "mcp-protocol-version" private const val MCP_RESUMPTION_TOKEN_HEADER = "Last-Event-ID" /** - * Error class for Streamable HTTP transport errors. + * Represents an error from the Streamable HTTP transport. + * + * @property code HTTP status code associated with the error, or `null` if unavailable */ public class StreamableHttpError(public val code: Int? = null, message: String? = null) : Exception("Streamable HTTP error: $message") @@ -66,6 +68,9 @@ private sealed interface ConnectResult { * Client transport for Streamable HTTP: this implements the MCP Streamable HTTP transport specification. * It will connect to a server using HTTP POST for sending messages and HTTP GET with Server-Sent Events * for receiving messages. + * + * @property sessionId session identifier assigned by the server after initialization, or `null` before connection + * @property protocolVersion MCP protocol version negotiated with the server, or `null` before connection */ @Suppress("TooManyFunctions") public class StreamableHttpClientTransport( diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.kt index d1cbe78..37a57b7 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.kt @@ -2,4 +2,5 @@ package io.modelcontextprotocol.kotlin.sdk.internal import kotlinx.coroutines.CoroutineDispatcher +/** Platform-specific [CoroutineDispatcher] for I/O-bound operations. */ public expect val IODispatcher: CoroutineDispatcher diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt index 20739e0..43c0ae5 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt @@ -42,6 +42,7 @@ import kotlin.time.Duration.Companion.seconds private val logger = KotlinLogging.logger { } +/** Default implementation name used in MCP handshake. */ public const val IMPLEMENTATION_NAME: String = "mcp-ktor" /** @@ -51,6 +52,8 @@ public typealias ProgressCallback = (Progress) -> Unit /** * Additional initialization options. + * + * @property timeout default timeout for outgoing requests */ public open class ProtocolOptions( /** @@ -97,9 +100,13 @@ public class RequestOptions( public val onProgress: ProgressCallback? = null, public val timeout: Duration = DEFAULT_REQUEST_TIMEOUT, ) : TransportSendOptions(relatedRequestId, resumptionToken, onResumptionToken) { + /** Destructuring component for [onProgress]. */ public operator fun component4(): ProgressCallback? = onProgress + + /** Destructuring component for [timeout]. */ public operator fun component5(): Duration = timeout + /** Creates a copy of this [RequestOptions] with the specified fields replaced. */ public fun copy( relatedRequestId: RequestId? = this.relatedRequestId, resumptionToken: String? = this.resumptionToken, @@ -139,6 +146,12 @@ internal val COMPLETED = CompletableDeferred(Unit).also { it.complete(Unit) } /** * Implements MCP protocol framing on top of a pluggable transport, including * features like request/response linking, notifications, and progress. + * + * @property transport the active transport, or `null` if not connected + * @property requestHandlers registered request handlers keyed by method name + * @property notificationHandlers registered notification handlers keyed by method name + * @property responseHandlers pending response handlers keyed by request ID + * @property progressHandlers registered progress callbacks keyed by progress token */ public abstract class Protocol(@PublishedApi internal val options: ProtocolOptions?) { public var transport: Transport? = null diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/TransportSendOptions.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/TransportSendOptions.kt index c56df04..5490288 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/TransportSendOptions.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/TransportSendOptions.kt @@ -17,10 +17,16 @@ public open class TransportSendOptions( public val resumptionToken: String? = null, public val onResumptionToken: ((String) -> Unit)? = null, ) { + /** Destructuring component for [relatedRequestId]. */ public operator fun component1(): RequestId? = relatedRequestId + + /** Destructuring component for [resumptionToken]. */ public operator fun component2(): String? = resumptionToken + + /** Destructuring component for [onResumptionToken]. */ public operator fun component3(): ((String) -> Unit)? = onResumptionToken + /** Creates a copy of this [TransportSendOptions] with the specified fields replaced. */ public open fun copy( relatedRequestId: RequestId? = this.relatedRequestId, resumptionToken: String? = this.resumptionToken, diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/WebSocketMcpTransport.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/WebSocketMcpTransport.kt index de75cc4..5f8bf9d 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/WebSocketMcpTransport.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/WebSocketMcpTransport.kt @@ -17,6 +17,7 @@ import kotlinx.coroutines.launch import kotlin.concurrent.atomics.AtomicBoolean import kotlin.concurrent.atomics.ExperimentalAtomicApi +/** WebSocket subprotocol identifier for MCP connections. */ public const val MCP_SUBPROTOCOL: String = "mcp" private val logger = KotlinLogging.logger {} diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/PingRequest.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/PingRequest.kt index 2f1e3ae..c45ed30 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/PingRequest.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/PingRequest.kt @@ -4,6 +4,11 @@ import kotlinx.serialization.EncodeDefault import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable +/** + * Represents a ping request used to check if the connection is alive. + * + * @property meta optional request metadata + */ @Serializable public data class PingRequest(override val params: BaseRequestParams? = null) : ClientRequest, diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/capabilities.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/capabilities.kt index cff3b89..fae24c3 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/capabilities.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/capabilities.kt @@ -54,6 +54,10 @@ public data class ClientCapabilities( public val experimental: JsonObject? = null, ) { + /** + * @property sampling convenience value to enable the sampling capability + * @property elicitation convenience value to enable the elicitation capability + */ public companion object { public val sampling: JsonObject = EmptyJsonObject public val elicitation: JsonObject = EmptyJsonObject @@ -100,6 +104,10 @@ public data class ServerCapabilities( val experimental: JsonObject? = null, ) { + /** + * @property Logging convenience value to enable the logging capability + * @property Completions convenience value to enable the completions capability + */ public companion object { public val Logging: JsonObject = EmptyJsonObject public val Completions: JsonObject = EmptyJsonObject diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/common.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/common.kt index 3ae8997..ac867af 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/common.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/common.kt @@ -8,10 +8,13 @@ import kotlinx.serialization.json.JsonObject // Protocol Version Constants // ============================================================================ +/** The latest supported MCP protocol version string. */ public const val LATEST_PROTOCOL_VERSION: String = "2025-11-25" +/** The default protocol version used when negotiation is not performed. */ public const val DEFAULT_NEGOTIATED_PROTOCOL_VERSION: String = "2025-06-18" +/** All MCP protocol versions supported by this SDK. */ public val SUPPORTED_PROTOCOL_VERSIONS: List = listOf( LATEST_PROTOCOL_VERSION, "2025-06-18", @@ -25,6 +28,8 @@ public val SUPPORTED_PROTOCOL_VERSIONS: List = listOf( /** * Represents an entity that includes additional metadata in its responses. + * + * @property meta optional metadata attached to this entity */ @Serializable public sealed interface WithMeta { @@ -123,13 +128,19 @@ public enum class Role { * * References are used to point to other entities (prompts, resources, etc.) * without including their full definitions. + * + * @property type discriminator identifying the reference subtype */ @Serializable(with = ReferencePolymorphicSerializer::class) public sealed interface Reference { public val type: ReferenceType } -/** Discriminator for [Reference] subtypes used in completion and other operations. */ +/** + * Discriminator for [Reference] subtypes used in completion and other operations. + * + * @property value serialized string representation of this reference type + */ @Serializable public enum class ReferenceType(public val value: String) { @SerialName("ref/prompt") diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/completion.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/completion.kt index 79a76ea..c782e3e 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/completion.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/completion.kt @@ -12,6 +12,7 @@ import kotlinx.serialization.json.JsonObject * A request from the client to the server to ask for completion options. * * @property params The request parameters containing the argument to complete and its context. + * @property meta optional request metadata */ @Serializable public data class CompleteRequest(override val params: CompleteRequestParams) : ClientRequest { diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/content.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/content.kt index 45cfd0d..a1c9e4f 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/content.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/content.kt @@ -8,7 +8,11 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonObject -/** Discriminator values for the polymorphic [ContentBlock] hierarchy. */ +/** + * Discriminator values for the polymorphic [ContentBlock] hierarchy. + * + * @property value serialized string representation of this content type + */ @Serializable public enum class ContentTypes(public val value: String) { @SerialName("text") @@ -27,11 +31,19 @@ public enum class ContentTypes(public val value: String) { EMBEDDED_RESOURCE("resource"), } +/** + * Base interface for all content blocks in the protocol. + * + * @property type discriminator identifying the content block subtype + */ @Serializable(with = ContentBlockPolymorphicSerializer::class) public sealed interface ContentBlock : WithMeta { public val type: ContentTypes } +/** + * Content block that carries media data such as text, images, or audio. + */ @Serializable(with = MediaContentPolymorphicSerializer::class) public sealed interface MediaContent : ContentBlock diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/elicitation.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/elicitation.kt index fc7787b..bb303f0 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/elicitation.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/elicitation.kt @@ -46,6 +46,8 @@ public data class ElicitRequest(override val params: ElicitRequestParams) : Serv * Represents the parameters for an `elicitation/create` request. * * Implementations: [ElicitRequestFormParams], [ElicitRequestURLParams]. + * + * @property message The message to present to the user describing what information is being requested. */ @Serializable(with = ElicitRequestParamsSerializer::class) public sealed interface ElicitRequestParams : RequestParams { @@ -111,6 +113,7 @@ public fun ElicitRequestParams( * later via `tasks/result`. * @property requestedSchema A restricted subset of JSON Schema. Only top-level properties * are allowed, without nesting. + * @property mode The elicitation mode discriminator, always `"form"`. * @property meta Optional metadata. May include a progressToken for out-of-band progress notifications. */ @Serializable @@ -138,6 +141,7 @@ public data class ElicitRequestFormParams( * @property task If specified, the caller is requesting task-augmented execution. The request * will return a [CreateTaskResult] immediately, and the actual result can be retrieved * later via `tasks/result`. + * @property mode The elicitation mode discriminator, always `"url"`. * @property meta Optional metadata. May include a progressToken for out-of-band progress notifications. */ @Serializable diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/jsonRpc.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/jsonRpc.kt index f42139f..1a9ea2e 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/jsonRpc.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/jsonRpc.kt @@ -14,6 +14,7 @@ import kotlin.jvm.JvmOverloads import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid +/** JSON-RPC protocol version used by MCP (`"2.0"`). */ public const val JSONRPC_VERSION: String = "2.0" /** @@ -40,12 +41,20 @@ public fun RequestId(value: Long): RequestId = RequestId.NumberId(value) @Serializable(with = RequestIdPolymorphicSerializer::class) public sealed interface RequestId { - /** A string-based request identifier. */ + /** + * A string-based request identifier. + * + * @property value the string representation of this request ID + */ @JvmInline @Serializable public value class StringId(public val value: String) : RequestId - /** A numeric request identifier. */ + /** + * A numeric request identifier. + * + * @property value the numeric representation of this request ID + */ @JvmInline @Serializable public value class NumberId(public val value: Long) : RequestId @@ -95,12 +104,17 @@ internal fun JSONRPCNotification.fromJSON(): Notification = * Base interface for all JSON-RPC 2.0 messages. * * All messages in the MCP protocol follow the JSON-RPC 2.0 specification. + * + * @property jsonrpc the JSON-RPC protocol version, always `"2.0"` */ @Serializable(with = JSONRPCMessagePolymorphicSerializer::class) public sealed interface JSONRPCMessage { public val jsonrpc: String } +/** + * Represents an empty JSON-RPC message used as a placeholder or no-op response. + */ @Serializable public data object JSONRPCEmptyMessage : JSONRPCMessage { override val jsonrpc: String = JSONRPC_VERSION diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/jsonUtils.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/jsonUtils.kt index 566905f..d83e012 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/jsonUtils.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/jsonUtils.kt @@ -11,8 +11,10 @@ import kotlinx.serialization.json.add import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.buildJsonObject +/** Reusable empty [JsonObject] instance. */ public val EmptyJsonObject: JsonObject = JsonObject(emptyMap()) +/** Pre-configured [Json] instance for MCP serialization. */ @OptIn(ExperimentalSerializationApi::class) public val McpJson: Json by lazy { Json { diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/methods.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/methods.kt index 5697df8..dae2fc7 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/methods.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/methods.kt @@ -4,6 +4,8 @@ import kotlinx.serialization.Serializable /** * Represents a method in the protocol, which can be predefined or custom. + * + * @property value the string representation of this method name */ @Serializable(with = MethodSerializer::class) public sealed interface Method { diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/notification.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/notification.kt index 08b1f12..24be040 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/notification.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/notification.kt @@ -11,6 +11,9 @@ import kotlinx.serialization.json.JsonObject /** * Represents a notification in the protocol. + * + * @property method the notification method identifier + * @property params optional notification parameters */ @Serializable(with = NotificationPolymorphicSerializer::class) public sealed interface Notification { @@ -73,6 +76,7 @@ public class Progress( * @property method The custom method name. By convention, custom methods often contain * organization-specific prefixes (e.g., "mycompany/custom_event"). * @property params Raw JSON parameters for the custom notification, if present. + * @property meta optional metadata for this notification */ @Serializable public data class CustomNotification(override val method: Method, override val params: BaseNotificationParams? = null) : diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/request.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/request.kt index 683186c..9f52ec9 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/request.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/request.kt @@ -11,6 +11,12 @@ import kotlinx.serialization.json.long import kotlinx.serialization.json.longOrNull import kotlin.jvm.JvmInline +/** + * Metadata attached to a request's `_meta` field. + * + * @property json the raw JSON object containing the metadata + * @property progressToken optional progress token for tracking request progress + */ @JvmInline @Serializable public value class RequestMeta(public val json: JsonObject) { @@ -43,6 +49,9 @@ public value class RequestMeta(public val json: JsonObject) { public operator fun get(key: String): JsonElement? = json[key] } +/** + * Base interface for parameters attached to a [Request]. + */ @Serializable public sealed interface RequestParams { /** @@ -55,11 +64,17 @@ public sealed interface RequestParams { public val meta: RequestMeta? } +/** + * Default [RequestParams] implementation carrying only optional metadata. + */ @Serializable public data class BaseRequestParams(@SerialName("_meta") override val meta: RequestMeta? = null) : RequestParams /** * Represents a request in the protocol. + * + * @property method the request method identifier + * @property params optional request parameters */ @OptIn(ExperimentalSerializationApi::class) @Serializable(with = RequestPolymorphicSerializer::class) @@ -112,9 +127,15 @@ public sealed interface PaginatedRequest : Request { @Serializable(with = RequestResultPolymorphicSerializer::class) public sealed interface RequestResult : WithMeta +/** + * Represents a result returned by the server in response to a [ClientRequest]. + */ @Serializable(with = ClientResultPolymorphicSerializer::class) public sealed interface ClientResult : RequestResult +/** + * Represents a result returned by the client in response to a [ServerRequest]. + */ @Serializable(with = ServerResultPolymorphicSerializer::class) public sealed interface ServerResult : RequestResult @@ -129,7 +150,9 @@ public data class EmptyResult(@SerialName("_meta") override val meta: JsonObject ServerResult /** - * Represents a request supporting pagination. + * Represents a paginated result. + * + * @property nextCursor opaque token for retrieving the next page of results, or `null` if no more results */ @Serializable public sealed interface PaginatedResult : RequestResult { diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/resources.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/resources.kt index fa316de..86ce3ce 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/resources.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/resources.kt @@ -8,6 +8,9 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonObject +/** + * Common interface for resource-like types that share URI, name, and description fields. + */ @Serializable public sealed interface ResourceLike : WithMeta diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/roots.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/roots.kt index af7b1e7..194ea4f 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/roots.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/roots.kt @@ -53,6 +53,7 @@ public data class Root( * `listChanged = true` to receive these requests. * * @property params Optional request parameters containing metadata. + * @property meta optional request metadata */ @Serializable public data class ListRootsRequest(override val params: BaseRequestParams? = null) : ServerRequest { diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/sampling.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/sampling.kt index 1ade1bf..97fc0c0 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/sampling.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/sampling.kt @@ -243,10 +243,19 @@ public data class CreateMessageResult( override val meta: JsonObject? = null, ) : ClientResult -/** The reason why the LLM stopped generating tokens. */ +/** + * The reason why the LLM stopped generating tokens. + * + * @property value the string representation of this stop reason + */ @JvmInline @Serializable public value class StopReason(public val value: String) { + /** + * @property EndTurn generation ended naturally + * @property StopSequence a stop sequence was encountered + * @property MaxTokens the maximum token limit was reached + */ public companion object { public val EndTurn: StopReason = StopReason("endTurn") public val StopSequence: StopReason = StopReason("stopSequence") diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/schema.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/schema.kt index dda2ac6..479cc66 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/schema.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/schema.kt @@ -24,6 +24,7 @@ public sealed interface PrimitiveSchemaDefinition * @property minLength Minimum string length. * @property maxLength Maximum string length. * @property format Optional format constraint (e.g., email, URI, date). + * @property type JSON Schema type discriminator, always `"string"`. * @property default Optional default value. */ @Serializable @@ -72,6 +73,7 @@ public sealed interface NumberSchemaDefinition : PrimitiveSchemaDefinition * @property description Optional description for the field. * @property minimum Minimum allowed value. * @property maximum Maximum allowed value. + * @property type JSON Schema type discriminator, always `"integer"`. * @property default Optional default value. */ @Serializable @@ -93,6 +95,7 @@ public data class IntegerSchema( * @property description Optional description for the field. * @property minimum Minimum allowed value. * @property maximum Maximum allowed value. + * @property type JSON Schema type discriminator, always `"number"`. * @property default Optional default value. */ @Serializable @@ -112,6 +115,7 @@ public data class DoubleSchema( * * @property title Optional display title for the field. * @property description Optional description for the field. + * @property type JSON Schema type discriminator, always `"boolean"`. * @property default Optional default value. */ @Serializable @@ -157,6 +161,7 @@ public sealed interface SingleSelectEnumSchema : EnumSchemaDefinition * @property title Optional display title for the field. * @property description Optional description for the field. * @property enumValues Array of enum values to choose from. + * @property type JSON Schema type discriminator, always `"string"`. * @property default Optional default value. */ @Serializable @@ -177,6 +182,7 @@ public data class UntitledSingleSelectEnumSchema( * @property title Optional display title for the field. * @property description Optional description for the field. * @property oneOf Array of enum options with values and display labels. + * @property type JSON Schema type discriminator, always `"string"`. * @property default Optional default value. */ @Serializable @@ -199,6 +205,7 @@ public data class TitledSingleSelectEnumSchema( * @property description Optional description for the field. * @property enumValues Array of enum values to choose from. * @property enumNames Display names for enum values. Non-standard according to JSON Schema 2020-12. + * @property type JSON Schema type discriminator, always `"string"`. * @property default Optional default value. */ @Deprecated("Use TitledSingleSelectEnumSchema instead") @@ -231,6 +238,7 @@ public sealed interface MultiSelectEnumSchema : EnumSchemaDefinition * @property minItems Minimum number of items to select. * @property maxItems Maximum number of items to select. * @property items Schema for the array items. + * @property type JSON Schema type discriminator, always `"array"`. * @property default Optional default value. */ @Serializable @@ -248,6 +256,7 @@ public data class UntitledMultiSelectEnumSchema( /** * Schema for the array items with plain enum values. * + * @property type JSON Schema type discriminator, always `"string"`. * @property enumValues Array of enum values to choose from. */ @Serializable @@ -268,6 +277,7 @@ public data class UntitledMultiSelectEnumSchema( * @property minItems Minimum number of items to select. * @property maxItems Maximum number of items to select. * @property items Schema for array items with enum options and display labels. + * @property type JSON Schema type discriminator, always `"array"`. * @property default Optional default value. */ @Serializable diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/tasks.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/tasks.kt index 42b5752..0f154e5 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/tasks.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/tasks.kt @@ -17,6 +17,14 @@ public const val RELATED_TASK_META_KEY: String = "io.modelcontextprotocol/relate /** * Common fields shared by all types representing the task state. + * + * @property taskId the task identifier + * @property status current task state + * @property statusMessage optional human-readable message describing the current task state + * @property createdAt ISO 8601 timestamp when the task was created + * @property lastUpdatedAt ISO 8601 timestamp when the task was last updated + * @property ttl actual retention duration from creation in milliseconds, or `null` for unlimited + * @property pollInterval suggested polling interval in milliseconds */ public sealed interface TaskFields { public val taskId: String @@ -228,6 +236,7 @@ public data class GetTaskPayloadRequestParams( * The structure matches the result type of the original request. * For example, a tools/call task would return the [CallToolResult] structure. * + * @property json the raw JSON object containing the result payload * @property meta Optional metadata for this response. */ @JvmInline diff --git a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/utils/ResourceTemplateMatcher.kt b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/utils/ResourceTemplateMatcher.kt index 5ba956d..867cc9f 100644 --- a/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/utils/ResourceTemplateMatcher.kt +++ b/kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/utils/ResourceTemplateMatcher.kt @@ -32,6 +32,8 @@ public class MatchResult(public val variables: Map, public val s * candidate URIs against that template via [match]. The returned [MatchResult.score] * must reflect match specificity so that a selection algorithm can prefer the most * specific template when multiple templates match the same URI. + * + * @property resourceTemplate the template to match URIs against */ public interface ResourceTemplateMatcher { diff --git a/kotlin-sdk-core/src/jvmMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.jvm.kt b/kotlin-sdk-core/src/jvmMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.jvm.kt index d00c1ab..35a1e98 100644 --- a/kotlin-sdk-core/src/jvmMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.jvm.kt +++ b/kotlin-sdk-core/src/jvmMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.jvm.kt @@ -3,5 +3,6 @@ package io.modelcontextprotocol.kotlin.sdk.internal import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers +/** Platform-specific [CoroutineDispatcher] for I/O-bound operations. */ public actual val IODispatcher: CoroutineDispatcher get() = Dispatchers.IO diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt index 619266a..f8c6581 100644 --- a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt @@ -26,6 +26,8 @@ internal const val SESSION_ID_PARAM = "sessionId" * Server transport for SSE: this will send messages over an SSE connection and receive messages from HTTP POST requests. * * Creates a new SSE server transport, which will direct the client to POST messages to the relative or absolute URL identified by `_endpoint`. + * + * @property sessionId unique identifier for this transport session, generated randomly on creation */ @OptIn(ExperimentalAtomicApi::class) public class SseServerTransport(private val endpoint: String, private val session: ServerSSESession) : diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerSession.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerSession.kt index e548e03..2f55c76 100644 --- a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerSession.kt +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerSession.kt @@ -40,6 +40,8 @@ private val logger = KotlinLogging.logger {} /** * Represents a server session. + * + * @property sessionId unique identifier for this session, generated randomly on creation */ @Suppress("TooManyFunctions") public open class ServerSession( diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransport.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransport.kt index 1ea8d83..70948d9 100644 --- a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransport.kt +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransport.kt @@ -71,6 +71,7 @@ private data class SessionContext(val session: ServerSSESession?, val call: Appl * - No session validation is performed * * @param configuration Transport configuration. See [Configuration] for available options. + * @property sessionId session identifier assigned after initialization, or `null` in stateless mode */ @OptIn(ExperimentalUuidApi::class, ExperimentalAtomicApi::class) @Suppress("TooManyFunctions") @@ -122,28 +123,16 @@ public class StreamableHttpServerTransport(private val configuration: Configurat ) /** - * Configuration for managing various aspects of the StreamableHttpServerTransport. - * - * @property enableJsonResponse Determines whether the server should return JSON responses. - * Defaults to `false`. - * - * @property enableDnsRebindingProtection Enables DNS rebinding protection. - * Defaults to `false`. - * - * @property allowedHosts A list of hosts allowed for server communication. - * Defaults to `null`, allowing all hosts. - * - * @property allowedOrigins A list of allowed origins for CORS (Cross-Origin Resource Sharing). - * Defaults to `null`, allowing all origins. - * - * @property eventStore The `EventStore` instance for handling resumable events. - * Defaults to `null`, disabling resumability. - * - * @property retryInterval Retry interval for event handling or reconnection attempts. - * Defaults to `null`. + * Configuration options for [StreamableHttpServerTransport]. * + * @property enableJsonResponse when `true`, returns direct JSON responses instead of SSE streams + * @property enableDnsRebindingProtection enables DNS rebinding protection + * @property allowedHosts list of hosts allowed for server communication, or `null` to allow all + * @property allowedOrigins list of allowed CORS origins, or `null` to allow all + * @property eventStore store for resumable events, or `null` to disable resumability + * @property retryInterval retry interval for SSE reconnection attempts * @property maxRequestBodySize Maximum allowed size (in bytes) for incoming request bodies. - * Defaults to 4 MB (4,194,304 bytes). + * Defaults to 4 MB (4,194,304 bytes). */ public class Configuration( public val enableJsonResponse: Boolean = false,