Skip to content

Commit 33923bc

Browse files
devcrocodkpavlov
andauthored
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>
1 parent e5e5ec2 commit 33923bc

28 files changed

Lines changed: 260 additions & 27 deletions

File tree

.claude/skills/kdoc/SKILL.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
name: kdoc
3+
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."
4+
---
5+
6+
# KDoc Generator
7+
8+
Add KDoc comments to public Kotlin API declarations.
9+
10+
## What to document
11+
12+
All public declarations (no explicit `private`/`internal`/`protected`):
13+
- Classes, interfaces, objects, sealed classes/interfaces
14+
- Functions, extension functions
15+
- Properties
16+
- Enum classes and entries
17+
- Type aliases, annotation classes
18+
19+
Include `@Deprecated` elements.
20+
21+
## Context
22+
23+
Read the implementation, not just the signature, to write accurate descriptions. Understanding what the code actually does prevents superficial or misleading documentation.
24+
25+
## KDoc format
26+
27+
**Class/interface example:**
28+
29+
````kotlin
30+
/**
31+
* Manages active client sessions and their lifecycle.
32+
*
33+
* Sessions are created on first connection and cleaned up
34+
* when the transport closes.
35+
*
36+
* @property maxSessions upper limit on concurrent sessions
37+
* @property timeout idle timeout before a session is evicted
38+
*/
39+
````
40+
41+
**Function example:**
42+
43+
````kotlin
44+
/**
45+
* Registers a new tool with the given handler.
46+
*
47+
* Example:
48+
* ```kotlin
49+
* server.addTool(
50+
* name = "echo",
51+
* description = "Echoes input back",
52+
* ) { request ->
53+
* CallToolResult(content = listOf(TextContent("Echo: ${request.arguments}")))
54+
* }
55+
* ```
56+
*
57+
* @param name unique tool identifier
58+
* @param description human-readable tool description
59+
* @param handler suspend function invoked when the tool is called
60+
* @return the registered tool definition
61+
*/
62+
````
63+
64+
## Rules
65+
66+
- Summary: concise first sentence starting with a third-person verb ("Creates", "Returns", "Represents"). Expand to 2-3 sentences only when genuinely complex
67+
- **@property** in class-level KDoc for all public properties (never as individual KDoc on the property); **@param** for function parameters
68+
- **@return** for non-Unit return types
69+
- **Example block**: add for DSL builders, complex functions, extension functions with non-obvious usage. Skip for trivial one-liners and simple getters
70+
- **DSL builders**: always include an Example showing full usage with the receiver scope — this is critical for discoverability
71+
- KDoc links (`[ClassName]`, `[methodName]`): only where it adds clear navigational value
72+
- No **@throws** — don't document exceptions
73+
- No **suspend** notes — coroutine nature is visible from the signature
74+
- **Existing KDoc**: rewrite if incomplete (missing @param/@return/@property) or low quality

config/detekt/detekt.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,22 @@ empty-blocks:
2222
EmptyFunctionBlock:
2323
excludes: *testFolders
2424

25+
comments:
26+
UndocumentedPublicClass:
27+
active: true
28+
excludes: &testAndGeneratedFolders
29+
- '**/test/**'
30+
- '**/commonTest/**'
31+
- '**/jvmTest/**'
32+
- '**/jsTest/**'
33+
- '**/iosTest/**'
34+
- '**/generated-sources/**'
35+
ignoreDefaultCompanionObject: true
36+
UndocumentedPublicFunction:
37+
active: true
38+
excludes: *testAndGeneratedFolders
39+
UndocumentedPublicProperty:
40+
active: true
41+
excludes: *testAndGeneratedFolders
42+
searchProtectedProperty: false
43+
ignoreEnumEntries: true

kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/StreamableHttpClientTransport.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ private const val MCP_PROTOCOL_VERSION_HEADER = "mcp-protocol-version"
5151
private const val MCP_RESUMPTION_TOKEN_HEADER = "Last-Event-ID"
5252

5353
/**
54-
* Error class for Streamable HTTP transport errors.
54+
* Represents an error from the Streamable HTTP transport.
55+
*
56+
* @property code HTTP status code associated with the error, or `null` if unavailable
5557
*/
5658
public class StreamableHttpError(public val code: Int? = null, message: String? = null) :
5759
Exception("Streamable HTTP error: $message")
@@ -66,6 +68,9 @@ private sealed interface ConnectResult {
6668
* Client transport for Streamable HTTP: this implements the MCP Streamable HTTP transport specification.
6769
* It will connect to a server using HTTP POST for sending messages and HTTP GET with Server-Sent Events
6870
* for receiving messages.
71+
*
72+
* @property sessionId session identifier assigned by the server after initialization, or `null` before connection
73+
* @property protocolVersion MCP protocol version negotiated with the server, or `null` before connection
6974
*/
7075
@Suppress("TooManyFunctions")
7176
public class StreamableHttpClientTransport(

kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/internal/utils.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ package io.modelcontextprotocol.kotlin.sdk.internal
22

33
import kotlinx.coroutines.CoroutineDispatcher
44

5+
/** Platform-specific [CoroutineDispatcher] for I/O-bound operations. */
56
public expect val IODispatcher: CoroutineDispatcher

kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/Protocol.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import kotlin.time.Duration.Companion.seconds
4242

4343
private val logger = KotlinLogging.logger { }
4444

45+
/** Default implementation name used in MCP handshake. */
4546
public const val IMPLEMENTATION_NAME: String = "mcp-ktor"
4647

4748
/**
@@ -51,6 +52,8 @@ public typealias ProgressCallback = (Progress) -> Unit
5152

5253
/**
5354
* Additional initialization options.
55+
*
56+
* @property timeout default timeout for outgoing requests
5457
*/
5558
public open class ProtocolOptions(
5659
/**
@@ -97,9 +100,13 @@ public class RequestOptions(
97100
public val onProgress: ProgressCallback? = null,
98101
public val timeout: Duration = DEFAULT_REQUEST_TIMEOUT,
99102
) : TransportSendOptions(relatedRequestId, resumptionToken, onResumptionToken) {
103+
/** Destructuring component for [onProgress]. */
100104
public operator fun component4(): ProgressCallback? = onProgress
105+
106+
/** Destructuring component for [timeout]. */
101107
public operator fun component5(): Duration = timeout
102108

109+
/** Creates a copy of this [RequestOptions] with the specified fields replaced. */
103110
public fun copy(
104111
relatedRequestId: RequestId? = this.relatedRequestId,
105112
resumptionToken: String? = this.resumptionToken,
@@ -139,6 +146,12 @@ internal val COMPLETED = CompletableDeferred(Unit).also { it.complete(Unit) }
139146
/**
140147
* Implements MCP protocol framing on top of a pluggable transport, including
141148
* features like request/response linking, notifications, and progress.
149+
*
150+
* @property transport the active transport, or `null` if not connected
151+
* @property requestHandlers registered request handlers keyed by method name
152+
* @property notificationHandlers registered notification handlers keyed by method name
153+
* @property responseHandlers pending response handlers keyed by request ID
154+
* @property progressHandlers registered progress callbacks keyed by progress token
142155
*/
143156
public abstract class Protocol(@PublishedApi internal val options: ProtocolOptions?) {
144157
public var transport: Transport? = null

kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/TransportSendOptions.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@ public open class TransportSendOptions(
1717
public val resumptionToken: String? = null,
1818
public val onResumptionToken: ((String) -> Unit)? = null,
1919
) {
20+
/** Destructuring component for [relatedRequestId]. */
2021
public operator fun component1(): RequestId? = relatedRequestId
22+
23+
/** Destructuring component for [resumptionToken]. */
2124
public operator fun component2(): String? = resumptionToken
25+
26+
/** Destructuring component for [onResumptionToken]. */
2227
public operator fun component3(): ((String) -> Unit)? = onResumptionToken
2328

29+
/** Creates a copy of this [TransportSendOptions] with the specified fields replaced. */
2430
public open fun copy(
2531
relatedRequestId: RequestId? = this.relatedRequestId,
2632
resumptionToken: String? = this.resumptionToken,

kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/WebSocketMcpTransport.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import kotlinx.coroutines.launch
1717
import kotlin.concurrent.atomics.AtomicBoolean
1818
import kotlin.concurrent.atomics.ExperimentalAtomicApi
1919

20+
/** WebSocket subprotocol identifier for MCP connections. */
2021
public const val MCP_SUBPROTOCOL: String = "mcp"
2122

2223
private val logger = KotlinLogging.logger {}

kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/PingRequest.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import kotlinx.serialization.EncodeDefault
44
import kotlinx.serialization.ExperimentalSerializationApi
55
import kotlinx.serialization.Serializable
66

7+
/**
8+
* Represents a ping request used to check if the connection is alive.
9+
*
10+
* @property meta optional request metadata
11+
*/
712
@Serializable
813
public data class PingRequest(override val params: BaseRequestParams? = null) :
914
ClientRequest,

kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/capabilities.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ public data class ClientCapabilities(
5454
public val experimental: JsonObject? = null,
5555
) {
5656

57+
/**
58+
* @property sampling convenience value to enable the sampling capability
59+
* @property elicitation convenience value to enable the elicitation capability
60+
*/
5761
public companion object {
5862
public val sampling: JsonObject = EmptyJsonObject
5963
public val elicitation: JsonObject = EmptyJsonObject
@@ -100,6 +104,10 @@ public data class ServerCapabilities(
100104
val experimental: JsonObject? = null,
101105
) {
102106

107+
/**
108+
* @property Logging convenience value to enable the logging capability
109+
* @property Completions convenience value to enable the completions capability
110+
*/
103111
public companion object {
104112
public val Logging: JsonObject = EmptyJsonObject
105113
public val Completions: JsonObject = EmptyJsonObject

kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/common.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ import kotlinx.serialization.json.JsonObject
88
// Protocol Version Constants
99
// ============================================================================
1010

11+
/** The latest supported MCP protocol version string. */
1112
public const val LATEST_PROTOCOL_VERSION: String = "2025-11-25"
1213

14+
/** The default protocol version used when negotiation is not performed. */
1315
public const val DEFAULT_NEGOTIATED_PROTOCOL_VERSION: String = "2025-06-18"
1416

17+
/** All MCP protocol versions supported by this SDK. */
1518
public val SUPPORTED_PROTOCOL_VERSIONS: List<String> = listOf(
1619
LATEST_PROTOCOL_VERSION,
1720
"2025-06-18",
@@ -25,6 +28,8 @@ public val SUPPORTED_PROTOCOL_VERSIONS: List<String> = listOf(
2528

2629
/**
2730
* Represents an entity that includes additional metadata in its responses.
31+
*
32+
* @property meta optional metadata attached to this entity
2833
*/
2934
@Serializable
3035
public sealed interface WithMeta {
@@ -123,13 +128,19 @@ public enum class Role {
123128
*
124129
* References are used to point to other entities (prompts, resources, etc.)
125130
* without including their full definitions.
131+
*
132+
* @property type discriminator identifying the reference subtype
126133
*/
127134
@Serializable(with = ReferencePolymorphicSerializer::class)
128135
public sealed interface Reference {
129136
public val type: ReferenceType
130137
}
131138

132-
/** Discriminator for [Reference] subtypes used in completion and other operations. */
139+
/**
140+
* Discriminator for [Reference] subtypes used in completion and other operations.
141+
*
142+
* @property value serialized string representation of this reference type
143+
*/
133144
@Serializable
134145
public enum class ReferenceType(public val value: String) {
135146
@SerialName("ref/prompt")

0 commit comments

Comments
 (0)