Skip to content

Commit ebfa6ba

Browse files
authored
Merge branch 'main' into devcrocod/document-public-api
2 parents e2fc8b0 + 3617ce4 commit ebfa6ba

33 files changed

Lines changed: 2467 additions & 472 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
include:
3535
- os: ubuntu-latest
3636
job-name: "Linux Tests"
37-
gradle-tasks: "build"
37+
gradle-tasks: "ktlintCheck build"
3838
max-workers: 3
3939

4040
- os: macos-latest

README.md

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,34 @@ standardized protocol interface.
1919

2020
* [Overview](#overview)
2121
* [Installation](#installation)
22-
* [Artifacts](#artifacts)
23-
* [Gradle setup (JVM)](#gradle-setup-jvm)
24-
* [Multiplatform](#multiplatform)
25-
* [Ktor dependencies](#ktor-dependencies)
22+
* [Artifacts](#artifacts)
23+
* [Gradle setup (JVM)](#gradle-setup-jvm)
24+
* [Multiplatform](#multiplatform)
25+
* [Ktor dependencies](#ktor-dependencies)
2626
* [Quickstart](#quickstart)
27-
* [Creating a Client](#creating-a-client)
28-
* [Creating a Server](#creating-a-server)
27+
* [Creating a Client](#creating-a-client)
28+
* [Creating a Server](#creating-a-server)
2929
* [Core Concepts](#core-concepts)
30-
* [MCP Primitives](#mcp-primitives)
31-
* [Capabilities](#capabilities)
32-
* [Server Capabilities](#server-capabilities)
33-
* [Client Capabilities](#client-capabilities)
34-
* [Server Features](#server-features)
35-
* [Prompts](#prompts)
36-
* [Resources](#resources)
37-
* [Tools](#tools)
38-
* [Completion](#completion)
39-
* [Logging](#logging)
40-
* [Pagination](#pagination)
41-
* [Client Features](#client-features)
42-
* [Roots](#roots)
43-
* [Sampling](#sampling)
30+
* [MCP Primitives](#mcp-primitives)
31+
* [Capabilities](#capabilities)
32+
* [Server Capabilities](#server-capabilities)
33+
* [Client Capabilities](#client-capabilities)
34+
* [Server Features](#server-features)
35+
* [Prompts](#prompts)
36+
* [Resources](#resources)
37+
* [Tools](#tools)
38+
* [Completion](#completion)
39+
* [Logging](#logging)
40+
* [Pagination](#pagination)
41+
* [Client Features](#client-features)
42+
* [Roots](#roots)
43+
* [Sampling](#sampling)
4444
* [Transports](#transports)
45-
* [STDIO Transport](#stdio-transport)
46-
* [Streamable HTTP Transport](#streamable-http-transport)
47-
* [SSE Transport](#sse-transport)
48-
* [WebSocket Transport](#websocket-transport)
49-
* [ChannelTransport (testing)](#channeltransport-testing)
45+
* [STDIO Transport](#stdio-transport)
46+
* [Streamable HTTP Transport](#streamable-http-transport)
47+
* [SSE Transport](#sse-transport)
48+
* [WebSocket Transport](#websocket-transport)
49+
* [ChannelTransport (testing)](#channeltransport-testing)
5050
* [Connecting your server](#connecting-your-server)
5151
* [Examples](#examples)
5252
* [Documentation](#documentation)
@@ -188,24 +188,19 @@ the [simple-streamable-server](samples/simple-streamable-server) sample.
188188
<!--- CLEAR -->
189189

190190
```kotlin
191-
import io.ktor.serialization.kotlinx.json.json
192-
import io.ktor.server.application.install
193191
import io.ktor.server.cio.CIO
194192
import io.ktor.server.engine.embeddedServer
195-
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
196193
import io.modelcontextprotocol.kotlin.sdk.server.Server
197194
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
198195
import io.modelcontextprotocol.kotlin.sdk.server.mcpStreamableHttp
199196
import io.modelcontextprotocol.kotlin.sdk.types.CallToolResult
200197
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
201-
import io.modelcontextprotocol.kotlin.sdk.types.McpJson
202198
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
203199
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
204200
import io.modelcontextprotocol.kotlin.sdk.types.ToolSchema
205201
import kotlinx.serialization.json.buildJsonObject
206202
import kotlinx.serialization.json.put
207203

208-
209204
fun main(args: Array<String>) {
210205
val port = args.firstOrNull()?.toIntOrNull() ?: 3000
211206
val mcpServer = Server(
@@ -231,11 +226,8 @@ fun main(args: Array<String>) {
231226
) { request ->
232227
CallToolResult(content = listOf(TextContent("Hello, world!")))
233228
}
234-
229+
235230
embeddedServer(CIO, host = "127.0.0.1", port = port) {
236-
install(ContentNegotiation) {
237-
json(McpJson)
238-
}
239231
mcpStreamableHttp {
240232
mcpServer
241233
}
@@ -774,8 +766,10 @@ CLI tooling that spawns a helper process. No networking setup is required.
774766

775767
`StreamableHttpClientTransport` and the Ktor `mcpStreamableHttp()` / `mcpStatelessStreamableHttp()` helpers expose MCP
776768
over a single HTTP endpoint with optional JSON-only or SSE streaming responses. This is the recommended choice for
777-
remote deployments and integrates nicely with proxies or service meshes. Both accept a `path` parameter (default:
778-
`"/mcp"`) to mount the endpoint at any URL:
769+
remote deployments and integrates nicely with proxies or service meshes.
770+
771+
These helpers automatically install `ContentNegotiation` with `McpJson` — do not install it yourself, or a warning will
772+
be logged. Both accept a `path` parameter (default: `"/mcp"`) to mount the endpoint at any URL:
779773

780774
<!--- CLEAR -->
781775
<!--- INCLUDE
@@ -809,11 +803,30 @@ embeddedServer(CIO, port = 3000) {
809803
-->
810804
<!--- KNIT example-server-routes-01.kt -->
811805

806+
**CORS for browser-based clients (e.g. MCP Inspector):** if you connect from a browser-based
807+
client you need to install the Ktor CORS plugin so that MCP-specific headers are allowed and exposed:
808+
809+
```kotlin
810+
install(CORS) {
811+
anyHost() // restrict to specific origins in production
812+
allowMethod(HttpMethod.Options)
813+
allowMethod(HttpMethod.Get)
814+
allowMethod(HttpMethod.Post)
815+
allowMethod(HttpMethod.Delete)
816+
allowNonSimpleContentTypes = true
817+
allowHeader("Mcp-Session-Id")
818+
allowHeader("Mcp-Protocol-Version")
819+
exposeHeader("Mcp-Session-Id")
820+
exposeHeader("Mcp-Protocol-Version")
821+
}
822+
```
823+
812824
### SSE Transport
813825

814826
Server-Sent Events remain available for backwards compatibility with older MCP clients. Two Ktor helpers are provided:
815827

816-
- **`Application.mcp { }`** — installs the SSE plugin automatically and registers MCP endpoints at `/`.
828+
- **`Application.mcp { }`** — installs SSE and `ContentNegotiation` with `McpJson` automatically, then registers MCP
829+
endpoints at `/`. Do not install `ContentNegotiation` yourself — the SDK handles it.
817830
- **`Route.mcp { }`** — registers MCP endpoints at the current route path; requires `install(SSE)` in the application
818831
first. Use this to host MCP alongside other routes or under a path prefix:
819832

conformance-test/conformance-baseline.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@
22
# Add entries here as tests are identified as known SDK limitations
33
server: []
44

5-
client:
6-
- elicitation-sep1034-client-defaults
5+
client: []

conformance-test/run-conformance.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ set -uo pipefail
99
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1; pwd)"
1010
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." || exit 1; pwd)"
1111

12-
CONFORMANCE_VERSION="0.1.15"
12+
CONFORMANCE_VERSION="0.1.16"
1313
PORT="${MCP_PORT:-3001}"
1414
SERVER_URL="http://localhost:${PORT}/mcp"
1515
RESULTS_DIR="$SCRIPT_DIR/results"

conformance-test/src/main/kotlin/io/modelcontextprotocol/kotlin/sdk/conformance/ConformanceServer.kt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,16 @@
11
package io.modelcontextprotocol.kotlin.sdk.conformance
22

3-
import io.ktor.serialization.kotlinx.json.json
4-
import io.ktor.server.application.install
53
import io.ktor.server.cio.CIO
64
import io.ktor.server.engine.embeddedServer
7-
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
85
import io.modelcontextprotocol.kotlin.sdk.server.Server
96
import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions
107
import io.modelcontextprotocol.kotlin.sdk.server.mcpStreamableHttp
118
import io.modelcontextprotocol.kotlin.sdk.types.Implementation
12-
import io.modelcontextprotocol.kotlin.sdk.types.McpJson
139
import io.modelcontextprotocol.kotlin.sdk.types.ServerCapabilities
1410

1511
fun main() {
1612
val port = System.getenv("MCP_PORT")?.toIntOrNull() ?: 3001
1713
embeddedServer(CIO, port = port) {
18-
install(ContentNegotiation) {
19-
json(McpJson)
20-
}
2114
mcpStreamableHttp(
2215
enableDnsRebindingProtection = true,
2316
allowedHosts = listOf("localhost", "127.0.0.1", "localhost:$port", "127.0.0.1:$port"),

0 commit comments

Comments
 (0)