Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ jobs:
sample:
- kotlin-mcp-client
- kotlin-mcp-server
- simple-streamable-server

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻

- weather-stdio-server

name: "Build Sample: ${{ matrix.sample }}"
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/samples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
sample:
- kotlin-mcp-client
- kotlin-mcp-server
- simple-streamable-server
- weather-stdio-server

name: Build Sample (${{ matrix.sample }})
Expand Down
84 changes: 48 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,34 @@ standardized protocol interface.

* [Overview](#overview)
* [Installation](#installation)
* [Artifacts](#artifacts)
* [Gradle setup (JVM)](#gradle-setup-jvm)
* [Multiplatform](#multiplatform)
* [Ktor dependencies](#ktor-dependencies)
* [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)
* [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)
* [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)
* [ChannelTransport (testing)](#channeltransport-testing)
* [STDIO Transport](#stdio-transport)
* [Streamable HTTP Transport](#streamable-http-transport)
* [SSE Transport](#sse-transport)
* [WebSocket Transport](#websocket-transport)
* [ChannelTransport (testing)](#channeltransport-testing)
* [Connecting your server](#connecting-your-server)
* [Examples](#examples)
* [Documentation](#documentation)
Expand Down Expand Up @@ -183,17 +183,24 @@ fun main(args: Array<String>) = runBlocking {

### Creating a Server

Create an MCP server that exposes a simple tool and runs on an embedded Ktor server with SSE transport:
Create an MCP server that exposes a simple tool and runs on an embedded Ktor server with Streamable HTTP transport.
For a full working project with all required dependencies, see
the [simple-streamable-server](samples/simple-streamable-server) sample.

<!--- CLEAR -->

```kotlin
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.install
import io.ktor.server.cio.CIO
import io.ktor.server.engine.embeddedServer
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.modelcontextprotocol.kotlin.sdk.server.Server
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
import io.modelcontextprotocol.kotlin.sdk.server.mcp
import io.modelcontextprotocol.kotlin.sdk.server.mcpStreamableHttp
import io.modelcontextprotocol.kotlin.sdk.types.CallToolResult
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
import io.modelcontextprotocol.kotlin.sdk.types.McpJson
Comment thread
devcrocod marked this conversation as resolved.
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
import io.modelcontextprotocol.kotlin.sdk.types.ToolSchema
Expand Down Expand Up @@ -228,7 +235,10 @@ fun main(args: Array<String>) {
}

embeddedServer(CIO, host = "127.0.0.1", port = port) {
mcp {
install(ContentNegotiation) {
json(McpJson)
}
mcpStreamableHttp {
Comment thread
devcrocod marked this conversation as resolved.
mcpServer
}
}.start(wait = true)
Expand All @@ -243,7 +253,7 @@ You can run the server and then connect to it using the client or test with the
npx -y @modelcontextprotocol/inspector
```

In the inspector UI, connect to `http://localhost:3000`.
In the inspector UI, connect to `http://localhost:3000/mcp`.

## Core Concepts

Expand Down Expand Up @@ -787,13 +797,15 @@ private class MyServer :

fun main() {
-->

```kotlin
embeddedServer(CIO, port = 3000) {
mcpStreamableHttp(path = "/api/mcp") {
MyServer()
}
}.start(wait = true)
```

<!--- SUFFIX
}
-->
Expand Down Expand Up @@ -831,6 +843,7 @@ private class MyServer :

fun main() {
-->

```kotlin
embeddedServer(CIO, port = 3000) {
install(SSE)
Expand All @@ -841,6 +854,7 @@ embeddedServer(CIO, port = 3000) {
}
}.start(wait = true)
```

<!--- SUFFIX
}
-->
Expand Down Expand Up @@ -880,12 +894,9 @@ allowing for easy testing of MCP functionality without the need for network setu

## 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) |
The [samples](./samples) directory contains runnable projects demonstrating
MCP server and client implementations with various transports.
See the [samples overview](./samples/README.md) for a comparison table and detailed descriptions.

## Documentation

Expand All @@ -899,4 +910,5 @@ Please see the [contribution guide](CONTRIBUTING.md) and the [Code of conduct](C

## License

This project is licensed under Apache 2.0 for new contributions, with existing code under MIT—see the [LICENSE](LICENSE) file for details.
This project is licensed under Apache 2.0 for new contributions, with existing code under MIT—see the [LICENSE](LICENSE)
file for details.
2 changes: 2 additions & 0 deletions docs/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ plugins {
dependencies {
implementation(project(":kotlin-sdk"))
implementation(libs.ktor.server.cio)
implementation(libs.ktor.serialization)
implementation(libs.ktor.server.content.negotiation)
}

tasks.matching {
Expand Down
55 changes: 55 additions & 0 deletions samples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Kotlin MCP SDK Samples

Runnable projects demonstrating MCP server and client implementations with the
[Kotlin MCP SDK](https://github.com/modelcontextprotocol/kotlin-sdk).
For background on the protocol itself, see the [MCP documentation](https://modelcontextprotocol.io/introduction).

## Overview

| Sample | Type | Transport | MCP Features |
|--------------------------------------------------------|-------------------|-----------------|------------------------------------|
| [simple-streamable-server](./simple-streamable-server) | Server | Streamable HTTP | Tools, Resources, Prompts, Logging |
| [kotlin-mcp-server](./kotlin-mcp-server) | Server | STDIO, SSE | Tools, Resources, Prompts |
| [weather-stdio-server](./weather-stdio-server) | Server | STDIO | Tools |
| [kotlin-mcp-client](./kotlin-mcp-client) | Client | STDIO | Tool discovery & invocation |
| [notebooks](./notebooks) | Client (Notebook) | Streamable HTTP | Tool discovery & invocation |

## Getting Started

- **Building a server?** Start with [simple-streamable-server](./simple-streamable-server) — it
uses the recommended Streamable HTTP transport and covers tools, resources, prompts, and logging.
- **Building a client?** Open the [notebooks](./notebooks) sample for a step-by-step walkthrough,
or see [kotlin-mcp-client](./kotlin-mcp-client) for a full CLI client with Anthropic API
integration.

## Samples

### Simple Streamable HTTP Server

A minimal Streamable HTTP server with optional Bearer token authentication. Demonstrates tools
(`greet`, `multi-greet`), a prompt template, a resource, and server-to-client logging notifications.
[Read more →](./simple-streamable-server)

### Kotlin MCP Server

A multi-transport server supporting STDIO, SSE (plain), and SSE (Ktor plugin). Useful for exploring
different transport modes side by side.
[Read more →](./kotlin-mcp-server)

### Weather STDIO Server

A focused STDIO server that exposes weather forecast and alert tools backed by the weather.gov API.
Includes Claude Desktop integration instructions.
[Read more →](./weather-stdio-server)

### Kotlin MCP Client

An interactive CLI client that connects to any MCP server over STDIO and routes queries through
Anthropic's Claude API, bridging MCP tools with LLM conversations.
[Read more →](./kotlin-mcp-client)

### MCP Client Notebook

A Kotlin notebook that connects to a remote MCP server via Streamable HTTP and demonstrates ping,
tool listing, and tool invocation — all in an interactive cell-by-cell format.
[Read more →](./notebooks)
73 changes: 27 additions & 46 deletions samples/kotlin-mcp-client/README.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,50 @@
# Kotlin MCP Client

This project demonstrates how to build a Model Context Protocol (MCP) client in Kotlin that interacts with an MCP server
via a STDIO transport layer while leveraging Anthropic's API for natural language processing. The client uses the MCP
Kotlin SDK to communicate with an MCP server that exposes various tools, and it uses Anthropic's API to process user
queries and integrate tool responses into the conversation.

For more information about the MCP SDK and protocol, please refer to
the [MCP documentation](https://modelcontextprotocol.io/introduction).

## Prerequisites

- **Java 17 or later**
- **Gradle** (or the Gradle wrapper provided with the project)
- An Anthropic API key set in your environment variable `ANTHROPIC_API_KEY`
- Basic understanding of MCP concepts and Kotlin programming
An interactive CLI client that connects to any MCP server over STDIO and pipes queries through
Anthropic's Claude API.

## Overview

The client application performs the following tasks:
This sample demonstrates a complete MCP client workflow: launching an MCP server as a subprocess,
discovering its tools, converting them to Anthropic's tool format, and running an interactive chat
loop where Claude can call server tools on behalf of the user.
Comment thread
kpavlov marked this conversation as resolved.

- **Connecting to an MCP server** —
launches an MCP server process (implemented in JavaScript, Python, or Java) using STDIO transport.
It connects to the server, retrieves available tools, and converts them to Anthropic’s tool format.
- **Processing queries** —
accepts user queries, sends them to Anthropic’s API along with the registered tools, and handles responses.
If the response indicates a tool should be called, it invokes the corresponding MCP tool and continues the
conversation based on the tool’s result.
- **Interactive chat loop** —
runs an interactive command-line loop, allowing users to continuously submit queries and receive responses.
## Prerequisites

## Building and Running
- JDK 17+
- An `ANTHROPIC_API_KEY` environment variable set with a valid Anthropic API key
- An MCP server script to connect to (`.js`, `.py`, or `.jar`)

Use the Gradle wrapper to build the application. In a terminal, run:
## Build & Run

```shell
./gradlew clean build
```
Run the client, passing the path to an MCP server:

To run the client, execute the jar file and provide the path to your MCP server script.
```shell
# Connect to a JVM server
./gradlew run --args="path/to/server.jar"

To run the client with any MCP server:
# Connect to a Python server
./gradlew run --args="path/to/server.py"

```shell
java -jar build/libs/<your-jar-name>.jar path/to/server.jar # jvm server
java -jar build/libs/<your-jar-name>.jar path/to/server.py # python server
java -jar build/libs/<your-jar-name>.jar path/to/build/index.js # node server
# Connect to a Node.js server
./gradlew run --args="path/to/build/index.js"
```
Comment thread
devcrocod marked this conversation as resolved.

> [!NOTE]
> The client uses STDIO transport, so it launches the MCP server as a separate process.
> The client uses STDIO transport, so it launches the MCP server as a subprocess.
> Ensure the server script is executable and is a valid `.js`, `.py`, or `.jar` file.

## Configuration for Anthropic
## MCP Capabilities

Ensure your Anthropic API key is available in your environment:

```shell
export ANTHROPIC_API_KEY=your_anthropic_api_key_here
```
From the **client** perspective, this sample demonstrates:

The client uses `AnthropicOkHttpClient.fromEnv()` to automatically load the API key from `ANTHROPIC_API_KEY` and
`ANTHROPIC_AUTH_TOKEN` environment variables.
- **Tool discovery** — lists tools from the connected server and converts them to Anthropic's tool
format.
- **Tool invocation** — when Claude's response requests a tool call, the client invokes the
corresponding MCP tool and feeds the result back into the conversation.

## Additional Resources

- [MCP Specification](https://spec.modelcontextprotocol.io/)
- [MCP Specification](https://modelcontextprotocol.io/specification/latest)
- [Kotlin MCP SDK](https://github.com/modelcontextprotocol/kotlin-sdk)
- [Anthropic Java SDK](https://github.com/anthropics/anthropic-sdk-java/tree/main)
- [Anthropic Java SDK](https://github.com/anthropics/anthropic-sdk-java)
Loading
Loading