From 0eefeabd96648f630e63792db13e750be1ff6cb8 Mon Sep 17 00:00:00 2001 From: devcrocod Date: Mon, 19 Oct 2026 22:37:23 +0200 Subject: [PATCH 1/3] chore: deprecate the SSE transport The MCP specification deprecates the SSE transport (SEP-2596). Its API is now `@Deprecated` at `WARNING` level and points to Streamable HTTP: `SseClientTransport`, `HttpClient.mcpSseTransport`, `HttpClient.mcpSse`, `SseServerTransport`, `Route.mcp` and `Application.mcp`. No behavior change. The SDK's own SSE code and the SSE tests suppress the warning where they use the deprecated API, so the suppressions go away together with SSE. README and the module docs mark SSE as deprecated. Closes #1059 --- README.md | 7 ++++-- docs/moduledoc.md | 12 +++++----- .../kotlin/sdk/client/SseTransportTest.kt | 1 + .../ClientDisconnectIntegrationTest.kt | 3 +++ .../integration/TransportIntegrationTest.kt | 11 ++++++--- .../integration/sse/SseAuthenticationTest.kt | 2 ++ .../sdk/integration/sse/SseSubpathTest.kt | 2 ++ kotlin-sdk-client/Module.md | 6 +++-- .../kotlin/sdk/client/KtorClient.kt | 12 ++++++++++ .../kotlin/sdk/client/SseClientTransport.kt | 5 ++++ .../sdk/client/sse/SseClientTransportTest.kt | 2 ++ kotlin-sdk-server/Module.md | 7 ++++-- .../kotlin/sdk/server/KtorServer.kt | 24 ++++++++++++++++--- .../kotlin/sdk/server/SSEServerTransport.kt | 5 ++++ .../sdk/server/DnsRebindingProtectionTest.kt | 2 ++ .../kotlin/sdk/server/KtorExtensionsTest.kt | 6 +++++ .../sdk/server/SseServerTransportTest.kt | 1 + 17 files changed, 90 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index b81aeb7aa..462b2e7ff 100644 --- a/README.md +++ b/README.md @@ -864,6 +864,11 @@ install(CORS) { ### SSE Transport +> [!WARNING] +> The SSE transport is [deprecated](https://modelcontextprotocol.io/specification/2026-07-28/deprecated) in the MCP +> specification and will be removed in a future release. +> Use the [Streamable HTTP transport](#streamable-http-transport) instead. + Server-Sent Events remain available for backwards compatibility with older MCP clients. Two Ktor helpers are provided: - **`Application.mcp { }`** — installs SSE and `ContentNegotiation` with `McpJson` automatically, then registers MCP @@ -912,8 +917,6 @@ embeddedServer(CIO, port = 3000) { --> -Prefer Streamable HTTP for new projects. - ### WebSocket Transport `WebSocketClientTransport` plus the matching server utilities provide full-duplex, low-latency connections—useful when diff --git a/docs/moduledoc.md b/docs/moduledoc.md index 05ce37098..2a49728bb 100644 --- a/docs/moduledoc.md +++ b/docs/moduledoc.md @@ -41,8 +41,8 @@ High-level client for connecting to MCP servers and invoking their features: `serverVersion`, and `serverInstructions`. - Typed operations for tools, prompts, resources, completion, logging, roots, sampling, and elicitation with capability enforcement. -- Transports: `StdioClientTransport`, `SseClientTransport`, `WebSocketClientTransport`, and `StreamableHttpClientTransport`, - plus Ktor client extensions for quick wiring. +- Transports: `StdioClientTransport`, `StreamableHttpClientTransport`, `WebSocketClientTransport`, and the deprecated + `SseClientTransport`, plus Ktor client extensions for quick wiring. Minimal WebSocket client: @@ -66,15 +66,15 @@ Server toolkit for exposing MCP tools, prompts, and resources: - `Server` runtime coordinates sessions, initialization flow, and capability enforcement with registries for tools, prompts, resources, and templates. -- Transports: `StdioServerTransport` for CLI/editor bridges; Ktor extensions (`mcp` for SSE + POST back-channel and - `mcpWebSocket` for WebSocket) for HTTP hosting. +- Transports: `StdioServerTransport` for CLI/editor bridges; Ktor extensions (`mcpStreamableHttp` for Streamable HTTP, + `mcpWebSocket` for WebSocket, and the deprecated `mcp` for SSE) for HTTP hosting. - Built-in notifications for list changes and resource subscriptions when capabilities enable them. -Minimal Ktor SSE server: +Minimal Ktor Streamable HTTP server: ```kotlin fun Application.module() { - mcp { + mcpStreamableHttp { Server( serverInfo = Implementation("sample-server", "1.0.0"), options = ServerOptions(ServerCapabilities( diff --git a/integration-test/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseTransportTest.kt b/integration-test/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseTransportTest.kt index f4a0ae490..c63a8b84d 100644 --- a/integration-test/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseTransportTest.kt +++ b/integration-test/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseTransportTest.kt @@ -18,6 +18,7 @@ import kotlin.test.Test import io.ktor.client.plugins.sse.SSE as ClientSSE import io.ktor.server.sse.SSE as ServerSSE +@Suppress("DEPRECATION") class SseTransportTest { @Test diff --git a/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/ClientDisconnectIntegrationTest.kt b/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/ClientDisconnectIntegrationTest.kt index e84a10ce0..3c2d0215d 100644 --- a/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/ClientDisconnectIntegrationTest.kt +++ b/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/ClientDisconnectIntegrationTest.kt @@ -54,6 +54,7 @@ class ClientDisconnectIntegrationTest { private fun testServer() = Server(Implementation("test-server", "1.0"), ServerOptions(ServerCapabilities())) + @Suppress("DEPRECATION") @Test fun `an SSE session ends when its client disconnects`(): Unit = runBlocking { val server = testServer() @@ -75,6 +76,7 @@ class ClientDisconnectIntegrationTest { } } + @Suppress("DEPRECATION") @Test fun `an SSE handler ends when the server closes its session`(): Unit = runBlocking { val server = testServer() @@ -101,6 +103,7 @@ class ClientDisconnectIntegrationTest { val handlerStarted = CompletableDeferred() val handlerCompleted = CompletableDeferred() withCioServer({ + @Suppress("DEPRECATION") mcp { testServer() } routing { get("/slow") { diff --git a/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/TransportIntegrationTest.kt b/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/TransportIntegrationTest.kt index 41f2b0379..131da9ec5 100644 --- a/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/TransportIntegrationTest.kt +++ b/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/TransportIntegrationTest.kt @@ -10,9 +10,9 @@ import io.ktor.client.plugins.websocket.WebSockets import io.ktor.server.engine.EmbeddedServer import io.ktor.server.engine.embeddedServer import io.modelcontextprotocol.kotlin.sdk.client.Client -import io.modelcontextprotocol.kotlin.sdk.client.SseClientTransport import io.modelcontextprotocol.kotlin.sdk.client.StdioClientTransport import io.modelcontextprotocol.kotlin.sdk.client.StreamableHttpClientTransport +import io.modelcontextprotocol.kotlin.sdk.client.mcpSseTransport import io.modelcontextprotocol.kotlin.sdk.client.mcpWebSocketTransport import io.modelcontextprotocol.kotlin.sdk.server.Server import io.modelcontextprotocol.kotlin.sdk.server.ServerOptions @@ -139,7 +139,10 @@ class TransportIntegrationTest { engine = when (kind) { TransportKind.STDIO -> null - TransportKind.SSE -> embeddedServer(ServerCIO, host = HOST, port = 0) { mcp { server } } + TransportKind.SSE -> embeddedServer(ServerCIO, host = HOST, port = 0) { + @Suppress("DEPRECATION") + mcp { server } + } TransportKind.STREAMABLE_HTTP -> embeddedServer(ServerCIO, host = HOST, port = 0) { mcpStreamableHttp { server } @@ -170,7 +173,9 @@ class TransportIntegrationTest { private suspend fun clientTransport(): Transport = when (kind) { TransportKind.STDIO -> stdioClientTransport() - TransportKind.SSE -> SseClientTransport(httpClient { install(SSE) }, "http://$HOST:${port()}") + TransportKind.SSE -> + @Suppress("DEPRECATION") + httpClient { install(SSE) }.mcpSseTransport("http://$HOST:${port()}") TransportKind.STREAMABLE_HTTP -> StreamableHttpClientTransport(httpClient { install(SSE) }, "http://$HOST:${port()}/mcp") diff --git a/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseAuthenticationTest.kt b/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseAuthenticationTest.kt index 33202147b..83b41c746 100644 --- a/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseAuthenticationTest.kt +++ b/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseAuthenticationTest.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package io.modelcontextprotocol.kotlin.sdk.integration.sse import io.kotest.matchers.shouldBe diff --git a/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseSubpathTest.kt b/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseSubpathTest.kt index b780eec8a..24791f051 100644 --- a/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseSubpathTest.kt +++ b/integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/sse/SseSubpathTest.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package io.modelcontextprotocol.kotlin.sdk.integration.sse import io.kotest.matchers.shouldBe diff --git a/kotlin-sdk-client/Module.md b/kotlin-sdk-client/Module.md index 4e6fd6303..2e372e7ec 100644 --- a/kotlin-sdk-client/Module.md +++ b/kotlin-sdk-client/Module.md @@ -14,7 +14,8 @@ protocol types from `kotlin-sdk-core` and ships with transports for CLI and Ktor - **Capability enforcement**: Methods fail fast if the server does not advertise the needed capability; optional strictness mirrors the protocol options used by the server SDK. - **Transports**: Ready-to-use implementations for STDIO (CLI interoperability), Ktor SSE (`SseClientTransport` with - POST back-channel), Ktor WebSocket, and Streamable HTTP for environments that prefer request/response streaming. + POST back-channel, deprecated), Ktor WebSocket, and Streamable HTTP for environments that prefer request/response + streaming. - **Ktor client integration**: Extension helpers wire MCP over Ktor client engines with minimal setup for SSE, Streamable HTTP, or WebSocket. @@ -50,7 +51,8 @@ println(result.content) ### Ktor-based transports - **SSE** (streaming GET + POST back-channel): create `SseClientTransport(httpClient, url)` (or - `HttpClient.mcpSseTransport(url)`); sessions are keyed by `sessionId` managed by the SDK. + `HttpClient.mcpSseTransport(url)`); sessions are keyed by `sessionId` managed by the SDK. Deprecated; use Streamable + HTTP instead. - **WebSocket**: use `WebSocketClientTransport(httpClient, url)` (or `HttpClient.mcpWebSocketTransport(url)`) to get bidirectional messaging in one connection. - **Streamable HTTP**: `StreamableHttpClientTransport(httpClient, url)` enables MCP over streaming HTTP diff --git a/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/KtorClient.kt b/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/KtorClient.kt index 0c695041e..db1d18af1 100644 --- a/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/KtorClient.kt +++ b/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/KtorClient.kt @@ -15,6 +15,12 @@ import kotlin.time.Duration * @param requestBuilder Optional lambda to configure the HTTP request. * @return A [SseClientTransport] configured for MCP communication. */ +@Deprecated( + "The SSE transport is deprecated in the MCP specification (SEP-2596) " + + "and will be removed in a future release. Use mcpStreamableHttpTransport instead.", + level = DeprecationLevel.WARNING, +) +@Suppress("DEPRECATION") public fun HttpClient.mcpSseTransport( urlString: String? = null, reconnectionTime: Duration? = null, @@ -29,6 +35,12 @@ public fun HttpClient.mcpSseTransport( * @param requestBuilder Optional lambda to configure the HTTP request. * @return A connected [Client] ready for MCP communication. */ +@Deprecated( + "The SSE transport is deprecated in the MCP specification (SEP-2596) " + + "and will be removed in a future release. Use mcpStreamableHttp instead.", + level = DeprecationLevel.WARNING, +) +@Suppress("DEPRECATION") public suspend fun HttpClient.mcpSse( urlString: String? = null, reconnectionTime: Duration? = null, diff --git a/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseClientTransport.kt b/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseClientTransport.kt index 29d1d3b98..cc39f3d5d 100644 --- a/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseClientTransport.kt +++ b/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseClientTransport.kt @@ -41,6 +41,11 @@ import kotlin.time.Duration * Client transport for SSE: this will connect to a server using Server-Sent Events for receiving * messages and make separate POST requests for sending messages. */ +@Deprecated( + "The SSE transport is deprecated in the MCP specification (SEP-2596) " + + "and will be removed in a future release. Use StreamableHttpClientTransport instead.", + level = DeprecationLevel.WARNING, +) @OptIn(ExperimentalAtomicApi::class) public class SseClientTransport( private val client: HttpClient, diff --git a/kotlin-sdk-client/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/sse/SseClientTransportTest.kt b/kotlin-sdk-client/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/sse/SseClientTransportTest.kt index 265b648cb..2a7dc56aa 100644 --- a/kotlin-sdk-client/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/sse/SseClientTransportTest.kt +++ b/kotlin-sdk-client/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/sse/SseClientTransportTest.kt @@ -1,3 +1,5 @@ +@file:Suppress("DEPRECATION") + package io.modelcontextprotocol.kotlin.sdk.client.sse import io.kotest.assertions.throwables.shouldThrow diff --git a/kotlin-sdk-server/Module.md b/kotlin-sdk-server/Module.md index 176a398f3..6ce59f305 100644 --- a/kotlin-sdk-server/Module.md +++ b/kotlin-sdk-server/Module.md @@ -10,8 +10,8 @@ that make it straightforward to expose tools, prompts, and resources to MCP clie 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 `Transport` abstraction from the SDK. +- **Transports**: Ready-to-use transports for STDIO (CLI-style hosting), Ktor Server-Sent Events (SSE, deprecated) with + POST back-channel, and Ktor WebSocket. All share the common `Transport` abstraction from the SDK. - **Ktor integration**: Extension functions (`Route.mcp`, `Route.mcpWebSocket`, and `Application` variants) 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 @@ -58,6 +58,9 @@ server.createSession(transport) ### Hosting with Ktor (SSE) +The SSE transport is deprecated in the MCP specification and will be removed in a future release. Use +`mcpStreamableHttp` instead. + ```kotlin fun Application.module() { mcp { diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt index f2d6cd589..6a357fedc 100644 --- a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt @@ -64,8 +64,13 @@ private val logger = KotlinLogging.logger {} * that creates and returns the [Server] to handle the connection. * @throws IllegalStateException if the [SSE] plugin is not installed. */ +@Deprecated( + "The SSE transport is deprecated in the MCP specification (SEP-2596) " + + "and will be removed in a future release. Use Application.mcpStreamableHttp instead.", + level = DeprecationLevel.WARNING, +) @KtorDsl -@Suppress("LongParameterList") +@Suppress("DEPRECATION", "LongParameterList") public fun Route.mcp( path: String, enableDnsRebindingProtection: Boolean = true, @@ -103,8 +108,13 @@ public fun Route.mcp( * that creates and returns the [Server] to handle the connection. * @throws IllegalStateException if the [SSE] plugin is not installed. */ +@Deprecated( + "The SSE transport is deprecated in the MCP specification (SEP-2596) " + + "and will be removed in a future release. Use Application.mcpStreamableHttp instead.", + level = DeprecationLevel.WARNING, +) @KtorDsl -@Suppress("LongParameterList") +@Suppress("DEPRECATION", "LongParameterList") public fun Route.mcp( enableDnsRebindingProtection: Boolean = true, allowedHosts: List? = null, @@ -162,8 +172,13 @@ public fun Route.mcp( * @param block factory block with access to the [ServerSSESession] * that creates and returns the [Server] to handle the connection. */ +@Deprecated( + "The SSE transport is deprecated in the MCP specification (SEP-2596) " + + "and will be removed in a future release. Use mcpStreamableHttp instead.", + level = DeprecationLevel.WARNING, +) @KtorDsl -@Suppress("LongParameterList") +@Suppress("DEPRECATION", "LongParameterList") public fun Application.mcp( enableDnsRebindingProtection: Boolean = true, allowedHosts: List? = null, @@ -367,6 +382,7 @@ public fun Application.mcpStatelessStreamableHttp( ) } +@Suppress("DEPRECATION") private suspend fun ServerSSESession.mcpSseEndpoint( postEndpoint: String, transportManager: TransportManager, @@ -394,6 +410,7 @@ private suspend fun ServerSSESession.mcpSseEndpoint( } } +@Suppress("DEPRECATION") private fun ServerSSESession.mcpSseTransport( postEndpoint: String, transportManager: TransportManager, @@ -430,6 +447,7 @@ private suspend fun RoutingContext.mcpStatelessStreamableHttpEndpoint( } } +@Suppress("DEPRECATION") private suspend fun RoutingContext.mcpPostEndpoint(transportManager: TransportManager) { val sessionId: String = call.request.queryParameters["sessionId"] ?: run { call.respond(HttpStatusCode.BadRequest, "sessionId query parameter is not provided") diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt index f525ec29e..2d543aa15 100644 --- a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt @@ -31,6 +31,11 @@ internal const val SESSION_ID_PARAM = "sessionId" * @param maxRequestBodySize maximum allowed size, in bytes, of an incoming POST body; larger requests are * rejected with `413 Payload Too Large` without being buffered in full. Defaults to 4 MiB. */ +@Deprecated( + "The SSE transport is deprecated in the MCP specification (SEP-2596) " + + "and will be removed in a future release. Use StreamableHttpServerTransport instead.", + level = DeprecationLevel.WARNING, +) @OptIn(ExperimentalAtomicApi::class) public class SseServerTransport( private val endpoint: String, diff --git a/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/DnsRebindingProtectionTest.kt b/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/DnsRebindingProtectionTest.kt index c3969b54d..a77014487 100644 --- a/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/DnsRebindingProtectionTest.kt +++ b/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/DnsRebindingProtectionTest.kt @@ -202,6 +202,7 @@ class DnsRebindingProtectionTest { ex.message shouldContain "not-a-url" } + @Suppress("DEPRECATION") @Test fun `Route mcp with DNS protection enabled rejects non-localhost`() = testApplication { application { @@ -218,6 +219,7 @@ class DnsRebindingProtectionTest { response.shouldHaveStatus(HttpStatusCode.Forbidden) } + @Suppress("DEPRECATION") @Test fun `Route mcp with DNS protection disabled allows any host`() = testApplication { application { diff --git a/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorExtensionsTest.kt b/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorExtensionsTest.kt index a132341ad..8b04cbaa4 100644 --- a/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorExtensionsTest.kt +++ b/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorExtensionsTest.kt @@ -31,6 +31,7 @@ import kotlin.time.Duration.Companion.seconds class KtorExtensionsTest { + @Suppress("DEPRECATION") @Test fun `Route mcp should throw at registration time if SSE plugin is not installed`() { val exception = shouldThrow { @@ -46,6 +47,7 @@ class KtorExtensionsTest { exception.message shouldContain "install(SSE)" } + @Suppress("DEPRECATION") @Test fun `Route mcp should register SSE and POST endpoints at the given subpath`() = testApplication { application { @@ -60,6 +62,7 @@ class KtorExtensionsTest { client.assertMcpEndpointsAt("/api/mcp") } + @Suppress("DEPRECATION") @Test fun `Route mcp with path parameter should register endpoints at the resolved path`() = testApplication { application { @@ -79,6 +82,7 @@ class KtorExtensionsTest { * Verifies that a closed session stops receiving POSTs and is not retained until the * [Server] itself closes, even while its SSE connection is still open. */ + @Suppress("DEPRECATION") @Test fun `Route mcp stops routing POSTs to a session once it closes`() = testApplication { val server = testServer() @@ -101,6 +105,7 @@ class KtorExtensionsTest { } } + @Suppress("DEPRECATION") @Test fun `Application mcp should install SSE and register endpoints at the root`() = testApplication { application { @@ -110,6 +115,7 @@ class KtorExtensionsTest { client.assertMcpEndpointsAt("/") } + @Suppress("DEPRECATION") @Test fun `Application mcp should reuse an installed SSE plugin`() = testApplication { application { diff --git a/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SseServerTransportTest.kt b/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SseServerTransportTest.kt index b5431fcc2..48098ec96 100644 --- a/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SseServerTransportTest.kt +++ b/kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SseServerTransportTest.kt @@ -16,6 +16,7 @@ import io.ktor.server.testing.testApplication import java.util.concurrent.atomic.AtomicBoolean import kotlin.test.Test +@Suppress("DEPRECATION") class SseServerTransportTest { @Test From 3386639c3ad6760e262c8c4f159e081ee62693ec Mon Sep 17 00:00:00 2001 From: devcrocod Date: Thu, 22 Oct 2026 16:30:31 +0200 Subject: [PATCH 2/3] Updated deprecation warnings for SSE transport to recommend `StreamableHttpServerTransport` instead of `Application.mcpStreamableHttp`, aligning with MCP specification --- .../io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt index 6a357fedc..6b0dfac56 100644 --- a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt @@ -66,7 +66,7 @@ private val logger = KotlinLogging.logger {} */ @Deprecated( "The SSE transport is deprecated in the MCP specification (SEP-2596) " + - "and will be removed in a future release. Use Application.mcpStreamableHttp instead.", + "and will be removed in a future release. Use StreamableHttpServerTransport instead.", level = DeprecationLevel.WARNING, ) @KtorDsl @@ -110,7 +110,7 @@ public fun Route.mcp( */ @Deprecated( "The SSE transport is deprecated in the MCP specification (SEP-2596) " + - "and will be removed in a future release. Use Application.mcpStreamableHttp instead.", + "and will be removed in a future release. Use StreamableHttpServerTransport instead.", level = DeprecationLevel.WARNING, ) @KtorDsl From 6cd06a12817bded9409f7857d36d34198616696d Mon Sep 17 00:00:00 2001 From: devcrocod Date: Tue, 27 Oct 2026 16:35:34 +0100 Subject: [PATCH 3/3] centralize and update SSE deprecation messages --- .../modelcontextprotocol/kotlin/sdk/client/KtorClient.kt | 6 ++---- .../kotlin/sdk/client/SseClientTransport.kt | 6 ++++-- .../modelcontextprotocol/kotlin/sdk/server/KtorServer.kt | 9 +++------ .../kotlin/sdk/server/SSEServerTransport.kt | 6 ++++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/KtorClient.kt b/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/KtorClient.kt index db1d18af1..7af68ad27 100644 --- a/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/KtorClient.kt +++ b/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/KtorClient.kt @@ -16,8 +16,7 @@ import kotlin.time.Duration * @return A [SseClientTransport] configured for MCP communication. */ @Deprecated( - "The SSE transport is deprecated in the MCP specification (SEP-2596) " + - "and will be removed in a future release. Use mcpStreamableHttpTransport instead.", + "$SSE_DEPRECATION_MESSAGE Use mcpStreamableHttpTransport instead.", level = DeprecationLevel.WARNING, ) @Suppress("DEPRECATION") @@ -36,8 +35,7 @@ public fun HttpClient.mcpSseTransport( * @return A connected [Client] ready for MCP communication. */ @Deprecated( - "The SSE transport is deprecated in the MCP specification (SEP-2596) " + - "and will be removed in a future release. Use mcpStreamableHttp instead.", + "$SSE_DEPRECATION_MESSAGE Use mcpStreamableHttp instead.", level = DeprecationLevel.WARNING, ) @Suppress("DEPRECATION") diff --git a/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseClientTransport.kt b/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseClientTransport.kt index cc39f3d5d..0179c1645 100644 --- a/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseClientTransport.kt +++ b/kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/SseClientTransport.kt @@ -37,13 +37,15 @@ import kotlinx.serialization.SerializationException import kotlin.concurrent.atomics.ExperimentalAtomicApi import kotlin.time.Duration +internal const val SSE_DEPRECATION_MESSAGE = + "The SSE transport is deprecated in the MCP specification (SEP-2596) and will be removed in a future release." + /** * Client transport for SSE: this will connect to a server using Server-Sent Events for receiving * messages and make separate POST requests for sending messages. */ @Deprecated( - "The SSE transport is deprecated in the MCP specification (SEP-2596) " + - "and will be removed in a future release. Use StreamableHttpClientTransport instead.", + "$SSE_DEPRECATION_MESSAGE Use StreamableHttpClientTransport instead.", level = DeprecationLevel.WARNING, ) @OptIn(ExperimentalAtomicApi::class) diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt index 6b0dfac56..c405f7bfe 100644 --- a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt @@ -65,8 +65,7 @@ private val logger = KotlinLogging.logger {} * @throws IllegalStateException if the [SSE] plugin is not installed. */ @Deprecated( - "The SSE transport is deprecated in the MCP specification (SEP-2596) " + - "and will be removed in a future release. Use StreamableHttpServerTransport instead.", + "$SSE_DEPRECATION_MESSAGE Use StreamableHttpServerTransport instead.", level = DeprecationLevel.WARNING, ) @KtorDsl @@ -109,8 +108,7 @@ public fun Route.mcp( * @throws IllegalStateException if the [SSE] plugin is not installed. */ @Deprecated( - "The SSE transport is deprecated in the MCP specification (SEP-2596) " + - "and will be removed in a future release. Use StreamableHttpServerTransport instead.", + "$SSE_DEPRECATION_MESSAGE Use StreamableHttpServerTransport instead.", level = DeprecationLevel.WARNING, ) @KtorDsl @@ -173,8 +171,7 @@ public fun Route.mcp( * that creates and returns the [Server] to handle the connection. */ @Deprecated( - "The SSE transport is deprecated in the MCP specification (SEP-2596) " + - "and will be removed in a future release. Use mcpStreamableHttp instead.", + "$SSE_DEPRECATION_MESSAGE Use mcpStreamableHttp instead.", level = DeprecationLevel.WARNING, ) @KtorDsl diff --git a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt index 2d543aa15..c65fe52b7 100644 --- a/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt +++ b/kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt @@ -21,6 +21,9 @@ import kotlin.uuid.Uuid internal const val SESSION_ID_PARAM = "sessionId" +internal const val SSE_DEPRECATION_MESSAGE = + "The SSE transport is deprecated in the MCP specification (SEP-2596) and will be removed in a future release." + /** * Server transport for SSE: this will send messages over an SSE connection and receive messages from HTTP POST requests. * @@ -32,8 +35,7 @@ internal const val SESSION_ID_PARAM = "sessionId" * rejected with `413 Payload Too Large` without being buffered in full. Defaults to 4 MiB. */ @Deprecated( - "The SSE transport is deprecated in the MCP specification (SEP-2596) " + - "and will be removed in a future release. Use StreamableHttpServerTransport instead.", + "$SSE_DEPRECATION_MESSAGE Use StreamableHttpServerTransport instead.", level = DeprecationLevel.WARNING, ) @OptIn(ExperimentalAtomicApi::class)