kotlin-sdk-server
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.
What the module provides
Server runtime: The
Serverclass 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
Transportabstraction from the SDK.Ktor integration: Extension functions (
Route.mcp,Route.mcpWebSocket, andApplicationvariants) 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.
Typical server setup
Declare capabilities your server supports using
ServerOptions. Capabilities drive which handlers are installed and whether list-change notifications are emitted.Register features: tools, prompts, resources, and resource templates. Handlers run in suspending context and can be removed or replaced at runtime.
Attach a transport and open a session via
createSession(transport). Multiple sessions can be active simultaneously.Close the server to tear down transports and unsubscribe sessions.
Minimal STDIO server
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)
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)
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:
addToolaccepts aTooldescriptor or inline parameters plus a suspend handler.removeToolandaddTools/removeToolssupport dynamic updates.Prompts:
addPromptwires a provider that returnsGetPromptResultand optional arguments metadata.Resources:
addResourceexposes static or generated content viaReadResourceResult;addResourcesbatch-registers. Templates and roots are also supported for structured discovery.Instructions: Provide static text or a function via
instructionsProviderto send per-session usage guidance during initialization.
Lifecycle and diagnostics
Sessions emit callbacks via
onConnectandonClose. DeprecatedonInitializedexists 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.