= emptyMap())` | `CallToolResult` | Call a tool by name with arguments |
+
+#### Prompts
+
+| Method | Return Type | Description |
+|--------|-------------|-------------|
+| `listPrompts()` | `ListPromptsResult` | List all available prompts |
+| `getPrompt(request: GetPromptRequest)` | `GetPromptResult` | Get a specific prompt with arguments |
+
+#### Other Operations
+
+| Method | Return Type | Description |
+|--------|-------------|-------------|
+| `complete(request: CompleteRequest)` | `CompleteResult` | Request argument/URI completions |
+| `setLoggingLevel(level: LoggingLevel)` | `EmptyResult` | Set server logging level |
+| `ping()` | `EmptyResult` | Ping server to check connectivity |
+
+### Server API
+
+The `Server` class provides methods to expose MCP capabilities.
+
+#### Initialization
+
+```kotlin
+Server(
+ serverInfo: Implementation,
+ options: ServerOptions,
+ instructionsProvider: (() -> String)? = null,
+ block: Server.() -> Unit = {}
+)
+```
+
+#### Resource Management
+
+| Method | Description |
+|--------|-------------|
+| `addResource(uri, name, description, mimeType, handler)` | Add a resource with fixed URI |
+| `addResourceTemplate(uriTemplate, name, description, mimeType, handler)` | Add resource template with URI pattern |
+| `suspend fun sendResourceUpdated(uri: String)` | Notify clients that resource changed |
+| `suspend fun sendResourceListChanged()` | Notify clients that resource list changed |
+
+#### Tool Management
+
+| Method | Description |
+|--------|-------------|
+| `addTool(name, description, inputSchema, handler)` | Add a tool handler |
+| `suspend fun sendToolListChanged()` | Notify clients that tool list changed |
+
+#### Prompt Management
+
+| Method | Description |
+|--------|-------------|
+| `addPrompt(name, description, arguments, handler)` | Add a prompt template handler |
+| `suspend fun sendPromptListChanged()` | Notify clients that prompt list changed |
+
+#### Session Management
+
+| Method | Description |
+|--------|-------------|
+| `suspend fun createSession(transport: Transport): ServerSession` | Create new session with transport |
+| `fun onClose(handler: () -> Unit)` | Register close handler |
+
+### Capabilities Configuration
+
+#### Client Capabilities
+
+```kotlin
+val client = Client(
+ clientInfo = Implementation("my-client", "1.0.0"),
+ options = ClientOptions(
+ capabilities = ClientCapabilities(
+ roots = ClientCapabilities.Roots(listChanged = true),
+ sampling = ClientCapabilities.Sampling()
+ )
+ )
+)
+```
+
+#### Server Capabilities
+
+```kotlin
+val server = Server(
+ serverInfo = Implementation("my-server", "1.0.0"),
+ options = ServerOptions(
+ capabilities = ServerCapabilities(
+ resources = ServerCapabilities.Resources(
+ subscribe = true,
+ listChanged = true
+ ),
+ tools = ServerCapabilities.Tools(
+ listChanged = true
+ ),
+ prompts = ServerCapabilities.Prompts(
+ listChanged = true
+ ),
+ logging = ServerCapabilities.Logging()
+ )
+ )
+)
+```
+
+---
+
+## Testing
+
+### Unit Testing Servers
+
+```kotlin
+import io.modelcontextprotocol.kotlin.sdk.test.InMemoryTransport
+import kotlinx.coroutines.test.runTest
+import org.junit.jupiter.api.Test
+import kotlin.test.assertEquals
+
+class MyServerTest {
+ @Test
+ fun `test calculator tool`() = runTest {
+ // Arrange
+ val server = Server(
+ serverInfo = Implementation("test-server", "1.0.0"),
+ options = ServerOptions(
+ capabilities = ServerCapabilities(
+ tools = ServerCapabilities.Tools(listChanged = true)
+ )
+ )
+ )
+
+ server.addTool("add", "Adds two numbers") { request ->
+ val a = request.arguments?.get("a")?.jsonPrimitive?.double ?: 0.0
+ val b = request.arguments?.get("b")?.jsonPrimitive?.double ?: 0.0
+ CallToolResult(content = listOf(TextContent((a + b).toString())))
+ }
+
+ val transport = InMemoryTransport()
+ server.createSession(transport.serverEnd)
+
+ val client = Client(Implementation("test-client", "1.0.0"))
+ client.connect(transport.clientEnd)
+
+ // Act
+ val result = client.callTool("add", mapOf("a" to 5, "b" to 3))
+
+ // Assert
+ val content = result.content.first() as TextContent
+ assertEquals("8.0", content.text)
+ }
+}
+```
+
+### Test Utilities
+
+```kotlin
+dependencies {
+ testImplementation("io.modelcontextprotocol:kotlin-sdk-test:0.8.1")
+}
+```
+
+Available utilities:
+- `InMemoryTransport` - Fast in-process transport for unit tests
+
+---
+
+## Production Deployment
+
+### Error Handling
+
+```kotlin
+server.addTool("divide", "Divides two numbers") { request ->
+ try {
+ val a = request.arguments?.get("a")?.jsonPrimitive?.double
+ ?: throw McpException.InvalidParams("Missing parameter 'a'")
+ val b = request.arguments?.get("b")?.jsonPrimitive?.double
+ ?: throw McpException.InvalidParams("Missing parameter 'b'")
+
+ if (b == 0.0) {
+ throw McpException.InvalidParams("Cannot divide by zero")
+ }
+
+ CallToolResult(content = listOf(TextContent((a / b).toString())))
+
+ } catch (e: McpException) {
+ throw e // Re-throw MCP protocol errors
+ } catch (e: Exception) {
+ logger.error(e) { "Tool execution failed" }
+ throw McpException.InternalError("Calculation failed: ${e.message}")
+ }
+}
+```
+
+### Observability
+
+
+Structured Logging
+
+```kotlin
+import io.github.oshai.kotlinlogging.KotlinLogging
+
+val logger = KotlinLogging.logger {}
+
+server.onInitialized {
+ logger.info { "Server initialized and ready" }
+}
+
+server.addTool("example", "Example tool") { request ->
+ logger.info { "Tool called with args: ${request.arguments}" }
+ // Tool implementation
+ CallToolResult(content = listOf(TextContent("Result")))
+}
+```
+
+
+
+Metrics with Micrometer
+
+```kotlin
+import io.micrometer.core.instrument.MeterRegistry
+import io.micrometer.prometheus.PrometheusConfig
+import io.micrometer.prometheus.PrometheusMeterRegistry
+import kotlin.system.measureTimeMillis
+
+val registry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
+
+server.addTool("example", "Example tool") { request ->
+ val duration = measureTimeMillis {
+ // Tool implementation
+ }
+
+ registry.counter("mcp.tools.calls", "tool", "example").increment()
+ registry.timer("mcp.tools.duration", "tool", "example")
+ .record(java.time.Duration.ofMillis(duration))
+
+ CallToolResult(content = listOf(TextContent("Result")))
+}
+```
+
+
+
+Distributed Tracing
+
+```kotlin
+import io.opentelemetry.api.GlobalOpenTelemetry
+
+val tracer = GlobalOpenTelemetry.getTracer("mcp-server")
+
+server.addTool("example", "Example tool") { request ->
+ val span = tracer.spanBuilder("mcp.tool.example")
+ .setAttribute("tool.name", "example")
+ .startSpan()
+
+ try {
+ // Tool implementation
+ CallToolResult(content = listOf(TextContent("Result")))
+ } finally {
+ span.end()
+ }
+}
+```
+
+
+### Deployment Patterns
+
+
+Docker Container
+
+```dockerfile
+FROM eclipse-temurin:11-jre-alpine
+
+WORKDIR /app
+COPY build/libs/server.jar server.jar
+
+EXPOSE 8080
+
+ENTRYPOINT ["java", "-jar", "server.jar"]
+```
+
+```bash
+docker build -t my-mcp-server .
+docker run -p 8080:8080 -e API_KEY=secret my-mcp-server
+```
+
+
+
+Kubernetes Deployment
+
+```yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: mcp-server
+spec:
+ replicas: 3
+ selector:
+ matchLabels:
+ app: mcp-server
+ template:
+ metadata:
+ labels:
+ app: mcp-server
+ spec:
+ containers:
+ - name: mcp-server
+ image: myorg/mcp-server:1.0.0
+ ports:
+ - containerPort: 8080
+ env:
+ - name: API_KEY
+ valueFrom:
+ secretKeyRef:
+ name: mcp-secrets
+ key: api-key
+ resources:
+ requests:
+ memory: "512Mi"
+ cpu: "500m"
+ limits:
+ memory: "1Gi"
+ cpu: "1000m"
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: mcp-server
+spec:
+ selector:
+ app: mcp-server
+ ports:
+ - port: 80
+ targetPort: 8080
+ type: LoadBalancer
+```
+
+
+---
+
+## Security
+
+### Authentication
+
+```kotlin
+// Custom authentication middleware
+class AuthenticatedServer(
+ serverInfo: Implementation,
+ options: ServerOptions,
+ private val validateToken: (String) -> Boolean
+) : Server(serverInfo, options) {
+
+ init {
+ onRequest { request ->
+ val token = request.meta?.get("authorization")?.jsonPrimitive?.content
+ ?: throw McpException.InvalidParams("Missing authorization")
+
+ if (!validateToken(token)) {
+ throw McpException.InvalidParams("Invalid authorization")
+ }
+ }
+ }
+}
+
+// Client with authentication
+val client = Client(Implementation("secure-client", "1.0.0"))
+client.setDefaultMeta(mapOf(
+ "authorization" to System.getenv("MCP_TOKEN")
+))
+```
+
+### Tool Sandboxing
+
+```kotlin
+// Restrict dangerous operations
+val ALLOWED_COMMANDS = setOf("ls", "cat", "grep")
+
+server.addTool("execute", "Executes shell command") { request ->
+ val command = request.arguments?.get("command")?.jsonPrimitive?.content
+ ?: throw McpException.InvalidParams("Missing command")
+
+ val parts = command.split(" ")
+ if (parts.first() !in ALLOWED_COMMANDS) {
+ throw McpException.InvalidParams("Command not allowed: ${parts.first()}")
+ }
+
+ // Execute in restricted environment
+ val result = ProcessBuilder(parts).start().inputStream.bufferedReader().readText()
+ CallToolResult(content = listOf(TextContent(result)))
+}
+```
+
+### TLS Configuration
+
+```kotlin
+import io.ktor.network.tls.certificates.*
+import java.io.File
+
+embeddedServer(Netty, port = 8080) {
+ // Production TLS
+ sslConnector(
+ keyStore = generateCertificate(
+ file = File("keystore.jks"),
+ keyAlias = "mcp-server",
+ keyPassword = "changeit",
+ jksPassword = "changeit"
+ ),
+ keyAlias = "mcp-server",
+ keyStorePassword = { "changeit".toCharArray() },
+ privateKeyPassword = { "changeit".toCharArray() }
+ ) {
+ port = 8443
+ }
+
+ mcp { /* server config */ }
+}.start(wait = true)
+```
+
+---
+
+## Troubleshooting
+
+### Common Issues
+
+
+"Could not find Ktor engine" Error
+
+**Error:**
+```
+java.lang.ClassNotFoundException: io.ktor.client.engine.cio.CIOEngine
+```
+
+**Solution:**
+Add a Ktor client engine dependency:
+```kotlin
+dependencies {
+ implementation("io.ktor:ktor-client-cio:3.0.0")
+}
+```
+
+
+
+Transport Connection Failures
+
+**Symptoms:** `TimeoutException`, `ConnectionRefusedException`
+
+**Checklist:**
+- β
Server process is running before client connects
+- β
Correct transport type (stdio, SSE, WebSocket)
+- β
Firewall allows connections (for network transports)
+- β
Correct host/port in client configuration
+- β
Server logs show successful startup
+
+**Debug stdio transport:**
+```kotlin
+// Server: Add debug output
+fun main() = runBlocking {
+ System.err.println("Server starting...")
+ val server = Server(...)
+ System.err.println("Server ready")
+ // ... rest of setup
+}
+```
+
+**Debug network transports:**
+```bash
+# Test SSE endpoint
+curl http://localhost:8080/sse
+
+# Test WebSocket endpoint
+wscat -c ws://localhost:8080/mcp
+```
+
+
+
+Tools Not Discovered
+
+**Issue:** `client.listTools()` returns empty list
+
+**Solutions:**
+1. Verify capabilities are configured:
+```kotlin
+ServerCapabilities(
+ tools = ServerCapabilities.Tools(listChanged = true) // Required
+)
+```
+
+2. Ensure tools are added before creating session:
+```kotlin
+server.addTool(...) // BEFORE this:
+server.createSession(transport)
+```
+
+3. Check tool registration:
+```kotlin
+server.addTool("my-tool", ...) { request ->
+ println("Tool called!") // Debug output
+ CallToolResult(...)
+}
+```
+
+
+
+Serialization Errors
+
+**Error:**
+```
+kotlinx.serialization.SerializationException: Unexpected JSON token
+```
+
+**Common causes:**
+- Invalid JSON in tool arguments
+- Incorrect `inputSchema` type definitions
+- Missing required fields in response objects
+
+**Solution:**
+Validate input schema matches arguments:
+```kotlin
+server.addTool(
+ name = "example",
+ inputSchema = ToolSchema(
+ properties = buildJsonObject {
+ putJsonObject("name") {
+ put("type", "string") // Must match argument type
+ }
+ },
+ required = listOf("name") // Mark required fields
+ )
+) { request ->
+ // Validate manually if needed
+ val name = request.arguments?.get("name")?.jsonPrimitive?.content
+ ?: throw McpException.InvalidParams("Missing required field: name")
+
+ CallToolResult(...)
+}
+```
+
+
+### Getting Help
+
+- π **Specification**: [spec.modelcontextprotocol.io](https://spec.modelcontextprotocol.io)
+- π¬ **Discord**: [MCP Community](https://discord.gg/modelcontextprotocol)
+- π **Issues**: [GitHub Issues](https://github.com/modelcontextprotocol/kotlin-sdk/issues)
+- π **Inspector**: [MCP Inspector](https://github.com/modelcontextprotocol/inspector) - Debug tool for testing servers
+
+---
+
+## Migration Guides
+
+### From Direct LLM APIs
+
+
+Migrating from Anthropic SDK
+
+**Before (Direct API):**
+```kotlin
+val anthropic = Anthropic(apiKey)
+val response = anthropic.messages.create(
+ model = "claude-3-5-sonnet-20241022",
+ maxTokens = 1024,
+ tools = listOf(
+ Tool.builder()
+ .name("get_weather")
+ .description("Get weather")
+ .inputSchema(/* manual schema */)
+ .build()
+ ),
+ messages = listOf(/* messages */)
+)
+
+// Manual tool execution
+if (response.stopReason == StopReason.TOOL_USE) {
+ val toolCall = response.content.first { it.isToolUse() }.toolUse()
+ when (toolCall.name) {
+ "get_weather" -> {
+ val result = WeatherAPI.fetch(/* hard-coded */)
+ // Send back to API...
+ }
+ }
+}
+```
+
+**After (MCP):**
+```kotlin
+// 1. Create reusable MCP server (once)
+val mcpServer = Server(...)
+mcpServer.addTool("get_weather", ...) { request ->
+ CallToolResult(content = listOf(TextContent(WeatherAPI.fetch(...))))
+}
+
+// 2. Connect MCP client
+val mcpClient = Client(...)
+mcpClient.connect(transport)
+
+// 3. Tools auto-discovered
+val tools = mcpClient.listTools() // Discovers get_weather
+
+// 4. Use with Anthropic (or any LLM)
+val anthropic = Anthropic(apiKey)
+val response = anthropic.messages.create(
+ tools = tools.toAnthropicFormat(), // Auto-converted
+ // ... rest
+)
+
+// 5. Protocol-handled execution
+if (response.stopReason == StopReason.TOOL_USE) {
+ val toolCall = response.content.first { it.isToolUse() }.toolUse()
+ val result = mcpClient.callTool(toolCall.name, toolCall.input)
+}
+```
+
+**Benefits:**
+- β
Tools work with any LLM (Claude, GPT-4, Gemini)
+- β
Reusable across applications
+- β
Shareable with team/community
+- β
Standardized discovery and execution
+
+
+### From TypeScript SDK
+
+
+Key Differences
+
+| Concept | TypeScript | Kotlin |
+|---------|-----------|--------|
+| **Async Model** | `async/await` | `suspend fun` + coroutines |
+| **Error Handling** | `try/catch` + Promises | `try/catch` + structured concurrency |
+| **Types** | Interfaces | Data classes |
+| **Null Safety** | `Type \| undefined` | `Type?` with null safety |
+| **Imports** | `import { Client } from '@modelcontextprotocol/sdk'` | `import io.modelcontextprotocol.kotlin.sdk.client.Client` |
+
+**TypeScript:**
+```typescript
+import { Client } from '@modelcontextprotocol/sdk/client/index.js';
+
+const client = new Client({
+ name: "my-client",
+ version: "1.0.0"
+});
+
+await client.connect(transport);
+const tools = await client.listTools();
+```
+
+**Kotlin:**
+```kotlin
+import io.modelcontextprotocol.kotlin.sdk.client.Client
+import io.modelcontextprotocol.kotlin.sdk.types.Implementation
+
+val client = Client(
+ clientInfo = Implementation(
+ name = "my-client",
+ version = "1.0.0"
+ )
+)
+
+client.connect(transport)
+val tools = client.listTools()
+```
+
+
+---
+
+## Examples
+
+### Complete Examples
+
+| Example | Description | Location |
+|---------|-------------|----------|
+| **Multiplatform Server** | MCP server with multiple transports (JVM, Wasm) | [kotlin-mcp-server](./samples/kotlin-mcp-server) |
+| **Weather Server** | Real-world API integration with stdio transport | [weather-stdio-server](./samples/weather-stdio-server) |
+| **AI Client** | Interactive client with Anthropic API integration | [kotlin-mcp-client](./samples/kotlin-mcp-client) |
+
+### Community Servers
+
+Explore pre-built MCP servers at [mcp.run](https://mcp.run):
+- π **File systems**: Google Drive, Dropbox, S3
+- ποΈ **Databases**: PostgreSQL, MongoDB, Supabase
+- π **Search**: Brave, Perplexity, Exa
+- π» **Development**: GitHub, Linear, Sentry
+- π **Data**: Snowflake, BigQuery, Airtable
+
+> **Note:** Community servers may be in TypeScript or Python. This SDK can connect to any MCP server regardless of implementation language.
+
+---
+
+## Contributing
+
+We welcome contributions! Please see:
+
+- [Contributing Guide](CONTRIBUTING.md) - Development setup, testing, PR process
+- [Code of Conduct](CODE_OF_CONDUCT.md) - Community guidelines
+- [Architecture](ARCHITECTURE.md) - Codebase structure and design decisions
+
+### Quick Start for Contributors
+
+```bash
+# Clone repository
+git clone https://github.com/modelcontextprotocol/kotlin-sdk.git
+cd kotlin-sdk
+
+# Build
+./gradlew build
+
+# Run tests
+./gradlew test
+
+# Run samples
+./gradlew :samples:weather-stdio-server:run
+```
+
+---
+
+## License
+
+This project is licensed under the MIT Licenseβsee the [LICENSE](LICENSE) file for details.
+
+### Third-Party Dependencies
+
+This SDK depends on:
+- **Kotlin** (Apache 2.0)
+- **Ktor** (Apache 2.0)
+- **kotlinx-coroutines** (Apache 2.0)
+- **kotlinx-serialization** (Apache 2.0)
+
+---
+
+## Additional Resources
+
+- π **MCP Specification**: [spec.modelcontextprotocol.io](https://spec.modelcontextprotocol.io)
+- π **Official Website**: [modelcontextprotocol.io](https://modelcontextprotocol.io)
+- π¦ **TypeScript SDK**: [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk)
+- π **Python SDK**: [mcp](https://github.com/modelcontextprotocol/python-sdk)
+- π **MCP Inspector**: [Debug tool](https://github.com/modelcontextprotocol/inspector)
+- π¬ **Community Discord**: [Join here](https://discord.gg/modelcontextprotocol)
+
+---
+
+
+ Built with β€οΈ by the MCP community
+
diff --git a/build.gradle.kts b/build.gradle.kts
index f7f3ef4c..c42772a1 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,5 +1,6 @@
plugins {
id("mcp.dokka")
+ id("knit-convention")
alias(libs.plugins.ktlint)
alias(libs.plugins.kover)
}
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index 84676a4f..2d61cad7 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -13,4 +13,5 @@ dependencies {
implementation(libs.kotlinx.atomicfu.gradle)
implementation(libs.dokka.gradle)
implementation(libs.maven.publish)
+ implementation(libs.kotlinx.knit)
}
diff --git a/buildSrc/src/main/kotlin/knit-convention.gradle.kts b/buildSrc/src/main/kotlin/knit-convention.gradle.kts
new file mode 100644
index 00000000..de6ab6d0
--- /dev/null
+++ b/buildSrc/src/main/kotlin/knit-convention.gradle.kts
@@ -0,0 +1,11 @@
+plugins {
+ id("org.jetbrains.kotlinx.knit")
+}
+knit {
+ rootDir = projectDir
+ files = fileTree(projectDir) {
+ include("README.md")
+ }
+ defaultLineSeparator = "\n"
+ siteRoot = "" // Disable site root validation
+}
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000..6a306c45
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,2 @@
+## Knit-generated sources
+src/
diff --git a/docs/build.gradle.kts b/docs/build.gradle.kts
new file mode 100644
index 00000000..99b5f655
--- /dev/null
+++ b/docs/build.gradle.kts
@@ -0,0 +1,27 @@
+import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
+
+plugins {
+ id("mcp.multiplatform")
+}
+
+kotlin {
+ jvm()
+
+ explicitApi = ExplicitApiMode.Disabled
+
+ sourceSets {
+ jvmMain {
+ dependencies {
+ implementation(project(":kotlin-sdk"))
+ implementation(libs.kotlinx.coroutines.core)
+ implementation(libs.kotlinx.io.core)
+ implementation(libs.ktor.server.core)
+ implementation(libs.ktor.server.sse)
+ }
+ }
+ }
+}
+
+tasks.clean {
+ delete("src")
+}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index d5a19ee6..c421e532 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,13 +1,14 @@
[versions]
# plugins version
-kotlin = "2.2.21"
-dokka = "2.1.0"
atomicfu = "0.29.0"
-ktlint = "14.0.1"
+binaryCompatibilityValidatorPlugin = "0.18.1"
+dokka = "2.1.0"
+knit = "0.5.0"
+kotlin = "2.2.21"
kover = "0.9.3"
-netty = "4.2.7.Final"
+ktlint = "14.0.1"
mavenPublish = "0.35.0"
-binaryCompatibilityValidatorPlugin = "0.18.1"
+netty = "4.2.7.Final"
openapi-generator = "7.17.0"
# libraries version
@@ -30,6 +31,7 @@ dokka-gradle = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref
kotlin-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
kotlin-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin" }
kotlinx-atomicfu-gradle = { module = "org.jetbrains.kotlinx:atomicfu-gradle-plugin", version.ref = "atomicfu" }
+kotlinx-knit = { module = "org.jetbrains.kotlinx:kotlinx-knit", version.ref = "knit" }
maven-publish = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "mavenPublish" }
# Kotlinx libraries
diff --git a/knit.properties b/knit.properties
new file mode 100644
index 00000000..f761ad73
--- /dev/null
+++ b/knit.properties
@@ -0,0 +1,3 @@
+# Knit configuration
+knit.package = io.modelcontextprotocol.kotlin.sdk.examples
+knit.dir = docs/src/jvmMain/kotlin
diff --git a/settings.gradle.kts b/settings.gradle.kts
index d7ec54f8..cad1322f 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -23,5 +23,6 @@ include(
":kotlin-sdk-server",
":kotlin-sdk",
":kotlin-sdk-test",
+ ":docs",
":conformance-test",
)