Skip to content

Commit f112b7b

Browse files
committed
Update README with expanded sections and knit examples
1 parent 0663972 commit f112b7b

File tree

1 file changed

+299
-13
lines changed

1 file changed

+299
-13
lines changed

README.md

Lines changed: 299 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,33 @@ standardized protocol interface.
1717

1818
* [Overview](#overview)
1919
* [Installation](#installation)
20+
* [Artifacts](#artifacts)
21+
* [Gradle setup (JVM)](#gradle-setup-jvm)
22+
* [Multiplatform](#multiplatform)
23+
* [Ktor dependencies](#ktor-dependencies)
2024
* [Quickstart](#quickstart)
2125
* [Creating a Client](#creating-a-client)
2226
* [Creating a Server](#creating-a-server)
2327
* [Core Concepts](#core-concepts)
2428
* [MCP Primitives](#mcp-primitives)
2529
* [Capabilities](#capabilities)
30+
* [Server Capabilities](#server-capabilities)
31+
* [Client Capabilities](#client-capabilities)
2632
* [Server Features](#server-features)
2733
* [Prompts](#prompts)
2834
* [Resources](#resources)
2935
* [Tools](#tools)
36+
* [Completion](#completion)
37+
* [Logging](#logging)
38+
* [Pagination](#pagination)
3039
* [Client Features](#client-features)
3140
* [Roots](#roots)
3241
* [Sampling](#sampling)
33-
* [Utilities](#utilities)
34-
* [Completion](#completion)
35-
* [Logging](#logging)
36-
* [Transports](#transports)
37-
* [STDIO Transport](#stdio-transport)
38-
* [Streamable HTTP Transport](#streamable-http-transport)
39-
* [SSE Transport](#sse-transport)
40-
* [WebSocket Transport](#websocket-transport)
42+
* [Transports](#transports)
43+
* [STDIO Transport](#stdio-transport)
44+
* [Streamable HTTP Transport](#streamable-http-transport)
45+
* [SSE Transport](#sse-transport)
46+
* [WebSocket Transport](#websocket-transport)
4147
* [Connecting your server](#connecting-your-server)
4248
* [Examples](#examples)
4349
* [Documentation](#documentation)
@@ -277,40 +283,316 @@ Clients declare their capabilities to inform servers what features they support:
277283

278284
### Server Features
279285

286+
The `Server` API lets you wire prompts, resources, and tools with only a few lines of Kotlin. Each feature is registered
287+
up front and then resolved lazily when a client asks for it, so your handlers stay small and suspendable.
288+
280289
#### Prompts
281290

291+
Prompts are reusable templates that help users or clients start conversations in a consistent way.
292+
293+
<!--- INCLUDE
294+
import io.modelcontextprotocol.kotlin.sdk.server.Server
295+
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
296+
import io.modelcontextprotocol.kotlin.sdk.types.GetPromptResult
297+
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
298+
import io.modelcontextprotocol.kotlin.sdk.types.PromptArgument
299+
import io.modelcontextprotocol.kotlin.sdk.types.PromptMessage
300+
import io.modelcontextprotocol.kotlin.sdk.types.Role
301+
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
302+
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
303+
304+
fun main() {
305+
-->
306+
307+
```kotlin
308+
val server = Server(
309+
serverInfo = Implementation(
310+
name = "example-server",
311+
version = "1.0.0"
312+
),
313+
options = ServerOptions(
314+
capabilities = ServerCapabilities(
315+
prompts = ServerCapabilities.Prompts(listChanged = true),
316+
),
317+
)
318+
)
319+
320+
server.addPrompt(
321+
name = "code-review",
322+
description = "Ask the model to review a diff",
323+
arguments = listOf(
324+
PromptArgument(name = "diff", description = "Unified diff", required = true),
325+
),
326+
) { request ->
327+
GetPromptResult(
328+
description = "Quick code review helper",
329+
messages = listOf(
330+
PromptMessage(
331+
role = Role.User,
332+
content = TextContent(text = "Review this change:\n${request.arguments?.get("diff")}"),
333+
),
334+
),
335+
)
336+
}
337+
```
338+
339+
<!--- SUFFIX
340+
}
341+
-->
342+
343+
<!--- KNIT example-server-prompts-01.kt -->
344+
345+
Use prompts for anything that deserves a template: bug triage questions, onboarding checklists, or saved searches.
346+
282347
#### Resources
283348

349+
Resources expose read-only context. Register them with a stable URI and return a `ReadResourceResult` when the client
350+
reads the resource.
351+
352+
<!--- INCLUDE
353+
import io.modelcontextprotocol.kotlin.sdk.server.Server
354+
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
355+
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
356+
import io.modelcontextprotocol.kotlin.sdk.types.ReadResourceResult
357+
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
358+
import io.modelcontextprotocol.kotlin.sdk.types.TextResourceContents
359+
360+
fun main() {
361+
-->
362+
363+
```kotlin
364+
val server = Server(
365+
serverInfo = Implementation(
366+
name = "example-server",
367+
version = "1.0.0"
368+
),
369+
options = ServerOptions(
370+
capabilities = ServerCapabilities(
371+
resources = ServerCapabilities.Resources(subscribe = true, listChanged = true),
372+
),
373+
)
374+
)
375+
376+
server.addResource(
377+
uri = "note://release/latest",
378+
name = "Release notes",
379+
description = "Last deployment summary",
380+
mimeType = "text/markdown",
381+
) { request ->
382+
ReadResourceResult(
383+
contents = listOf(
384+
TextResourceContents(
385+
text = "Ship 42 reached production successfully.",
386+
uri = request.uri,
387+
mimeType = "text/markdown",
388+
),
389+
),
390+
)
391+
}
392+
```
393+
394+
<!--- SUFFIX
395+
}
396+
-->
397+
398+
<!--- KNIT example-server-resources-01.kt -->
399+
400+
Resources can be static text, generated JSON, or blobs—anything the client can surface to the user or inject into the
401+
model context.
402+
284403
#### Tools
285404

405+
Tools are the imperative side of MCP. Each tool gets JSON arguments, can emit streaming logs or progress, and returns a
406+
`CallToolResult`.
407+
408+
<!--- INCLUDE
409+
import io.modelcontextprotocol.kotlin.sdk.server.Server
410+
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
411+
import io.modelcontextprotocol.kotlin.sdk.types.CallToolResult
412+
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
413+
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
414+
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
415+
import kotlinx.serialization.json.jsonPrimitive
416+
417+
fun main() {
418+
-->
419+
420+
```kotlin
421+
val server = Server(
422+
serverInfo = Implementation(
423+
name = "example-server",
424+
version = "1.0.0"
425+
),
426+
options = ServerOptions(
427+
capabilities = ServerCapabilities(
428+
tools = ServerCapabilities.Tools(listChanged = true),
429+
),
430+
)
431+
)
432+
433+
server.addTool(
434+
name = "echo",
435+
description = "Return whatever the user sent back to them",
436+
) { request ->
437+
val text = request.arguments?.get("text")?.jsonPrimitive?.content ?: "(empty)"
438+
CallToolResult(content = listOf(TextContent(text = "Echo: $text")))
439+
}
440+
```
441+
442+
<!--- SUFFIX
443+
}
444+
-->
445+
446+
<!--- KNIT example-server-tools-01.kt -->
447+
448+
Register as many tools as you need—long-running jobs can report progress via the request context, and tools can also
449+
trigger sampling (see below) when they need the client’s LLM.
450+
451+
#### Completion
452+
453+
#### Logging
454+
455+
#### Pagination
456+
286457
### Client Features
287458

459+
Clients advertise their capabilities (roots, sampling, elicitation, etc.) during initialization. After that they can
460+
serve requests from the server while still initiating calls such as `listTools` or `callTool`.
461+
288462
#### Roots
289463

464+
Roots describe folders or logical mounts that the client is willing to expose. Servers can list them to understand what
465+
paths are available before proposing file operations.
466+
467+
<!--- INCLUDE
468+
import io.modelcontextprotocol.kotlin.sdk.client.Client
469+
import io.modelcontextprotocol.kotlin.sdk.client.ClientOptions
470+
import io.modelcontextprotocol.kotlin.sdk.types.ClientCapabilities
471+
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
472+
473+
suspend fun main() {
474+
-->
475+
476+
```kotlin
477+
val client = Client(
478+
clientInfo = Implementation("demo-client", "1.0.0"),
479+
options = ClientOptions(
480+
capabilities = ClientCapabilities(roots = ClientCapabilities.Roots(listChanged = true)),
481+
),
482+
)
483+
484+
client.addRoot(
485+
uri = "file:///Users/demo/projects",
486+
name = "Projects",
487+
)
488+
client.sendRootsListChanged()
489+
```
490+
491+
<!--- SUFFIX
492+
}
493+
-->
494+
495+
<!--- KNIT example-client-roots-01.kt -->
496+
497+
Call `addRoot`/`removeRoot` whenever your file system view changes, and use `sendRootsListChanged()` to notify the
498+
server.
499+
290500
#### Sampling
291501

292-
[//]: # (TODO: add elicitation section)
502+
Sampling lets a server ask the client to call its preferred LLM. Enable it by declaring the `sampling` capability and
503+
handling the `sampling/createMessage` request.
293504

294-
[//]: # (#### Elicitation)
505+
<!--- INCLUDE
506+
import io.modelcontextprotocol.kotlin.sdk.client.Client
507+
import io.modelcontextprotocol.kotlin.sdk.client.ClientOptions
508+
import io.modelcontextprotocol.kotlin.sdk.types.ClientCapabilities
509+
import io.modelcontextprotocol.kotlin.sdk.types.CreateMessageRequest
510+
import io.modelcontextprotocol.kotlin.sdk.types.CreateMessageResult
511+
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
512+
import io.modelcontextprotocol.kotlin.sdk.types.Method
513+
import io.modelcontextprotocol.kotlin.sdk.types.Role
514+
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
295515
296-
### Utilities
516+
fun main() {
517+
-->
297518

298-
#### Completion
519+
```kotlin
520+
val client = Client(
521+
clientInfo = Implementation("demo-client", "1.0.0"),
522+
options = ClientOptions(
523+
capabilities = ClientCapabilities(sampling = ClientCapabilities.sampling),
524+
),
525+
)
526+
527+
client.setRequestHandler<CreateMessageRequest>(Method.Defined.SamplingCreateMessage) { request, _ ->
528+
val content = request.messages.lastOrNull()?.content
529+
val prompt = if (content is TextContent) content.text else "your topic"
530+
CreateMessageResult(
531+
model = "gpt-4o-mini",
532+
role = Role.Assistant,
533+
content = TextContent(text = "Here is a short note about $prompt"),
534+
)
535+
}
536+
```
299537

300-
#### Logging
538+
<!--- SUFFIX
539+
}
540+
-->
541+
542+
<!--- KNIT example-client-sampling-01.kt -->
543+
544+
Inside the handler you are free to choose any model/provider, collect extra approvals, or reject the request.
545+
546+
[//]: # (TODO: add elicitation section)
547+
548+
[//]: # (#### Elicitation)
301549

302550
## Transports
303551

552+
All transports share the same API surface, so you can change deployment style without touching business logic. Pick the
553+
transport that best matches where the server runs.
554+
304555
### STDIO Transport
305556

557+
`StdioClientTransport` and `StdioServerTransport` tunnel MCP messages over stdin/stdout—perfect for editor plugins or
558+
CLI tooling that spawns a helper process. No networking setup is required.
559+
306560
### Streamable HTTP Transport
307561

562+
`StreamableHttpClientTransport` and the Ktor `streamableHttpApp()` helpers expose MCP over a single HTTP endpoint with
563+
optional JSON-only or SSE streaming responses. This is the recommended choice for remote deployments and integrates
564+
nicely with proxies or service meshes.
565+
308566
### SSE Transport
309567

568+
Server-Sent Events remain available for backwards compatibility with older MCP clients. Use `SseServerTransport` or the
569+
SSE Ktor plugin when you need drop-in compatibility, but prefer Streamable HTTP for new projects.
570+
310571
### WebSocket Transport
311572

573+
`WebSocketClientTransport` plus the matching server utilities provide full-duplex, low-latency connections—useful when
574+
you expect lots of notifications or long-running sessions behind a reverse proxy that already terminates WebSockets.
575+
312576
## Connecting your server
313577

578+
1. Start a sample server:
579+
580+
```bash
581+
./gradlew :samples:kotlin-mcp-server:run
582+
```
583+
584+
2. Point the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) or Claude Desktop/Code at the running
585+
endpoint:
586+
587+
```bash
588+
npx -y @modelcontextprotocol/inspector --connect http://localhost:3000/mcp
589+
# or
590+
claude mcp add --transport http kotlin-mcp http://localhost:3000/mcp
591+
```
592+
593+
3. Watch the Inspector UI to verify prompts, tools, resources, and logs are all available, then iterate on your server
594+
locally until it’s ready for production hosting.
595+
314596
## Examples
315597

316598
- [kotlin-mcp-server](./samples/kotlin-mcp-server): demonstrates a MCP server setup with
@@ -322,6 +604,10 @@ Clients declare their capabilities to inform servers what features they support:
322604

323605
## Documentation
324606

607+
- [API Reference](https://modelcontextprotocol.github.io/kotlin-sdk/)
608+
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
609+
- [MCP specification](https://modelcontextprotocol.io/specification/latest)
610+
325611
## Contributing
326612

327613
Please see the [contribution guide](CONTRIBUTING.md) and the [Code of conduct](CODE_OF_CONDUCT.md) before contributing.

0 commit comments

Comments
 (0)