{"id":26590453,"url":"https://github.com/modelcontextprotocol/kotlin-sdk","last_synced_at":"2026-02-17T08:13:17.725Z","repository":{"id":268729661,"uuid":"904281964","full_name":"modelcontextprotocol/kotlin-sdk","owner":"modelcontextprotocol","description":"The official Kotlin SDK for Model Context Protocol servers and clients. Maintained in collaboration with JetBrains","archived":false,"fork":false,"pushed_at":"2025-05-06T07:12:01.000Z","size":1091,"stargazers_count":623,"open_issues_count":35,"forks_count":85,"subscribers_count":18,"default_branch":"main","last_synced_at":"2025-05-06T07:50:56.312Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://modelcontextprotocol.io","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/modelcontextprotocol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-12-16T15:35:02.000Z","updated_at":"2025-05-06T07:31:11.000Z","dependencies_parsed_at":"2025-02-21T18:23:30.094Z","dependency_job_id":"47615649-e5e9-4b4d-b78b-ee4269af1a53","html_url":"https://github.com/modelcontextprotocol/kotlin-sdk","commit_stats":null,"previous_names":["modelcontextprotocol/kotlin-sdk"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modelcontextprotocol%2Fkotlin-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modelcontextprotocol%2Fkotlin-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modelcontextprotocol%2Fkotlin-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/modelcontextprotocol%2Fkotlin-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/modelcontextprotocol","download_url":"https://codeload.github.com/modelcontextprotocol/kotlin-sdk/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254319717,"owners_count":22051072,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-03-23T13:39:45.560Z","updated_at":"2026-02-17T08:13:17.716Z","avatar_url":"https://github.com/modelcontextprotocol.png","language":"Kotlin","funding_links":[],"categories":["SDKs","📚 Projects (1974 total)","Kotlin","MCP","Mcp Server Directories \u0026 Lists","📦 Other","人工智能","MCP Servers \u0026 Protocol","MCP Frameworks and libraries"],"sub_categories":["Official","MCP Servers","Spring Cloud框架","Kotlin"],"readme":"# MCP Kotlin SDK\n\n[![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)\n[![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)\n[![Conformance Tests](https://github.com/modelcontextprotocol/kotlin-sdk/actions/workflows/conformance.yml/badge.svg)](https://github.com/modelcontextprotocol/kotlin-sdk/actions/workflows/conformance.yml)\n[![Kotlin](https://img.shields.io/badge/kotlin-2.2+-blueviolet.svg?logo=kotlin)](http://kotlinlang.org)\n[![Kotlin Multiplatform](https://img.shields.io/badge/Platforms-%20JVM%20%7C%20Wasm%2FJS%20%7C%20Native%20-blueviolet?logo=kotlin)](https://kotlinlang.org/docs/multiplatform.html)\n[![JVM](https://img.shields.io/badge/JVM-11+-red.svg?logo=jvm)](http://java.com)\n[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/modelcontextprotocol/kotlin-sdk)\n\nKotlin Multiplatform SDK for the [Model Context Protocol](https://modelcontextprotocol.io).\nIt enables Kotlin applications targeting JVM, Native, JS, and Wasm to implement MCP clients and servers using a\nstandardized protocol interface.\n\n## Table of Contents\n\n\u003c!--- TOC --\u003e\n\n* [Overview](#overview)\n* [Installation](#installation)\n  * [Artifacts](#artifacts)\n  * [Gradle setup (JVM)](#gradle-setup-jvm)\n  * [Multiplatform](#multiplatform)\n  * [Ktor dependencies](#ktor-dependencies)\n* [Quickstart](#quickstart)\n  * [Creating a Client](#creating-a-client)\n  * [Creating a Server](#creating-a-server)\n* [Core Concepts](#core-concepts)\n  * [MCP Primitives](#mcp-primitives)\n  * [Capabilities](#capabilities)\n    * [Server Capabilities](#server-capabilities)\n    * [Client Capabilities](#client-capabilities)\n  * [Server Features](#server-features)\n    * [Prompts](#prompts)\n    * [Resources](#resources)\n    * [Tools](#tools)\n    * [Completion](#completion)\n    * [Logging](#logging)\n    * [Pagination](#pagination)\n  * [Client Features](#client-features)\n    * [Roots](#roots)\n    * [Sampling](#sampling)\n* [Transports](#transports)\n  * [STDIO Transport](#stdio-transport)\n  * [Streamable HTTP Transport](#streamable-http-transport)\n  * [SSE Transport](#sse-transport)\n  * [WebSocket Transport](#websocket-transport)\n  * [ChannelTransport (testing)](#channeltransport-testing)\n* [Connecting your server](#connecting-your-server)\n* [Examples](#examples)\n* [Documentation](#documentation)\n* [Contributing](#contributing)\n* [License](#license)\n\n\u003c!--- END --\u003e\n\n## Overview\n\nThe Model Context Protocol allows applications to provide context for LLMs in a standardized way,\nseparating the concerns of providing context from the actual LLM interaction.\nThis Kotlin SDK implements the MCP specification, making it easy to:\n\n- Build MCP **clients** that can connect to any MCP server\n- Create MCP **servers** that expose resources, prompts, and tools\n- Target **JVM, Native, JS, and Wasm** from a single codebase\n- Use standard transports like **stdio**, **SSE**, **Streamable HTTP**, and **WebSocket**\n- Handle MCP protocol messages and lifecycle events with coroutine-friendly APIs\n\n## Installation\n\n### Artifacts\n\n- `io.modelcontextprotocol:kotlin-sdk` – umbrella SDK (client + server APIs)\n- `io.modelcontextprotocol:kotlin-sdk-client` – client-only APIs\n- `io.modelcontextprotocol:kotlin-sdk-server` – server-only APIs\n\n### Gradle setup (JVM)\n\nAdd the Maven Central repository and the SDK dependency:\n\n```kotlin\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    // See the badge above for the latest version\n    implementation(\"io.modelcontextprotocol:kotlin-sdk:$mcpVersion\")\n}\n```\n\nUse _kotlin-sdk-client_ or _kotlin-sdk-server_ if you only need one side of the API:\n\n```kotlin\ndependencies {\n    implementation(\"io.modelcontextprotocol:kotlin-sdk-client:$mcpVersion\")\n    implementation(\"io.modelcontextprotocol:kotlin-sdk-server:$mcpVersion\")\n}\n```\n\n### Multiplatform\n\nIn a Kotlin Multiplatform project you can add the SDK to commonMain:\n\n```kotlin\ncommonMain {\n    dependencies {\n        // Works as a common dependency as well as the platform one\n        implementation(\"io.modelcontextprotocol:kotlin-sdk:$mcpVersion\")\n    }\n}\n```\n\n### Ktor dependencies\n\nThe Kotlin MCP SDK uses [Ktor](https://ktor.io/), but it does not add Ktor engine dependencies transitively.\nYou need to declare\nKtor [client](https://ktor.io/docs/client-dependencies.html#engine-dependency)/[server](https://ktor.io/docs/server-dependencies.html)\ndependencies yourself (or reuse the ones already used in your project),\nfor example:\n\n```kotlin\ndependencies {\n    // MCP client with Ktor\n    implementation(\"io.ktor:ktor-client-cio:$ktorVersion\")\n    implementation(\"io.modelcontextprotocol:kotlin-sdk-client:$mcpVersion\")\n\n    // MCP server with Ktor\n    implementation(\"io.ktor:ktor-server-netty:$ktorVersion\")\n    implementation(\"io.modelcontextprotocol:kotlin-sdk-server:$mcpVersion\")\n}\n```\n\n## Quickstart\n\nLet's create a simple MCP client and server to demonstrate the basic usage of the Kotlin SDK.\n\n\u003c!--- CLEAR --\u003e\n\n### Creating a Client\n\nCreate an MCP client that connects to a server via Streamable HTTP transport and lists available tools:\n\n```kotlin\nimport io.ktor.client.HttpClient\nimport io.ktor.client.plugins.sse.SSE\nimport io.modelcontextprotocol.kotlin.sdk.client.Client\nimport io.modelcontextprotocol.kotlin.sdk.client.StreamableHttpClientTransport\nimport io.modelcontextprotocol.kotlin.sdk.types.Implementation\nimport kotlinx.coroutines.runBlocking\n\nfun main(args: Array\u003cString\u003e) = runBlocking {\n    val url = args.firstOrNull() ?: \"http://localhost:3000/mcp\"\n\n    val httpClient = HttpClient { install(SSE) }\n\n    val client = Client(\n        clientInfo = Implementation(\n            name = \"example-client\",\n            version = \"1.0.0\"\n        )\n    )\n\n    val transport = StreamableHttpClientTransport(\n        client = httpClient,\n        url = url\n    )\n\n    // Connect to server\n    client.connect(transport)\n\n    // List available tools\n    val tools = client.listTools().tools\n\n    println(tools)\n}\n```\n\n\u003c!--- KNIT example-quickstart-client-01.kt --\u003e\n\n### Creating a Server\n\nCreate an MCP server that exposes a simple tool and runs on an embedded Ktor server with SSE transport:\n\n```kotlin\nimport io.ktor.server.cio.CIO\nimport io.ktor.server.engine.embeddedServer\nimport io.modelcontextprotocol.kotlin.sdk.server.Server\nimport io.modelcontextprotocol.kotlin.sdk.server.ServerOptions\nimport io.modelcontextprotocol.kotlin.sdk.server.mcp\nimport io.modelcontextprotocol.kotlin.sdk.types.CallToolResult\nimport io.modelcontextprotocol.kotlin.sdk.types.Implementation\nimport io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities\nimport io.modelcontextprotocol.kotlin.sdk.types.TextContent\nimport io.modelcontextprotocol.kotlin.sdk.types.ToolSchema\nimport kotlinx.serialization.json.buildJsonObject\nimport kotlinx.serialization.json.put\n\n\nfun main(args: Array\u003cString\u003e) {\n    val port = args.firstOrNull()?.toIntOrNull() ?: 3000\n    val mcpServer = Server(\n        serverInfo = Implementation(\n            name = \"example-server\",\n            version = \"1.0.0\"\n        ),\n        options = ServerOptions(\n            capabilities = ServerCapabilities(\n                tools = ServerCapabilities.Tools(listChanged = true),\n            ),\n        )\n    )\n\n    mcpServer.addTool(\n        name = \"example-tool\",\n        description = \"An example tool\",\n        inputSchema = ToolSchema(\n            properties = buildJsonObject {\n                put(\"input\", buildJsonObject { put(\"type\", \"string\") })\n            }\n        )\n    ) { request -\u003e\n        CallToolResult(content = listOf(TextContent(\"Hello, world!\")))\n    }\n\n    embeddedServer(CIO, host = \"127.0.0.1\", port = port) {\n        mcp {\n            mcpServer\n        }\n    }.start(wait = true)\n}\n```\n\n\u003c!--- KNIT example-quickstart-server-01.kt --\u003e\n\nYou can run the server and then connect to it using the client or test with the MCP Inspector:\n\n```bash\nnpx -y @modelcontextprotocol/inspector\n```\n\nIn the inspector UI, connect to `http://localhost:3000`.\n\n## Core Concepts\n\n### MCP Primitives\n\nThe MCP protocol defines core primitives that enable communication between servers and clients:\n\n| Primitive     | Server Role                                       | Client Role                            | Description                                       |\n|---------------|---------------------------------------------------|----------------------------------------|---------------------------------------------------|\n| **Prompts**   | Provides prompt templates with optional arguments | Requests and uses prompts              | Interactive templates for LLM interactions        |\n| **Resources** | Exposes data sources (files, API responses, etc.) | Reads and subscribes to resources      | Contextual data for augmenting LLM context        |\n| **Tools**     | Defines executable functions                      | Calls tools to perform actions         | Functions the LLM can invoke to take actions      |\n| **Sampling**  | Requests LLM completions from client              | Executes LLM calls and returns results | Server-initiated LLM requests (reverse direction) |\n\n### Capabilities\n\nCapabilities define what features a server or client supports. They are declared during initialization and determine\nwhat operations are available.\n\n#### Server Capabilities\n\nServers declare their capabilities to inform clients what features they provide:\n\n| Capability     | Feature Flags                 | Description                                                |\n|----------------|-------------------------------|------------------------------------------------------------|\n| `prompts`      | `listChanged`                 | Prompt template management and notifications               |\n| `resources`    | `subscribe`\u003cbr/\u003e`listChanged` | Resource exposure, subscriptions, and update notifications |\n| `tools`        | `listChanged`                 | Tool discovery, execution, and list change notifications   |\n| `logging`      | -                             | Server logging to client console                           |\n| `completions`  | -                             | Argument autocompletion suggestions                        |\n| `experimental` | Custom properties             | Non-standard experimental features                         |\n\n#### Client Capabilities\n\nClients declare their capabilities to inform servers what features they support:\n\n| Capability     | Feature Flags     | Description                                                 |\n|----------------|-------------------|-------------------------------------------------------------|\n| `sampling`     | -                 | Client can sample from an LLM (execute model requests)      |\n| `roots`        | `listChanged`     | Client exposes root directories and can notify of changes   |\n| `elicitation`  | -                 | Client can display schema/form dialogs for structured input |\n| `experimental` | Custom properties | Non-standard experimental features                          |\n\n### Server Features\n\nThe `Server` API lets you wire prompts, resources, and tools with only a few lines of Kotlin. Each feature is registered\nup front and then resolved lazily when a client asks for it, so your handlers stay small and suspendable.\n\n#### Prompts\n\nPrompts are user-controlled templates that clients discover via `prompts/list` and fetch with `prompts/get` when a user\nchooses one (think slash commands or saved flows). They’re best for repeatable, structured starters rather than ad-hoc\nmodel calls.\n\n\u003c!--- INCLUDE\nimport io.modelcontextprotocol.kotlin.sdk.server.Server\nimport io.modelcontextprotocol.kotlin.sdk.server.ServerOptions\nimport io.modelcontextprotocol.kotlin.sdk.types.GetPromptResult\nimport io.modelcontextprotocol.kotlin.sdk.types.Implementation\nimport io.modelcontextprotocol.kotlin.sdk.types.PromptArgument\nimport io.modelcontextprotocol.kotlin.sdk.types.PromptMessage\nimport io.modelcontextprotocol.kotlin.sdk.types.Role\nimport io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities\nimport io.modelcontextprotocol.kotlin.sdk.types.TextContent\n\nfun main() {\n--\u003e\n\n```kotlin\nval server = Server(\n    serverInfo = Implementation(\n        name = \"example-server\",\n        version = \"1.0.0\"\n    ),\n    options = ServerOptions(\n        capabilities = ServerCapabilities(\n            prompts = ServerCapabilities.Prompts(listChanged = true),\n        ),\n    )\n)\n\nserver.addPrompt(\n    name = \"code-review\",\n    description = \"Ask the model to review a diff\",\n    arguments = listOf(\n        PromptArgument(name = \"diff\", description = \"Unified diff\", required = true),\n    ),\n) { request -\u003e\n    GetPromptResult(\n        description = \"Quick code review helper\",\n        messages = listOf(\n            PromptMessage(\n                role = Role.User,\n                content = TextContent(text = \"Review this change:\\n${request.arguments?.get(\"diff\")}\"),\n            ),\n        ),\n    )\n}\n```\n\n\u003c!--- SUFFIX\n}\n--\u003e\n\n\u003c!--- KNIT example-server-prompts-01.kt --\u003e\n\nUse prompts for anything that deserves a template: bug triage questions, onboarding checklists, or saved searches. Set\n`listChanged = true` only if your prompt catalog can change at runtime and your server will emit\n`notifications/prompts/list_changed` when it does.\n\n#### Resources\n\nResources are application-driven context that clients discover via `resources/list` or `resources/templates/list`, then\nfetch with `resources/read`. Register each one with a stable URI and return a `ReadResourceResult` when asked—contents\ncan be text or binary blobs.\n\n\u003c!--- INCLUDE\nimport io.modelcontextprotocol.kotlin.sdk.server.Server\nimport io.modelcontextprotocol.kotlin.sdk.server.ServerOptions\nimport io.modelcontextprotocol.kotlin.sdk.types.Implementation\nimport io.modelcontextprotocol.kotlin.sdk.types.ReadResourceResult\nimport io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities\nimport io.modelcontextprotocol.kotlin.sdk.types.TextResourceContents\n\nfun main() {\n--\u003e\n\n```kotlin\nval server = Server(\n    serverInfo = Implementation(\n        name = \"example-server\",\n        version = \"1.0.0\"\n    ),\n    options = ServerOptions(\n        capabilities = ServerCapabilities(\n            resources = ServerCapabilities.Resources(subscribe = true, listChanged = true),\n        ),\n    )\n)\n\nserver.addResource(\n    uri = \"note://release/latest\",\n    name = \"Release notes\",\n    description = \"Last deployment summary\",\n    mimeType = \"text/markdown\",\n) { request -\u003e\n    ReadResourceResult(\n        contents = listOf(\n            TextResourceContents(\n                text = \"Ship 42 reached production successfully.\",\n                uri = request.uri,\n                mimeType = \"text/markdown\",\n            ),\n        ),\n    )\n}\n```\n\n\u003c!--- SUFFIX\n}\n--\u003e\n\n\u003c!--- KNIT example-server-resources-01.kt --\u003e\n\nResources can be static text, generated JSON, or blobs—anything the client can surface to the user or inject into the\nmodel context. Set `subscribe = true` if you emit `notifications/resources/updated` for changes to specific URIs, and\n`listChanged = true` if you’ll send `notifications/resources/list_changed` when the catalog itself changes.\n\n#### Tools\n\nTools are model-controlled capabilities the client exposes to the model. Clients discover them via `tools/list`, invoke\nthem with `tools/call`, and your handlers receive JSON arguments, can emit streaming logs or progress, and return a\n`CallToolResult`. Keep a human in the loop for sensitive operations.\n\n\u003c!--- INCLUDE\nimport io.modelcontextprotocol.kotlin.sdk.server.Server\nimport io.modelcontextprotocol.kotlin.sdk.server.ServerOptions\nimport io.modelcontextprotocol.kotlin.sdk.types.CallToolResult\nimport io.modelcontextprotocol.kotlin.sdk.types.Implementation\nimport io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities\nimport io.modelcontextprotocol.kotlin.sdk.types.TextContent\nimport kotlinx.serialization.json.jsonPrimitive\n\nfun main() {\n--\u003e\n\n```kotlin\nval server = Server(\n    serverInfo = Implementation(\n        name = \"example-server\",\n        version = \"1.0.0\"\n    ),\n    options = ServerOptions(\n        capabilities = ServerCapabilities(\n            tools = ServerCapabilities.Tools(listChanged = true),\n        ),\n    )\n)\n\nserver.addTool(\n    name = \"echo\",\n    description = \"Return whatever the user sent back to them\",\n) { request -\u003e\n    val text = request.arguments?.get(\"text\")?.jsonPrimitive?.content ?: \"(empty)\"\n    CallToolResult(content = listOf(TextContent(text = \"Echo: $text\")))\n}\n```\n\n\u003c!--- SUFFIX\n}\n--\u003e\n\n\u003c!--- KNIT example-server-tools-01.kt --\u003e\n\nRegister as many tools as you need—long-running jobs can report progress via the request context, and tools can also\ntrigger sampling (see below) when they need the client’s LLM. Set `listChanged = true` only if your tool catalog can\nchange at runtime and your server will emit `notifications/tools/list_changed` when it does.\n\n#### Completion\n\nCompletion provides argument suggestions for prompts or resource templates. Declare the `completions` capability and\nhandle `completion/complete` requests to return up to 100 ranked values (include `total`/`hasMore` if you paginate).\n\n\u003c!--- INCLUDE\nimport io.modelcontextprotocol.kotlin.sdk.server.Server\nimport io.modelcontextprotocol.kotlin.sdk.server.ServerOptions\nimport io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport\nimport io.modelcontextprotocol.kotlin.sdk.types.CompleteRequest\nimport io.modelcontextprotocol.kotlin.sdk.types.CompleteResult\nimport io.modelcontextprotocol.kotlin.sdk.types.Implementation\nimport io.modelcontextprotocol.kotlin.sdk.types.Method\nimport io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities\nimport kotlinx.io.asSink\nimport kotlinx.io.asSource\nimport kotlinx.io.buffered\n\nsuspend fun main() {\n--\u003e\n\n```kotlin\nval server = Server(\n    serverInfo = Implementation(\n        name = \"example-server\",\n        version = \"1.0.0\"\n    ),\n    options = ServerOptions(\n        capabilities = ServerCapabilities(\n            completions = ServerCapabilities.Completions,\n        ),\n    )\n)\n\nval session = server.createSession(\n    StdioServerTransport(\n        inputStream = System.`in`.asSource().buffered(),\n        outputStream = System.out.asSink().buffered()\n    )\n)\n\nsession.setRequestHandler\u003cCompleteRequest\u003e(Method.Defined.CompletionComplete) { request, _ -\u003e\n    val options = listOf(\"kotlin\", \"compose\", \"coroutine\")\n    val matches = options.filter { it.startsWith(request.argument.value.lowercase()) }\n\n    CompleteResult(\n        completion = CompleteResult.Completion(\n            values = matches.take(3),\n            total = matches.size,\n            hasMore = matches.size \u003e 3,\n        ),\n    )\n}\n```\n\n\u003c!--- SUFFIX\n}\n--\u003e\n\n\u003c!--- KNIT example-server-util-completions-01.kt --\u003e\n\nUse `context.arguments` to refine suggestions for dependent fields (e.g., framework list filtered by chosen language).\n\n#### Logging\n\nLogging lets the server stream structured log notifications to the client using RFC 5424 levels (`debug` → `emergency`).\nDeclare the `logging` capability; clients can raise the minimum level with `logging/setLevel`, and the server emits\n`notifications/message` with severity, optional logger name, and JSON data.\n\n\u003c!--- INCLUDE\nimport io.modelcontextprotocol.kotlin.sdk.server.Server\nimport io.modelcontextprotocol.kotlin.sdk.server.ServerOptions\nimport io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport\nimport io.modelcontextprotocol.kotlin.sdk.types.Implementation\nimport io.modelcontextprotocol.kotlin.sdk.types.LoggingLevel\nimport io.modelcontextprotocol.kotlin.sdk.types.LoggingMessageNotification\nimport io.modelcontextprotocol.kotlin.sdk.types.LoggingMessageNotificationParams\nimport io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities\nimport kotlinx.io.asSink\nimport kotlinx.io.asSource\nimport kotlinx.io.buffered\nimport kotlinx.serialization.json.buildJsonObject\nimport kotlinx.serialization.json.put\n\nsuspend fun main() {\n--\u003e\n\n```kotlin\nval server = Server(\n    serverInfo = Implementation(\"example-server\", \"1.0.0\"),\n    options = ServerOptions(\n        capabilities = ServerCapabilities(\n            logging = ServerCapabilities.Logging,\n        ),\n    )\n)\n\nval session = server.createSession(\n    StdioServerTransport(\n        inputStream = System.`in`.asSource().buffered(),\n        outputStream = System.out.asSink().buffered()\n    )\n)\n\nsession.sendLoggingMessage(\n    LoggingMessageNotification(\n        LoggingMessageNotificationParams(\n            level = LoggingLevel.Info,\n            logger = \"startup\",\n            data = buildJsonObject { put(\"message\", \"Server started\") },\n        ),\n    ),\n)\n```\n\n\u003c!--- SUFFIX\n}\n--\u003e\n\n\u003c!--- KNIT example-server-util-logging-01.kt --\u003e\n\nKeep logs free of sensitive data, and expect clients to surface them in their own UI.\n\n#### Pagination\n\nList operations return paginated results with an opaque `nextCursor`, clients echo that cursor to fetch the next page.\nSupported list calls: `resources/list`, `resources/templates/list`, `prompts/list`, and `tools/list`.\nTreat cursors as opaque—don’t parse or persist them across sessions.\n\n\u003c!--- INCLUDE\nimport io.modelcontextprotocol.kotlin.sdk.server.Server\nimport io.modelcontextprotocol.kotlin.sdk.server.ServerOptions\nimport io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport\nimport io.modelcontextprotocol.kotlin.sdk.types.Implementation\nimport io.modelcontextprotocol.kotlin.sdk.types.ListResourcesRequest\nimport io.modelcontextprotocol.kotlin.sdk.types.ListResourcesResult\nimport io.modelcontextprotocol.kotlin.sdk.types.Method\nimport io.modelcontextprotocol.kotlin.sdk.types.Resource\nimport io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities\nimport kotlinx.io.asSink\nimport kotlinx.io.asSource\nimport kotlinx.io.buffered\n\nsuspend fun main() {\n--\u003e\n\n```kotlin\nval server = Server(\n    serverInfo = Implementation(\"example-server\", \"1.0.0\"),\n    options = ServerOptions(\n        capabilities = ServerCapabilities(\n            resources = ServerCapabilities.Resources(),\n        ),\n    )\n)\n\nval session = server.createSession(\n    StdioServerTransport(\n        inputStream = System.`in`.asSource().buffered(),\n        outputStream = System.out.asSink().buffered()\n    )\n)\n\nval resources = listOf(\n    Resource(uri = \"note://1\", name = \"Note 1\", description = \"First\"),\n    Resource(uri = \"note://2\", name = \"Note 2\", description = \"Second\"),\n    Resource(uri = \"note://3\", name = \"Note 3\", description = \"Third\"),\n)\nval pageSize = 2\n\nsession.setRequestHandler\u003cListResourcesRequest\u003e(Method.Defined.ResourcesList) { request, _ -\u003e\n    val start = request.params?.cursor?.toIntOrNull() ?: 0\n    val page = resources.drop(start).take(pageSize)\n    val next = if (start + page.size \u003c resources.size) (start + page.size).toString() else null\n\n    ListResourcesResult(\n        resources = page,\n        nextCursor = next,\n    )\n}\n```\n\n\u003c!--- SUFFIX\n}\n--\u003e\n\n\u003c!--- KNIT example-server-util-pagination-01.kt --\u003e\n\nInclude `nextCursor` only when more items remain an absent cursor ends pagination.\n\n### Client Features\n\nClients advertise their capabilities (roots, sampling, elicitation, etc.) during initialization. After that they can\nserve requests from the server while still initiating calls such as `listTools` or `callTool`.\n\n#### Roots\n\nRoots let the client declare where the server is allowed to operate. Declare the `roots` capability, respond to\n`roots/list`, and emit `notifications/roots/list_changed` if you set `listChanged = true`. URIs **must** be `file://`\npaths.\n\n\u003c!--- INCLUDE\nimport io.modelcontextprotocol.kotlin.sdk.client.Client\nimport io.modelcontextprotocol.kotlin.sdk.client.ClientOptions\nimport io.modelcontextprotocol.kotlin.sdk.types.ClientCapabilities\nimport io.modelcontextprotocol.kotlin.sdk.types.Implementation\n\nsuspend fun main() {\n--\u003e\n\n```kotlin\nval client = Client(\n    clientInfo = Implementation(\"demo-client\", \"1.0.0\"),\n    options = ClientOptions(\n        capabilities = ClientCapabilities(roots = ClientCapabilities.Roots(listChanged = true)),\n    ),\n)\n\nclient.addRoot(\n    uri = \"file:///Users/demo/projects\",\n    name = \"Projects\",\n)\nclient.sendRootsListChanged()\n```\n\n\u003c!--- SUFFIX \n}    \n--\u003e\n\n\u003c!--- KNIT example-client-roots-01.kt --\u003e\n\nCall `addRoot`/`removeRoot` whenever your file system view changes, and use `sendRootsListChanged()` to notify the\nserver. Keep root lists user-controlled and revoke entries that are no longer authorized.\n\n#### Sampling\n\nSampling lets the server ask the client to call its preferred LLM. Declare the `sampling` capability (and\n`sampling.tools` if you allow tool-enabled sampling), and handle `sampling/createMessage`. Keep a human in the loop for\napprovals.\n\n\u003c!--- INCLUDE\nimport io.modelcontextprotocol.kotlin.sdk.client.Client\nimport io.modelcontextprotocol.kotlin.sdk.client.ClientOptions\nimport io.modelcontextprotocol.kotlin.sdk.types.ClientCapabilities\nimport io.modelcontextprotocol.kotlin.sdk.types.CreateMessageRequest\nimport io.modelcontextprotocol.kotlin.sdk.types.CreateMessageResult\nimport io.modelcontextprotocol.kotlin.sdk.types.Implementation\nimport io.modelcontextprotocol.kotlin.sdk.types.Method\nimport io.modelcontextprotocol.kotlin.sdk.types.Role\nimport io.modelcontextprotocol.kotlin.sdk.types.TextContent\nimport kotlinx.serialization.json.buildJsonObject\nimport kotlinx.serialization.json.putJsonObject\n\nfun main() {\n--\u003e\n\n```kotlin\nval client = Client(\n    clientInfo = Implementation(\"demo-client\", \"1.0.0\"),\n    options = ClientOptions(\n        capabilities = ClientCapabilities(\n            sampling = buildJsonObject { putJsonObject(\"tools\") { } }, // drop tools if you don't support tool use\n        ),\n    ),\n)\n\nclient.setRequestHandler\u003cCreateMessageRequest\u003e(Method.Defined.SamplingCreateMessage) { request, _ -\u003e\n    val content = request.messages.lastOrNull()?.content\n    val prompt = if (content is TextContent) content.text else \"your topic\"\n    CreateMessageResult(\n        model = \"gpt-4o-mini\",\n        role = Role.Assistant,\n        content = TextContent(text = \"Here is a short note about $prompt\"),\n    )\n}\n```\n\n\u003c!--- SUFFIX\n}\n--\u003e\n\n\u003c!--- KNIT example-client-sampling-01.kt --\u003e\n\nInside the handler you can pick any model/provider, require approvals, or reject the request. If you don’t support tool\nuse, omit `sampling.tools` from capabilities.\n\n[//]: # (TODO: add elicitation section)\n\n[//]: # (#### Elicitation)\n\n## Transports\n\nAll transports share the same API surface, so you can change deployment style without touching business logic. Pick the\ntransport that best matches where the server runs.\n\n### STDIO Transport\n\n`StdioClientTransport` and `StdioServerTransport` tunnel MCP messages over stdin/stdout—perfect for editor plugins or\nCLI tooling that spawns a helper process. No networking setup is required.\n\n### Streamable HTTP Transport\n\n`StreamableHttpClientTransport` and the Ktor `streamableHttpApp()` helpers expose MCP over a single HTTP endpoint with\noptional JSON-only or SSE streaming responses. This is the recommended choice for remote deployments and integrates\nnicely with proxies or service meshes.\n\n### SSE Transport\n\nServer-Sent Events remain available for backwards compatibility with older MCP clients. Use `SseServerTransport` or the\nSSE Ktor plugin when you need drop-in compatibility, but prefer Streamable HTTP for new projects.\n\n### WebSocket Transport\n\n`WebSocketClientTransport` plus the matching server utilities provide full-duplex, low-latency connections—useful when\nyou expect lots of notifications or long-running sessions behind a reverse proxy that already terminates WebSockets.\n\n### ChannelTransport (testing)\n\n`ChannelTransport` provides a simple, non-networked transport for testing and local development.\nIt uses Kotlin coroutines channels to provide a full-duplex connection between a client and server,\nallowing for easy testing of MCP functionality without the need for network setup.\n\n## Connecting your server\n\n1. Start a sample HTTP server on port 3000:\n\n    ```bash\n    ./gradlew :samples:kotlin-mcp-server:run\n    ```\n\n2. Connect with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) or Claude Desktop/Code:\n\n   ```bash\n   npx -y @modelcontextprotocol/inspector --connect http://localhost:3000\n   # or\n   claude mcp add --transport http kotlin-mcp http://localhost:3000\n   ```\n\n3. In the Inspector, confirm prompts, tools, resources, completions, and logs show up. Iterate locally until you’re\n   ready to host the server wherever you prefer.\n\n## Examples\n\n| Scenario                 | Description                                                     | Example                                                                  |\n|--------------------------|-----------------------------------------------------------------|--------------------------------------------------------------------------|\n| Streamable HTTP server   | Full MCP server with prompts, resources, tools, completions     | [samples/kotlin-mcp-server](./samples/kotlin-mcp-server)                 |\n| STDIO weather server     | Minimal STDIO transport server exposing weather info and alerts | [samples/weather-stdio-server](./samples/weather-stdio-server)           |\n| Interactive STDIO client | MCP client that connects over STDIO and pipes requests to LLMs  | [samples/kotlin-mcp-client](./samples/kotlin-mcp-client)                 |\n| Streamable HTTP client   | MCP client demo in a runnable notebook                          | [samples/notebooks/McpClient.ipynb](./samples/notebooks/McpClient.ipynb) |\n\n## Documentation\n\n- [API Reference](https://modelcontextprotocol.github.io/kotlin-sdk/)\n- [Model Context Protocol documentation](https://modelcontextprotocol.io)\n- [MCP specification](https://modelcontextprotocol.io/specification/latest)\n\n## Contributing\n\nPlease see the [contribution guide](CONTRIBUTING.md) and the [Code of conduct](CODE_OF_CONDUCT.md) before contributing.\n\n## License\n\nThis project is licensed under Apache 2.0 for new contributions, with existing code under MIT—see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmodelcontextprotocol%2Fkotlin-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmodelcontextprotocol%2Fkotlin-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmodelcontextprotocol%2Fkotlin-sdk/lists"}