docs: Update readme, enable Knit (#162) (#510)

#162 

## Motivation and Context
- update readme
- add more snippets 
- add knit

## How Has This Been Tested?
knit on CI

## 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: devcrocod <devcrocod@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Konstantin Pavlov 2026-02-06 18:40:31 +02:00 • committed by GitHub
commit adc4150f1f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 1093 additions and 195 deletions

View file

@ -7,6 +7,10 @@ on:
# Allow running this workflow manually from the Actions tab
workflow_dispatch:
env:
JAVA_VERSION: 21
JAVA_DISTRIBUTION: temurin
jobs:
deploy:
@ -25,11 +29,11 @@ jobs:
submodules: true # Fetch Hugo themes (true OR recursive)
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
- name: Set up JDK 21
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v5
with:
java-version: '21'
distribution: 'temurin'
java-version: ${{ env.JAVA_VERSION }}
distribution: ${{ env.JAVA_DISTRIBUTION }}
cache: gradle
- name: Setup Gradle
@ -37,7 +41,7 @@ jobs:
- name: Generate Dokka Site
run: |-
./gradlew clean dokkaGenerate
./gradlew clean knit docs:classes docs:knitCheck dokkaGenerate
- name: Upload artifact
uses: actions/upload-pages-artifact@v4

View file

@ -120,6 +120,40 @@ jobs:
path: local-maven-repository.zip
retention-days: 1
knit:
runs-on: ubuntu-latest
name: Knit
timeout-minutes: 10
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v5
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: ${{ env.JAVA_DISTRIBUTION }}
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5
with:
validate-wrappers: true
add-job-summary: 'always'
cache-read-only: ${{ github.ref != 'refs/heads/main' }}
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
gradle-home-cache-includes: |
caches
notifications
sdks
../.konan/**
- name: Run Knit
run: |-
./gradlew knit docs:classes docs:knitCheck -x :conformance-test:test --max-workers 3 --continue --rerun-tasks --configure-on-demand --parallel
samples:
needs: [ build ]
runs-on: ubuntu-latest

842
README.md
View file

@ -1,6 +1,5 @@
# MCP Kotlin SDK
[![Maven Central](https://img.shields.io/maven-central/v/io.modelcontextprotocol/kotlin-sdk.svg?label=Maven%20Central)](https://central.sonatype.com/artifact/io.modelcontextprotocol/kotlin-sdk)
[![Build](https://github.com/modelcontextprotocol/kotlin-sdk/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/modelcontextprotocol/kotlin-sdk/actions/workflows/build.yml)
[![Conformance Tests](https://github.com/modelcontextprotocol/kotlin-sdk/actions/workflows/conformance.yml/badge.svg)](https://github.com/modelcontextprotocol/kotlin-sdk/actions/workflows/conformance.yml)
@ -9,100 +8,306 @@
[![JVM](https://img.shields.io/badge/JVM-11+-red.svg?logo=jvm)](http://java.com)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
Kotlin Multiplatform implementation of the [Model Context Protocol](https://modelcontextprotocol.io) (MCP),
providing both client and server capabilities for integrating with LLM surfaces across various platforms.
Kotlin Multiplatform SDK for the [Model Context Protocol](https://modelcontextprotocol.io).
It enables Kotlin applications targeting JVM, Native, JS, and Wasm to implement MCP clients and servers using a
standardized protocol interface.
## Table of Contents
<!--- TOC -->
* [Overview](#overview)
* [Installation](#installation)
* [Artifacts](#artifacts)
* [Gradle setup (JVM)](#gradle-setup-jvm)
* [Multiplatform](#multiplatform)
* [Ktor dependencies](#ktor-dependencies)
* [Quickstart](#quickstart)
* [Creating a Client](#creating-a-client)
* [Creating a Server](#creating-a-server)
* [Core Concepts](#core-concepts)
* [MCP Primitives](#mcp-primitives)
* [Capabilities](#capabilities)
* [Server Capabilities](#server-capabilities)
* [Client Capabilities](#client-capabilities)
* [Server Features](#server-features)
* [Prompts](#prompts)
* [Resources](#resources)
* [Tools](#tools)
* [Completion](#completion)
* [Logging](#logging)
* [Pagination](#pagination)
* [Client Features](#client-features)
* [Roots](#roots)
* [Sampling](#sampling)
* [Transports](#transports)
* [STDIO Transport](#stdio-transport)
* [Streamable HTTP Transport](#streamable-http-transport)
* [SSE Transport](#sse-transport)
* [WebSocket Transport](#websocket-transport)
* [Connecting your server](#connecting-your-server)
* [Examples](#examples)
* [Documentation](#documentation)
* [Contributing](#contributing)
* [License](#license)
<!--- END -->
## Overview
The Model Context Protocol allows applications to provide context for LLMs in a standardized way,
separating the concerns of providing context from the actual LLM interaction.
This SDK implements the MCP specification for Kotlin,
enabling you to build applications that can communicate using MCP on the JVM, WebAssembly and iOS.
This Kotlin SDK implements the MCP specification, making it easy to:
- Build MCP clients that can connect to any MCP server
- Create MCP servers that expose resources, prompts and tools
- Use standard transports like stdio, SSE, and WebSocket
- Handle all MCP protocol messages and lifecycle events
## Samples
- [kotlin-mcp-server](./samples/kotlin-mcp-server): demonstrates a multiplatform (JVM, Wasm) MCP server setup with various features and transports.
- [weather-stdio-server](./samples/weather-stdio-server): shows how to build a Kotlin MCP server providing weather forecast and alerts using STDIO transport.
- [kotlin-mcp-client](./samples/kotlin-mcp-client): demonstrates building an interactive Kotlin MCP client that connects to an MCP server via STDIO and integrates with Anthropic’s API.
- Build MCP **clients** that can connect to any MCP server
- Create MCP **servers** that expose resources, prompts, and tools
- Target **JVM, Native, JS, and Wasm** from a single codebase
- Use standard transports like **stdio**, **SSE**, **Streamable HTTP**, and **WebSocket**
- Handle MCP protocol messages and lifecycle events with coroutine-friendly APIs
## Installation
Add the new repository to your build file:
### Artifacts
- `io.modelcontextprotocol:kotlin-sdk` – umbrella SDK (client + server APIs)
- `io.modelcontextprotocol:kotlin-sdk-client` – client-only APIs
- `io.modelcontextprotocol:kotlin-sdk-server` – server-only APIs
### Gradle setup (JVM)
Add the Maven Central repository and the SDK dependency:
```kotlin
repositories {
mavenCentral()
}
```
Add the dependency:
```kotlin
dependencies {
// See the badge above for the latest version
implementation("io.modelcontextprotocol:kotlin-sdk:$mcpVersion")
}
```
MCP SDK uses [Ktor](https://ktor.io/), but does not come with a specific engine dependency.
You should add [Ktor client](https://ktor.io/docs/client-dependencies.html#engine-dependency)
and/or [Ktor server](https://ktor.io/docs/client-dependencies.html#engine-dependency) dependency
to your project yourself, e.g.:
Use _kotlin-sdk-client_ or _kotlin-sdk-server_ if you only need one side of the API:
```kotlin
dependencies {
// for client:
implementation("io.ktor:ktor-client-cio:$ktorVersion")
// for server:
implementation("io.ktor:ktor-server-netty:$ktorVersion")
implementation("io.modelcontextprotocol:kotlin-sdk-client:$mcpVersion")
implementation("io.modelcontextprotocol:kotlin-sdk-server:$mcpVersion")
}
```
## Quick Start
### Multiplatform
In a Kotlin Multiplatform project you can add the SDK to commonMain:
```kotlin
commonMain {
dependencies {
// Works as a common dependency as well as the platform one
implementation("io.modelcontextprotocol:kotlin-sdk:$mcpVersion")
}
}
```
### Ktor dependencies
The Kotlin MCP SDK uses [Ktor](https://ktor.io/), but it does not add Ktor engine dependencies transitively.
You need to declare
Ktor [client](https://ktor.io/docs/client-dependencies.html#engine-dependency)/[server](https://ktor.io/docs/server-dependencies.html)
dependencies yourself (or reuse the ones already used in your project),
for example:
```kotlin
dependencies {
// MCP client with Ktor
implementation("io.ktor:ktor-client-cio:$ktorVersion")
implementation("io.modelcontextprotocol:kotlin-sdk-client:$mcpVersion")
// MCP server with Ktor
implementation("io.ktor:ktor-server-netty:$ktorVersion")
implementation("io.modelcontextprotocol:kotlin-sdk-server:$mcpVersion")
}
```
## Quickstart
Let's create a simple MCP client and server to demonstrate the basic usage of the Kotlin SDK.
<!--- CLEAR -->
### Creating a Client
Create an MCP client that connects to a server via Streamable HTTP transport and lists available tools:
```kotlin
import io.ktor.client.HttpClient
import io.ktor.client.plugins.sse.SSE
import io.modelcontextprotocol.kotlin.sdk.client.Client
import io.modelcontextprotocol.kotlin.sdk.client.StdioClientTransport
import io.modelcontextprotocol.kotlin.sdk.Implementation
import io.modelcontextprotocol.kotlin.sdk.client.StreamableHttpClientTransport
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import kotlinx.coroutines.runBlocking
val client = Client(
clientInfo = Implementation(
name = "example-client",
version = "1.0.0"
fun main(args: Array<String>) = runBlocking {
val url = args.firstOrNull() ?: "http://localhost:3000/mcp"
val httpClient = HttpClient { install(SSE) }
val client = Client(
clientInfo = Implementation(
name = "example-client",
version = "1.0.0"
)
)
)
val transport = StdioClientTransport(
inputStream = processInputStream,
outputStream = processOutputStream
)
val transport = StreamableHttpClientTransport(
client = httpClient,
url = url
)
// Connect to server
client.connect(transport)
// Connect to server
client.connect(transport)
// List available resources
val resources = client.listResources()
// List available tools
val tools = client.listTools().tools
// Read a specific resource
val resourceContent = client.readResource(
ReadResourceRequest(uri = "file:///example.txt")
)
println(tools)
}
```
<!--- KNIT example-quickstart-client-01.kt -->
### Creating a Server
Create an MCP server that exposes a simple tool and runs on an embedded Ktor server with SSE transport:
```kotlin
import io.ktor.server.cio.CIO
import io.ktor.server.engine.embeddedServer
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport
import io.modelcontextprotocol.kotlin.sdk.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.server.mcp
import io.modelcontextprotocol.kotlin.sdk.types.CallToolResult
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
import io.modelcontextprotocol.kotlin.sdk.types.ToolSchema
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
fun main(args: Array<String>) {
val port = args.firstOrNull()?.toIntOrNull() ?: 3000
val mcpServer = Server(
serverInfo = Implementation(
name = "example-server",
version = "1.0.0"
),
options = ServerOptions(
capabilities = ServerCapabilities(
tools = ServerCapabilities.Tools(listChanged = true),
),
)
)
mcpServer.addTool(
name = "example-tool",
description = "An example tool",
inputSchema = ToolSchema(
properties = buildJsonObject {
put("input", buildJsonObject { put("type", "string") })
}
)
) { request ->
CallToolResult(content = listOf(TextContent("Hello, world!")))
}
embeddedServer(CIO, host = "127.0.0.1", port = port) {
mcp {
mcpServer
}
}.start(wait = true)
}
```
<!--- KNIT example-quickstart-server-01.kt -->
You can run the server and then connect to it using the client or test with the MCP Inspector:
```bash
npx -y @modelcontextprotocol/inspector
```
In the inspector UI, connect to `http://localhost:3000`.
## Core Concepts
### MCP Primitives
The MCP protocol defines core primitives that enable communication between servers and clients:
| Primitive | Server Role | Client Role | Description |
|---------------|---------------------------------------------------|----------------------------------------|---------------------------------------------------|
| **Prompts** | Provides prompt templates with optional arguments | Requests and uses prompts | Interactive templates for LLM interactions |
| **Resources** | Exposes data sources (files, API responses, etc.) | Reads and subscribes to resources | Contextual data for augmenting LLM context |
| **Tools** | Defines executable functions | Calls tools to perform actions | Functions the LLM can invoke to take actions |
| **Sampling** | Requests LLM completions from client | Executes LLM calls and returns results | Server-initiated LLM requests (reverse direction) |
### Capabilities
Capabilities define what features a server or client supports. They are declared during initialization and determine
what operations are available.
#### Server Capabilities
Servers declare their capabilities to inform clients what features they provide:
| Capability | Feature Flags | Description |
|----------------|-------------------------------|------------------------------------------------------------|
| `prompts` | `listChanged` | Prompt template management and notifications |
| `resources` | `subscribe`<br/>`listChanged` | Resource exposure, subscriptions, and update notifications |
| `tools` | `listChanged` | Tool discovery, execution, and list change notifications |
| `logging` | - | Server logging to client console |
| `completions` | - | Argument autocompletion suggestions |
| `experimental` | Custom properties | Non-standard experimental features |
#### Client Capabilities
Clients declare their capabilities to inform servers what features they support:
| Capability | Feature Flags | Description |
|----------------|-------------------|-------------------------------------------------------------|
| `sampling` | - | Client can sample from an LLM (execute model requests) |
| `roots` | `listChanged` | Client exposes root directories and can notify of changes |
| `elicitation` | - | Client can display schema/form dialogs for structured input |
| `experimental` | Custom properties | Non-standard experimental features |
### Server Features
The `Server` API lets you wire prompts, resources, and tools with only a few lines of Kotlin. Each feature is registered
up front and then resolved lazily when a client asks for it, so your handlers stay small and suspendable.
#### Prompts
Prompts are user-controlled templates that clients discover via `prompts/list` and fetch with `prompts/get` when a user
chooses one (think slash commands or saved flows). They’re best for repeatable, structured starters rather than ad-hoc
model calls.
<!--- INCLUDE
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.types.GetPromptResult
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.PromptArgument
import io.modelcontextprotocol.kotlin.sdk.types.PromptMessage
import io.modelcontextprotocol.kotlin.sdk.types.Role
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
fun main() {
-->
```kotlin
val server = Server(
serverInfo = Implementation(
name = "example-server",
@ -110,97 +315,498 @@ val server = Server(
),
options = ServerOptions(
capabilities = ServerCapabilities(
resources = ServerCapabilities.Resources(
subscribe = true,
listChanged = true
)
)
prompts = ServerCapabilities.Prompts(listChanged = true),
),
)
){
"This server provides example resources and demonstrates MCP capabilities."
)
server.addPrompt(
name = "code-review",
description = "Ask the model to review a diff",
arguments = listOf(
PromptArgument(name = "diff", description = "Unified diff", required = true),
),
) { request ->
GetPromptResult(
description = "Quick code review helper",
messages = listOf(
PromptMessage(
role = Role.User,
content = TextContent(text = "Review this change:\n${request.arguments?.get("diff")}"),
),
),
)
}
```
<!--- SUFFIX
}
-->
<!--- KNIT example-server-prompts-01.kt -->
Use prompts for anything that deserves a template: bug triage questions, onboarding checklists, or saved searches. Set
`listChanged = true` only if your prompt catalog can change at runtime and your server will emit
`notifications/prompts/list_changed` when it does.
#### Resources
Resources are application-driven context that clients discover via `resources/list` or `resources/templates/list`, then
fetch with `resources/read`. Register each one with a stable URI and return a `ReadResourceResult` when asked—contents
can be text or binary blobs.
<!--- INCLUDE
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.ReadResourceResult
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.TextResourceContents
fun main() {
-->
```kotlin
val server = Server(
serverInfo = Implementation(
name = "example-server",
version = "1.0.0"
),
options = ServerOptions(
capabilities = ServerCapabilities(
resources = ServerCapabilities.Resources(subscribe = true, listChanged = true),
),
)
)
// Add a resource
server.addResource(
uri = "file:///example.txt",
name = "Example Resource",
description = "An example text file",
mimeType = "text/plain"
uri = "note://release/latest",
name = "Release notes",
description = "Last deployment summary",
mimeType = "text/markdown",
) { request ->
ReadResourceResult(
contents = listOf(
TextResourceContents(
text = "This is the content of the example resource.",
text = "Ship 42 reached production successfully.",
uri = request.uri,
mimeType = "text/plain"
)
)
mimeType = "text/markdown",
),
),
)
}
// Start server with stdio transport
val transport = StdioServerTransport()
server.connect(transport)
```
### Using SSE Transport
<!--- SUFFIX
}
-->
<!--- KNIT example-server-resources-01.kt -->
Resources can be static text, generated JSON, or blobs—anything the client can surface to the user or inject into the
model context. Set `subscribe = true` if you emit `notifications/resources/updated` for changes to specific URIs, and
`listChanged = true` if you’ll send `notifications/resources/list_changed` when the catalog itself changes.
#### Tools
Tools are model-controlled capabilities the client exposes to the model. Clients discover them via `tools/list`, invoke
them with `tools/call`, and your handlers receive JSON arguments, can emit streaming logs or progress, and return a
`CallToolResult`. Keep a human in the loop for sensitive operations.
<!--- INCLUDE
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.types.CallToolResult
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
import kotlinx.serialization.json.jsonPrimitive
fun main() {
-->
Directly in Ktor's `Application`:
```kotlin
import io.ktor.server.application.*
import io.modelcontextprotocol.kotlin.sdk.server.mcp
val server = Server(
serverInfo = Implementation(
name = "example-server",
version = "1.0.0"
),
options = ServerOptions(
capabilities = ServerCapabilities(
tools = ServerCapabilities.Tools(listChanged = true),
),
)
)
fun Application.module() {
mcp {
Server(
serverInfo = Implementation(
name = "example-sse-server",
version = "1.0.0"
),
options = ServerOptions(
capabilities = ServerCapabilities(
prompts = ServerCapabilities.Prompts(listChanged = null),
resources = ServerCapabilities.Resources(subscribe = null, listChanged = null)
)
),
) {
"This SSE server provides prompts and resources via Server-Sent Events."
}
}
server.addTool(
name = "echo",
description = "Return whatever the user sent back to them",
) { request ->
val text = request.arguments?.get("text")?.jsonPrimitive?.content ?: "(empty)"
CallToolResult(content = listOf(TextContent(text = "Echo: $text")))
}
```
Inside a custom Ktor's `Route`:
<!--- SUFFIX
}
-->
<!--- KNIT example-server-tools-01.kt -->
Register as many tools as you need—long-running jobs can report progress via the request context, and tools can also
trigger sampling (see below) when they need the client’s LLM. Set `listChanged = true` only if your tool catalog can
change at runtime and your server will emit `notifications/tools/list_changed` when it does.
#### Completion
Completion provides argument suggestions for prompts or resource templates. Declare the `completions` capability and
handle `completion/complete` requests to return up to 100 ranked values (include `total`/`hasMore` if you paginate).
<!--- INCLUDE
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport
import io.modelcontextprotocol.kotlin.sdk.types.CompleteRequest
import io.modelcontextprotocol.kotlin.sdk.types.CompleteResult
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.Method
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import kotlinx.io.asSink
import kotlinx.io.asSource
import kotlinx.io.buffered
suspend fun main() {
-->
```kotlin
import io.ktor.server.application.*
import io.ktor.server.sse.SSE
import io.modelcontextprotocol.kotlin.sdk.server.mcp
val server = Server(
serverInfo = Implementation(
name = "example-server",
version = "1.0.0"
),
options = ServerOptions(
capabilities = ServerCapabilities(
completions = ServerCapabilities.Completions,
),
)
)
fun Application.module() {
install(SSE)
val session = server.createSession(
StdioServerTransport(
inputStream = System.`in`.asSource().buffered(),
outputStream = System.out.asSink().buffered()
)
)
routing {
route("myRoute") {
mcp {
Server(
serverInfo = Implementation(
name = "example-sse-server",
version = "1.0.0"
),
options = ServerOptions(
capabilities = ServerCapabilities(
prompts = ServerCapabilities.Prompts(listChanged = null),
resources = ServerCapabilities.Resources(subscribe = null, listChanged = null)
)
),
) {
"Connect via SSE to interact with this MCP server."
}
}
}
}
session.setRequestHandler<CompleteRequest>(Method.Defined.CompletionComplete) { request, _ ->
val options = listOf("kotlin", "compose", "coroutine")
val matches = options.filter { it.startsWith(request.argument.value.lowercase()) }
CompleteResult(
completion = CompleteResult.Completion(
values = matches.take(3),
total = matches.size,
hasMore = matches.size > 3,
),
)
}
```
<!--- SUFFIX
}
-->
<!--- KNIT example-server-util-completions-01.kt -->
Use `context.arguments` to refine suggestions for dependent fields (e.g., framework list filtered by chosen language).
#### Logging
Logging lets the server stream structured log notifications to the client using RFC 5424 levels (`debug` → `emergency`).
Declare the `logging` capability; clients can raise the minimum level with `logging/setLevel`, and the server emits
`notifications/message` with severity, optional logger name, and JSON data.
<!--- INCLUDE
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.LoggingLevel
import io.modelcontextprotocol.kotlin.sdk.types.LoggingMessageNotification
import io.modelcontextprotocol.kotlin.sdk.types.LoggingMessageNotificationParams
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import kotlinx.io.asSink
import kotlinx.io.asSource
import kotlinx.io.buffered
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
suspend fun main() {
-->
```kotlin
val server = Server(
serverInfo = Implementation("example-server", "1.0.0"),
options = ServerOptions(
capabilities = ServerCapabilities(
logging = ServerCapabilities.Logging,
),
)
)
val session = server.createSession(
StdioServerTransport(
inputStream = System.`in`.asSource().buffered(),
outputStream = System.out.asSink().buffered()
)
)
session.sendLoggingMessage(
LoggingMessageNotification(
LoggingMessageNotificationParams(
level = LoggingLevel.Info,
logger = "startup",
data = buildJsonObject { put("message", "Server started") },
),
),
)
```
<!--- SUFFIX
}
-->
<!--- KNIT example-server-util-logging-01.kt -->
Keep logs free of sensitive data, and expect clients to surface them in their own UI.
#### Pagination
List operations return paginated results with an opaque `nextCursor`, clients echo that cursor to fetch the next page.
Supported list calls: `resources/list`, `resources/templates/list`, `prompts/list`, and `tools/list`.
Treat cursors as opaque—don’t parse or persist them across sessions.
<!--- INCLUDE
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.ListResourcesRequest
import io.modelcontextprotocol.kotlin.sdk.types.ListResourcesResult
import io.modelcontextprotocol.kotlin.sdk.types.Method
import io.modelcontextprotocol.kotlin.sdk.types.Resource
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import kotlinx.io.asSink
import kotlinx.io.asSource
import kotlinx.io.buffered
suspend fun main() {
-->
```kotlin
val server = Server(
serverInfo = Implementation("example-server", "1.0.0"),
options = ServerOptions(
capabilities = ServerCapabilities(
resources = ServerCapabilities.Resources(),
),
)
)
val session = server.createSession(
StdioServerTransport(
inputStream = System.`in`.asSource().buffered(),
outputStream = System.out.asSink().buffered()
)
)
val resources = listOf(
Resource(uri = "note://1", name = "Note 1", description = "First"),
Resource(uri = "note://2", name = "Note 2", description = "Second"),
Resource(uri = "note://3", name = "Note 3", description = "Third"),
)
val pageSize = 2
session.setRequestHandler<ListResourcesRequest>(Method.Defined.ResourcesList) { request, _ ->
val start = request.params?.cursor?.toIntOrNull() ?: 0
val page = resources.drop(start).take(pageSize)
val next = if (start + page.size < resources.size) (start + page.size).toString() else null
ListResourcesResult(
resources = page,
nextCursor = next,
)
}
```
<!--- SUFFIX
}
-->
<!--- KNIT example-server-util-pagination-01.kt -->
Include `nextCursor` only when more items remain an absent cursor ends pagination.
### Client Features
Clients advertise their capabilities (roots, sampling, elicitation, etc.) during initialization. After that they can
serve requests from the server while still initiating calls such as `listTools` or `callTool`.
#### Roots
Roots let the client declare where the server is allowed to operate. Declare the `roots` capability, respond to
`roots/list`, and emit `notifications/roots/list_changed` if you set `listChanged = true`. URIs **must** be `file://`
paths.
<!--- INCLUDE
import io.modelcontextprotocol.kotlin.sdk.client.Client
import io.modelcontextprotocol.kotlin.sdk.client.ClientOptions
import io.modelcontextprotocol.kotlin.sdk.types.ClientCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
suspend fun main() {
-->
```kotlin
val client = Client(
clientInfo = Implementation("demo-client", "1.0.0"),
options = ClientOptions(
capabilities = ClientCapabilities(roots = ClientCapabilities.Roots(listChanged = true)),
),
)
client.addRoot(
uri = "file:///Users/demo/projects",
name = "Projects",
)
client.sendRootsListChanged()
```
<!--- SUFFIX
}
-->
<!--- KNIT example-client-roots-01.kt -->
Call `addRoot`/`removeRoot` whenever your file system view changes, and use `sendRootsListChanged()` to notify the
server. Keep root lists user-controlled and revoke entries that are no longer authorized.
#### Sampling
Sampling lets the server ask the client to call its preferred LLM. Declare the `sampling` capability (and
`sampling.tools` if you allow tool-enabled sampling), and handle `sampling/createMessage`. Keep a human in the loop for
approvals.
<!--- INCLUDE
import io.modelcontextprotocol.kotlin.sdk.client.Client
import io.modelcontextprotocol.kotlin.sdk.client.ClientOptions
import io.modelcontextprotocol.kotlin.sdk.types.ClientCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.CreateMessageRequest
import io.modelcontextprotocol.kotlin.sdk.types.CreateMessageResult
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.Method
import io.modelcontextprotocol.kotlin.sdk.types.Role
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.putJsonObject
fun main() {
-->
```kotlin
val client = Client(
clientInfo = Implementation("demo-client", "1.0.0"),
options = ClientOptions(
capabilities = ClientCapabilities(
sampling = buildJsonObject { putJsonObject("tools") { } }, // drop tools if you don't support tool use
),
),
)
client.setRequestHandler<CreateMessageRequest>(Method.Defined.SamplingCreateMessage) { request, _ ->
val content = request.messages.lastOrNull()?.content
val prompt = if (content is TextContent) content.text else "your topic"
CreateMessageResult(
model = "gpt-4o-mini",
role = Role.Assistant,
content = TextContent(text = "Here is a short note about $prompt"),
)
}
```
<!--- SUFFIX
}
-->
<!--- KNIT example-client-sampling-01.kt -->
Inside the handler you can pick any model/provider, require approvals, or reject the request. If you don’t support tool
use, omit `sampling.tools` from capabilities.
[//]: # (TODO: add elicitation section)
[//]: # (#### Elicitation)
## Transports
All transports share the same API surface, so you can change deployment style without touching business logic. Pick the
transport that best matches where the server runs.
### STDIO Transport
`StdioClientTransport` and `StdioServerTransport` tunnel MCP messages over stdin/stdout—perfect for editor plugins or
CLI tooling that spawns a helper process. No networking setup is required.
### Streamable HTTP Transport
`StreamableHttpClientTransport` and the Ktor `streamableHttpApp()` helpers expose MCP over a single HTTP endpoint with
optional JSON-only or SSE streaming responses. This is the recommended choice for remote deployments and integrates
nicely with proxies or service meshes.
### SSE Transport
Server-Sent Events remain available for backwards compatibility with older MCP clients. Use `SseServerTransport` or the
SSE Ktor plugin when you need drop-in compatibility, but prefer Streamable HTTP for new projects.
### WebSocket Transport
`WebSocketClientTransport` plus the matching server utilities provide full-duplex, low-latency connections—useful when
you expect lots of notifications or long-running sessions behind a reverse proxy that already terminates WebSockets.
## Connecting your server
1. Start a sample HTTP server on port 3000:
```bash
./gradlew :samples:kotlin-mcp-server:run
```
2. Connect with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) or Claude Desktop/Code:
```bash
npx -y @modelcontextprotocol/inspector --connect http://localhost:3000
# or
claude mcp add --transport http kotlin-mcp http://localhost:3000
```
3. In the Inspector, confirm prompts, tools, resources, completions, and logs show up. Iterate locally until you’re
ready to host the server wherever you prefer.
## Examples
| Scenario | Description | Example |
|--------------------------|-----------------------------------------------------------------|--------------------------------------------------------------------------|
| Streamable HTTP server | Full MCP server with prompts, resources, tools, completions | [samples/kotlin-mcp-server](./samples/kotlin-mcp-server) |
| STDIO weather server | Minimal STDIO transport server exposing weather info and alerts | [samples/weather-stdio-server](./samples/weather-stdio-server) |
| Interactive STDIO client | MCP client that connects over STDIO and pipes requests to LLMs | [samples/kotlin-mcp-client](./samples/kotlin-mcp-client) |
| Streamable HTTP client | MCP client demo in a runnable notebook | [samples/notebooks/McpClient.ipynb](./samples/notebooks/McpClient.ipynb) |
## Documentation
- [API Reference](https://modelcontextprotocol.github.io/kotlin-sdk/)
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
- [MCP specification](https://modelcontextprotocol.io/specification/latest)
## Contributing
Please see the [contribution guide](CONTRIBUTING.md) and the [Code of conduct](CODE_OF_CONDUCT.md) before contributing.

1
docs/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
src/

35
docs/build.gradle.kts Normal file
View file

@ -0,0 +1,35 @@
plugins {
kotlin("jvm")
alias(libs.plugins.knit)
}
dependencies {
implementation(project(":kotlin-sdk"))
implementation(libs.ktor.server.cio)
}
tasks.matching {
it.name == "ktlintMainSourceSetCheck" || it.name == "ktlintMainSourceSetFormat"
}.configureEach {
enabled = false
}
knit {
rootDir = project.rootDir
files = files(project.rootDir.resolve("README.md"))
defaultLineSeparator = "\n"
siteRoot = "" // Disable site root validation
}
// Only run knitCheck when explicitly requested, not as part of build/check
tasks.named("knitCheck") {
onlyIf {
gradle.startParameter.taskNames.any {
it.contains("knitCheck") || it.contains("knit")
}
}
}
tasks.clean {
delete("src")
}

View file

@ -1,21 +1,17 @@
# MCP Kotlin SDK
Kotlin SDK for the Model Context Protocol (MCP).
This is a Kotlin Multiplatform library that helps you build MCP clients and servers that speak the same protocol and
share the same types.
The SDK focuses on clarity, small building blocks, and first‑class coroutine support.
Kotlin Multiplatform implementation of the Model Context Protocol (MCP). The SDK focuses on clear, explicit APIs,
small building blocks, and first-class coroutine support so clients and servers share the same well-typed messages and
transports.
Use the umbrella `kotlin-sdk` artifact when you want a single dependency that brings the core types plus both client and
server toolkits. If you only need one side, depend on `kotlin-sdk-client` or `kotlin-sdk-server` directly.
Gradle (Kotlin DSL):
Use the umbrella `kotlin-sdk` artifact to bring in everything at once, or depend on the focused modules directly:
```kotlin
dependencies {
// Convenience bundle with everything you need to start
// All-in-one bundle
implementation("io.modelcontextprotocol:kotlin-sdk:<version>")
// Or pick modules explicitly
// Or pick sides explicitly
implementation("io.modelcontextprotocol:kotlin-sdk-client:<version>")
implementation("io.modelcontextprotocol:kotlin-sdk-server:<version>")
}
@ -25,79 +21,74 @@ dependencies {
## Module kotlin-sdk-core
Foundational, platform‑agnostic pieces:
Foundation shared by both sides:
- Protocol data model and JSON serialization (kotlinx.serialization)
- Request/response and notification types used by both sides of MCP
- Coroutine‑friendly protocol engine and utilities
- Transport abstractions shared by client and server
- Protocol data model for MCP requests, results, notifications, capabilities, and content types.
- `McpJson` (kotlinx.serialization) with MCP-friendly defaults plus helpers for converting native values to JSON.
- Transport abstractions (`Transport`, `AbstractTransport`, `WebSocketMcpTransport`) and streaming `ReadBuffer`.
- `Protocol` base class that handles JSON-RPC framing, correlation, progress tokens, and capability assertions.
You typically do not use `core` directly in application code; it is pulled in by the client/server modules. Use it
explicitly if you only need the protocol types or plan to implement a custom transport.
Use `core` when you need the raw types or want to author a custom transport. Public APIs are explicit to keep the shared
surface stable across platforms.
---
## Module kotlin-sdk-client
High‑level client API for connecting to an MCP server and invoking its tools, prompts, and resources. Ships with several
transports:
High-level client for connecting to MCP servers and invoking their features:
- WebSocketClientTransport – low latency, full‑duplex
- SSEClientTransport – Server‑Sent Events over HTTP
- StdioClientTransport – CLI‑friendly stdio bridge
- StreamableHttpClientTransport – simple HTTP streaming
- `Client` runtime (or `mcpClient` helper) performs the MCP handshake and exposes `serverCapabilities`,
`serverVersion`, and `serverInstructions`.
- Typed operations for tools, prompts, resources, completion, logging, roots, sampling, and elicitation with capability
enforcement.
- Transports: `StdioClientTransport`, `SseClientTransport`, `WebSocketClientTransport`, and `StreamableHttpClientTransport`,
plus Ktor client extensions for quick wiring.
A minimal client:
Minimal WebSocket client:
```kotlin
val client = Client(
clientInfo = Implementation(name = "sample-client", version = "1.0.0")
val client = mcpClient(
clientInfo = Implementation("sample-client", "1.0.0"),
clientOptions = ClientOptions(ClientCapabilities(tools = ClientCapabilities.Tools())),
transport = WebSocketClientTransport("ws://localhost:8080/mcp")
)
client.connect(WebSocketClientTransport("ws://localhost:8080/mcp"))
val tools = client.listTools()
val result = client.callTool(
name = "echo",
arguments = mapOf("text" to "Hello, MCP!")
)
val result = client.callTool("echo", mapOf("text" to "Hello, MCP!"))
println(result.content)
```
---
## Module kotlin-sdk-server
Lightweight server toolkit for hosting MCP tools, prompts, and resources. It provides a small, composable API and
ready‑to‑use transports:
Server toolkit for exposing MCP tools, prompts, and resources:
- StdioServerTransport – integrates well with CLIs and editors
- SSE/WebSocket helpers for Ktor – easy HTTP deployment
- `Server` runtime coordinates sessions, initialization flow, and capability enforcement with registries for tools,
prompts, resources, and templates.
- Transports: `StdioServerTransport` for CLI/editor bridges; Ktor extensions (`mcp` for SSE + POST back-channel and
`mcpWebSocket` for WebSocket) for HTTP hosting.
- Built-in notifications for list changes and resource subscriptions when capabilities enable them.
Register tools and run over stdio:
Minimal Ktor SSE server:
```kotlin
val server = Server(
serverInfo = Implementation(name = "sample-server", version = "1.0.0"),
options = ServerOptions(ServerCapabilities())
)
server.addTool(
name = "echo",
description = "Echoes the provided text"
) { request ->
// Build and return a CallToolResult from request.arguments
// (see CallToolResult and related types in kotlin-sdk-core)
/* ... */
fun Application.module() {
mcp {
Server(
serverInfo = Implementation("sample-server", "1.0.0"),
options = ServerOptions(ServerCapabilities(
tools = ServerCapabilities.Tools(listChanged = true),
resources = ServerCapabilities.Resources(listChanged = true, subscribe = true),
)),
) {
addTool(name = "echo", description = "Echo text back") { request ->
val text = request.params.arguments?.get("text")?.jsonPrimitive?.content ?: ""
CallToolResult(content = listOf(TextContent("You said: $text")))
}
}
}
}
// Bridge the protocol over stdio
val transport = StdioServerTransport(
inputStream = kotlinx.io.files.Path("/dev/stdin").source(),
outputStream = kotlinx.io.files.Path("/dev/stdout").sink()
)
// Start transport and wire it with the server using provided helpers in the SDK.
```
For HTTP deployments, use the Ktor extensions included in the module to expose an MCP WebSocket or SSE endpoint with a
few lines of code.
Pick the module that matches your role, or use the umbrella artifact to get both sides with the shared core.

View file

@ -7,6 +7,7 @@ dokka = "2.1.0"
kotlin = "2.2.21"
kover = "0.9.4"
ktlint = "14.0.1"
knit = "0.5.1"
mavenPublish = "0.36.0"
netty = "4.2.9.Final"
openapi-generator = "7.18.0"
@ -23,7 +24,7 @@ mockk = "1.14.7"
mokksy = "0.6.2"
serialization = "1.9.0"
slf4j = "2.0.17"
junit="5.14.2"
junit = "5.14.2"
[libraries]
# Plugins
@ -74,4 +75,5 @@ detekt = { id = "dev.detekt", version.ref = "detekt" }
kotlinx-binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binaryCompatibilityValidatorPlugin" }
kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" }
knit = { id = "org.jetbrains.kotlinx.knit", version.ref = "knit" }
openapi-generator = { id = "org.openapi.generator", version.ref = "openapi-generator" }

3
knit.properties Normal file
View file

@ -0,0 +1,3 @@
# Knit configuration
knit.dir=docs/src/main/kotlin/
knit.package=io.modelcontextprotocol.kotlin.sdk.examples

View file

@ -1,10 +1,78 @@
# Module kotlin-sdk-client
The Model Context Protocol (MCP) Kotlin SDK client module provides a multiplatform implementation for connecting to and
interacting with MCP servers.
`kotlin-sdk-client` is the multiplatform MCP client for Kotlin. It handles the MCP handshake, enforces capabilities, and
gives you typed APIs to call tools, prompts, resources, completions, and logging endpoints on MCP servers. It reuses
protocol types from `kotlin-sdk-core` and ships with transports for CLI and Ktor-based networking.
## Features
## What the module provides
- Cross-platform support for JVM, WASM, JS, and Native
- Built-in support for multiple transport protocols (stdio, SSE, WebSocket)
- Type-safe API for resource management and server interactions
- **Client runtime**: The `Client` class (or `mcpClient` helper) wraps initialization, capability checks, and
request/notification plumbing. After connecting, it exposes `serverCapabilities`, `serverVersion`, and
`serverInstructions`.
- **Typed operations**: Convenience functions like `listTools`, `callTool`, `listResources`, `readResource`,
`listPrompts`, `complete`, `setLoggingLevel`, and subscription helpers for resources.
- **Capability enforcement**: Methods fail fast if the server does not advertise the needed capability; optional
strictness mirrors the protocol options used by the server SDK.
- **Transports**: Ready-to-use implementations for STDIO (CLI interoperability), Ktor SSE (`SseClientTransport` with
POST back-channel), Ktor WebSocket, and Streamable HTTP for environments that prefer request/response streaming.
- **Ktor client integration**: Extension helpers wire MCP over Ktor client engines with minimal setup for SSE,
Streamable HTTP, or WebSocket.
## Typical client setup
1. Declare client capabilities with `ClientOptions` (e.g., sampling, roots, elicitation, experimental).
2. Create a transport suitable for your environment.
3. Connect using `mcpClient` or instantiate `Client` and call `connect(transport)`.
4. Use typed APIs to interact with the server; results and errors use the shared MCP types.
### Minimal STDIO client
```kotlin
val client = mcpClient(
clientInfo = Implementation(name = "demo-client", version = "1.0.0"),
clientOptions = ClientOptions(
capabilities = ClientCapabilities(
tools = ClientCapabilities.Tools(),
resources = ClientCapabilities.Resources(subscribe = true),
)
),
transport = StdioClientTransport(
System.`in`.asSource().buffered(),
System.out.asSink().buffered()
)
)
val tools = client.listTools()
val result = client.callTool("hello", mapOf("name" to "Kotlin"))
println(result.content)
```
### Ktor-based transports
- **SSE** (streaming GET + POST back-channel): create `SseClientTransport(httpClient, url)` (or
`HttpClient.mcpSseTransport(url)`); sessions are keyed by `sessionId` managed by the SDK.
- **WebSocket**: use `WebSocketClientTransport(httpClient, url)` (or `HttpClient.mcpWebSocketTransport(url)`) to get
bidirectional messaging in one connection.
- **Streamable HTTP**: `StreamableHttpClientTransport(httpClient, url)` enables MCP over streaming HTTP
(or `HttpClient.mcpStreamableHttpTransport(url)`).
## Feature usage highlights
- **Tools**: `callTool` accepts raw maps or `CallToolRequest`; metadata keys are validated per MCP rules.
- **Prompts & completion**: `getPrompt`, `listPrompts`, and `complete` wrap common prompt flows.
- **Resources**: `listResources`, `listResourceTemplates`, `readResource`, and `subscribeResource` cover discovery,
templating, and updates (when the server allows subscriptions).
- **Roots**: If enabled, register local roots with `addRoot`/`addRoots`; the client responds to `RootsList` requests
from the server.
- **Notifications**: Built-in handlers cover initialization, cancellation, progress, and roots list changes; you can
register more handlers via the underlying `Protocol` API.
## Diagnostics and lifecycle
- Capability assertions prevent calling endpoints the server does not expose; errors surface with clear messages.
- Logging uses `KotlinLogging`; enable DEBUG to inspect transport and handshake behavior.
- `close()` tears down the transport and cancels in-flight requests.
Use this module whenever you need an MCP-aware Kotlin client—whether embedding in a CLI over STDIO or talking to remote
servers via Ktor SSE/WebSocket/streamable HTTP transports. Public APIs are explicit so downstream users can rely on
stable, well-typed surface areas across platforms.

View file

@ -1,5 +1,47 @@
# Module kotlin-sdk-core
The MCP Kotlin SDK Core module provides fundamental functionality for interacting with Model Context Protocol (MCP).
This module serves as the foundation for building MCP-enabled applications in Kotlin.
`kotlin-sdk-core` is the foundation of the MCP Kotlin SDK. It contains protocol message types, JSON handling, and
transport abstractions used by both client and server modules. No platform-specific code lives here; everything is
designed for Kotlin Multiplatform with explicit API mode enabled.
## What the module provides
- **Protocol model**: Complete MCP data classes for requests, results, notifications, capabilities, tools, prompts,
resources, logging, completion, sampling, elicitation, and roots. DSL helpers (`*.dsl.kt`) let you build messages
fluently without repeating boilerplate.
- **JSON utilities**: A shared `McpJson` configuration (kotlinx.serialization) with MCP-friendly settings (ignore
unknown keys, no class discriminator). Helpers for converting maps to `JsonElement`, `EmptyJsonObject`, and
encoding/decoding JSON-RPC envelopes.
- **Transport abstractions**: `Transport` and `AbstractTransport` define the message pipeline, callbacks, and error
handling. `WebSocketMcpTransport` adds a shared WebSocket implementation for both client and server sides, and
`ReadBuffer` handles streaming JSON-RPC framing.
- **Protocol engine**: The `Protocol` base class manages request/response correlation, notifications, progress tokens,
and capability assertions. Higher-level modules extend it to become `Client` and `Server`.
- **Errors and safety**: Common exception types (`McpException`, parsing errors) plus capability enforcement hooks
ensure callers cannot use endpoints the peer does not advertise.
## Typical usage
- Import MCP types to define capabilities and message payloads for your own transports or custom integrations.
- Extend `Protocol` if you need a bespoke peer role while reusing correlation logic and JSON-RPC helpers.
- Use the DSL builders to construct well-typed requests (tools, prompts, resources, logging, completion) instead of
crafting raw JSON.
### Example: building a tool call request
```kotlin
val request = CallToolRequest {
name = "summarize"
arguments = mapOf("text" to "Hello MCP")
}
```
### Example: parsing a JSON-RPC message
```kotlin
val message: JSONRPCMessage = McpJson.decodeFromString(jsonString)
```
Use this module when you need the raw building blocks of MCP—types, JSON config, and transport base classes—whether to
embed in another runtime, author new transports, or contribute higher-level features in the client/server modules. The
APIs are explicit to keep the shared surface stable for downstream users.

View file

@ -1,14 +1,125 @@
# Module kotlin-sdk-server
The server module provides core server-side functionality for the Model Context Protocol (MCP) Kotlin SDK.
This module includes essential parts for writing MCP server applications.
`kotlin-sdk-server` contains the server-side building blocks for Model Context Protocol (MCP) applications written in
Kotlin Multiplatform. It pairs the protocol types from `kotlin-sdk-core` with transport implementations and utilities
that make it straightforward to expose tools, prompts, and resources to MCP clients.
## Features
## What the module provides
* Server-side request handling
* Model context management
* Protocol implementation
* Integration utilities
- **Server runtime**: The `Server` class coordinates sessions, initialization flow, and capability enforcement. It
tracks active sessions and cleans them up when transports close.
- **Feature registries**: Helpers to register and remove tools, prompts, resources, and resource templates. Registry
listeners emit list-changed notifications when the capability is enabled.
- **Transports**: Ready-to-use transports for STDIO (CLI-style hosting), Ktor Server-Sent Events (SSE) with POST
back-channel, and Ktor WebSocket. All share the common `Transport` abstraction from the SDK.
- **Ktor integration**: Extension functions (`Routing.mcp`, `Routing.mcpWebSocket`, and `Application` variants) that
plug MCP into an existing Ktor server with minimal boilerplate.
- **Notifications**: Built-in support for resource subscription, resource-updated events, and feature list change
notifications when capabilities are set accordingly.
For detailed usage instructions and examples, please refer to
the [documentation](https://github.com/modelcontextprotocol/kotlin-sdk/blob/main/README.md).
## Typical server setup
1. Declare capabilities your server supports using `ServerOptions`. Capabilities drive which handlers are installed and
whether list-change notifications are emitted.
2. Register features: tools, prompts, resources, and resource templates. Handlers run in suspending context and can be
removed or replaced at runtime.
3. Attach a transport and open a session via `createSession(transport)`. Multiple sessions can be active simultaneously.
4. Close the server to tear down transports and unsubscribe sessions.
### Minimal STDIO server
```kotlin
val server = Server(
serverInfo = Implementation(name = "demo-server", version = "1.0.0"),
options = ServerOptions(
capabilities = ServerCapabilities(
tools = ServerCapabilities.Tools(listChanged = true)
)
)
) {
addTool(
name = "hello",
description = "Greets the caller by name"
) { request ->
val name = request.params.arguments?.get("name")?.jsonPrimitive?.content ?: "there"
CallToolResult(
content = listOf(TextContent("Hello, $name!")),
isError = false,
)
}
}
val transport = StdioServerTransport(
System.`in`.asSource().buffered(),
System.out.asSink().buffered()
)
server.createSession(transport)
```
### Hosting with Ktor (SSE)
```kotlin
fun Application.module() {
mcp {
Server(
serverInfo = Implementation("ktor-sse", "1.0.0"),
options = ServerOptions(
ServerCapabilities(
prompts = ServerCapabilities.Prompts(listChanged = true),
resources = ServerCapabilities.Resources(listChanged = true, subscribe = true),
)
)
) {
addPrompt(
name = "welcome",
description = "Explain how to use the server"
) {
GetPromptResult(
description = "Welcome to the MCP server",
messages = listOf(CreateMessageResult.Message(TextContent("Try listing tools first")))
)
}
}
}
}
```
The SSE route exposes a streaming GET endpoint and a POST endpoint for client messages. Session affinity is maintained
by a `sessionId` query parameter managed by the SDK.
### Hosting with Ktor (WebSocket)
```kotlin
fun Application.module() {
mcpWebSocket {
Server(
serverInfo = Implementation("ktor-ws", "1.0.0"),
options = ServerOptions(ServerCapabilities(tools = ServerCapabilities.Tools()))
)
}
}
```
`mcpWebSocket` installs Ktor WebSockets and wires message handling over a single bidirectional connection.
## Feature registration details
- **Tools**: `addTool` accepts a `Tool` descriptor or inline parameters plus a suspend handler. `removeTool` and
`addTools/removeTools` support dynamic updates.
- **Prompts**: `addPrompt` wires a provider that returns `GetPromptResult` and optional arguments metadata.
- **Resources**: `addResource` exposes static or generated content via `ReadResourceResult`; `addResources`
batch-registers. Templates and roots are also supported for structured discovery.
- **Instructions**: Provide static text or a function via `instructionsProvider` to send per-session usage guidance
during initialization.
## Lifecycle and diagnostics
- Sessions emit callbacks via `onConnect` and `onClose`. Deprecated `onInitialized` exists for backward compatibility;
prefer session-level hooks.
- The server enforces declared capabilities; attempting to register an unsupported feature throws with a descriptive
message.
- Logging uses `KotlinLogging`; avoid logging secrets. To inspect traffic, run the server with DEBUG level enabled.
Use this module whenever you need to expose MCP features from a Kotlin service—whether embedding in a CLI via STDIO,
serving from Ktor over SSE/WebSocket, or composing transports for custom environments. Public APIs are explicit to keep
server-facing contracts stable for consumers.

View file

@ -24,5 +24,6 @@ include(
":kotlin-sdk-server",
":kotlin-sdk",
":integration-test",
":docs",
":conformance-test",
)