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
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,8 @@ val server = Server(

val session = server.createSession(
StdioServerTransport(
inputStream = System.`in`.asSource().buffered(),
outputStream = System.out.asSink().buffered()
input = System.`in`.asSource().buffered(),
output = System.out.asSink().buffered()
)
)

Expand Down Expand Up @@ -561,8 +561,8 @@ val server = Server(

val session = server.createSession(
StdioServerTransport(
inputStream = System.`in`.asSource().buffered(),
outputStream = System.out.asSink().buffered()
input = System.`in`.asSource().buffered(),
output = System.out.asSink().buffered()
)
)

Expand Down Expand Up @@ -620,8 +620,8 @@ val server = Server(

val session = server.createSession(
StdioServerTransport(
inputStream = System.`in`.asSource().buffered(),
outputStream = System.out.asSink().buffered()
input = System.`in`.asSource().buffered(),
output = System.out.asSink().buffered()
)
)

Expand Down Expand Up @@ -713,7 +713,6 @@ import io.modelcontextprotocol.kotlin.sdk.types.Method
import io.modelcontextprotocol.kotlin.sdk.types.Role
import io.modelcontextprotocol.kotlin.sdk.types.TextContent
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.putJsonObject

fun main() {
-->
Expand All @@ -723,7 +722,7 @@ val client = Client(
clientInfo = Implementation("demo-client", "1.0.0"),
options = ClientOptions(
capabilities = ClientCapabilities(
sampling = buildJsonObject { putJsonObject("tools") { } }, // drop tools if you don't support tool use
sampling = ClientCapabilities.Sampling(tools = buildJsonObject { }), // drop tools if you don't support tool use
),
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ public class StreamableHttpClientTransport(
"kotlin.time.Duration.Companion.seconds",
"io.modelcontextprotocol.kotlin.sdk.client.ReconnectionOptions",
),
level = DeprecationLevel.ERROR,
)
public constructor(
client: HttpClient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public fun HttpClient.mcpStreamableHttpTransport(
"mcpStreamableHttpTransport(url, " +
"ReconnectionOptions(initialReconnectionDelay = reconnectionTime ?: 1.seconds), requestBuilder)",
),
level = DeprecationLevel.ERROR,
)
public fun HttpClient.mcpStreamableHttpTransport(
url: String,
Expand Down Expand Up @@ -82,6 +83,7 @@ public suspend fun HttpClient.mcpStreamableHttp(
"mcpStreamableHttp(url, " +
"ReconnectionOptions(initialReconnectionDelay = reconnectionTime ?: 1.seconds), requestBuilder)",
),
level = DeprecationLevel.ERROR,
)
public suspend fun HttpClient.mcpStreamableHttp(
url: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public data class ClientCapabilities(
"experimental = experimental, " +
"extensions = extensions)",
),
level = DeprecationLevel.WARNING,
level = DeprecationLevel.ERROR,
)
public constructor(
sampling: JsonObject?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public class ElicitRequestBuilder @PublishedApi internal constructor() : Request
"Missing required field 'requestedSchema'. Use requestedSchema { properties { ... } }"
}

val params = ElicitRequestParams(message = message, requestedSchema = requestedSchema, meta = meta)
val params = ElicitRequestFormParams(message = message, requestedSchema = requestedSchema, meta = meta)
return ElicitRequest(params)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public data class ElicitRequest(override val params: ElicitRequestParams) : Serv
@Deprecated(
"Use (params as ElicitRequestFormParams).requestedSchema",
ReplaceWith("(params as ElicitRequestFormParams).requestedSchema"),
DeprecationLevel.WARNING,
DeprecationLevel.ERROR,
)
public val requestedSchema: ElicitRequestParams.RequestedSchema?
get() = (params as? ElicitRequestFormParams)?.requestedSchema
Expand Down Expand Up @@ -88,7 +88,7 @@ public sealed interface ElicitRequestParams : RequestParams {
@Deprecated(
"Use ElicitRequestFormParams instead",
ReplaceWith("ElicitRequestFormParams(message, requestedSchema = requestedSchema, meta = meta)"),
DeprecationLevel.WARNING,
DeprecationLevel.ERROR,
)
@Suppress("FunctionName")
public fun ElicitRequestParams(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ class ElicitationTest {
}
}

@Suppress("DEPRECATION")
@Suppress("DEPRECATION_ERROR")
@Test
fun `deprecated requestedSchema should return schema only for form mode`() {
val schema = ElicitRequestParams.RequestedSchema(
Expand Down
4 changes: 1 addition & 3 deletions kotlin-sdk-server/api/kotlin-sdk-server.api
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/server/KtorServerKt {
public static synthetic fun mcp$default (Lio/ktor/server/application/Application;ZLjava/util/List;Ljava/util/List;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static synthetic fun mcp$default (Lio/ktor/server/routing/Route;Ljava/lang/String;ZLjava/util/List;Ljava/util/List;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static synthetic fun mcp$default (Lio/ktor/server/routing/Route;ZLjava/util/List;Ljava/util/List;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun mcpStatelessStreamableHttp (Lio/ktor/server/application/Application;Ljava/lang/String;ZLjava/util/List;Ljava/util/List;Lio/modelcontextprotocol/kotlin/sdk/server/EventStore;Lkotlin/jvm/functions/Function1;)V
public static final fun mcpStatelessStreamableHttp (Lio/ktor/server/application/Application;Ljava/lang/String;ZLjava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun mcpStatelessStreamableHttp$default (Lio/ktor/server/application/Application;Ljava/lang/String;ZLjava/util/List;Ljava/util/List;Lio/modelcontextprotocol/kotlin/sdk/server/EventStore;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static synthetic fun mcpStatelessStreamableHttp$default (Lio/ktor/server/application/Application;Ljava/lang/String;ZLjava/util/List;Ljava/util/List;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun mcpStreamableHttp-u4uj9nY (Lio/ktor/server/application/Application;Ljava/lang/String;ZLjava/util/List;Ljava/util/List;Lio/modelcontextprotocol/kotlin/sdk/server/EventStore;Lkotlin/jvm/functions/Function1;JILkotlin/jvm/functions/Function1;)V
public static synthetic fun mcpStreamableHttp-u4uj9nY$default (Lio/ktor/server/application/Application;Ljava/lang/String;ZLjava/util/List;Ljava/util/List;Lio/modelcontextprotocol/kotlin/sdk/server/EventStore;Lkotlin/jvm/functions/Function1;JILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
Expand Down Expand Up @@ -222,7 +220,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/server/SseServerTransport
}

public final class io/modelcontextprotocol/kotlin/sdk/server/StdioServerTransport : io/modelcontextprotocol/kotlin/sdk/shared/AbstractTransport {
public fun <init> (Lkotlinx/io/Source;Lkotlinx/io/Sink;)V
public synthetic fun <init> (Lkotlinx/io/Source;Lkotlinx/io/Sink;)V
public fun <init> (Lkotlinx/io/Source;Lkotlinx/io/Sink;Lkotlin/jvm/functions/Function1;)V
public synthetic fun <init> (Lkotlinx/io/Source;Lkotlinx/io/Sink;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun close (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Expand Down
1 change: 0 additions & 1 deletion kotlin-sdk-server/api/kotlin-sdk-server.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ final val io.modelcontextprotocol.kotlin.sdk.server/DnsRebindingProtection // io
final fun <get-DnsRebindingProtection>(): io.ktor.server.application/RouteScopedPlugin<io.modelcontextprotocol.kotlin.sdk.server/DnsRebindingProtectionConfig> // io.modelcontextprotocol.kotlin.sdk.server/DnsRebindingProtection.<get-DnsRebindingProtection>|<get-DnsRebindingProtection>(){}[0]

final fun (io.ktor.server.application/Application).io.modelcontextprotocol.kotlin.sdk.server/mcp(kotlin/Boolean = ..., kotlin.collections/List<kotlin/String>? = ..., kotlin.collections/List<kotlin/String>? = ..., kotlin/Long = ..., kotlin/Function1<io.ktor.server.sse/ServerSSESession, io.modelcontextprotocol.kotlin.sdk.server/Server>) // io.modelcontextprotocol.kotlin.sdk.server/mcp|mcp@io.ktor.server.application.Application(kotlin.Boolean;kotlin.collections.List<kotlin.String>?;kotlin.collections.List<kotlin.String>?;kotlin.Long;kotlin.Function1<io.ktor.server.sse.ServerSSESession,io.modelcontextprotocol.kotlin.sdk.server.Server>){}[0]
final fun (io.ktor.server.application/Application).io.modelcontextprotocol.kotlin.sdk.server/mcpStatelessStreamableHttp(kotlin/String = ..., kotlin/Boolean = ..., kotlin.collections/List<kotlin/String>? = ..., kotlin.collections/List<kotlin/String>? = ..., io.modelcontextprotocol.kotlin.sdk.server/EventStore?, kotlin/Function1<io.ktor.server.routing/RoutingContext, io.modelcontextprotocol.kotlin.sdk.server/Server>) // io.modelcontextprotocol.kotlin.sdk.server/mcpStatelessStreamableHttp|mcpStatelessStreamableHttp@io.ktor.server.application.Application(kotlin.String;kotlin.Boolean;kotlin.collections.List<kotlin.String>?;kotlin.collections.List<kotlin.String>?;io.modelcontextprotocol.kotlin.sdk.server.EventStore?;kotlin.Function1<io.ktor.server.routing.RoutingContext,io.modelcontextprotocol.kotlin.sdk.server.Server>){}[0]
final fun (io.ktor.server.application/Application).io.modelcontextprotocol.kotlin.sdk.server/mcpStatelessStreamableHttp(kotlin/String = ..., kotlin/Boolean = ..., kotlin.collections/List<kotlin/String>? = ..., kotlin.collections/List<kotlin/String>? = ..., kotlin/Function1<io.ktor.server.routing/RoutingContext, io.modelcontextprotocol.kotlin.sdk.server/Server>) // io.modelcontextprotocol.kotlin.sdk.server/mcpStatelessStreamableHttp|mcpStatelessStreamableHttp@io.ktor.server.application.Application(kotlin.String;kotlin.Boolean;kotlin.collections.List<kotlin.String>?;kotlin.collections.List<kotlin.String>?;kotlin.Function1<io.ktor.server.routing.RoutingContext,io.modelcontextprotocol.kotlin.sdk.server.Server>){}[0]
final fun (io.ktor.server.application/Application).io.modelcontextprotocol.kotlin.sdk.server/mcpStreamableHttp(kotlin/String = ..., kotlin/Boolean = ..., kotlin.collections/List<kotlin/String>? = ..., kotlin.collections/List<kotlin/String>? = ..., io.modelcontextprotocol.kotlin.sdk.server/EventStore? = ..., kotlin/Function1<io.ktor.server.sse/Heartbeat, kotlin/Unit>? = ..., kotlin.time/Duration = ..., kotlin/Int = ..., kotlin/Function1<io.ktor.server.routing/RoutingContext, io.modelcontextprotocol.kotlin.sdk.server/Server>) // io.modelcontextprotocol.kotlin.sdk.server/mcpStreamableHttp|mcpStreamableHttp@io.ktor.server.application.Application(kotlin.String;kotlin.Boolean;kotlin.collections.List<kotlin.String>?;kotlin.collections.List<kotlin.String>?;io.modelcontextprotocol.kotlin.sdk.server.EventStore?;kotlin.Function1<io.ktor.server.sse.Heartbeat,kotlin.Unit>?;kotlin.time.Duration;kotlin.Int;kotlin.Function1<io.ktor.server.routing.RoutingContext,io.modelcontextprotocol.kotlin.sdk.server.Server>){}[0]
final fun (io.ktor.server.application/Application).io.modelcontextprotocol.kotlin.sdk.server/mcpWebSocket(kotlin/Function0<io.modelcontextprotocol.kotlin.sdk.server/Server>) // io.modelcontextprotocol.kotlin.sdk.server/mcpWebSocket|mcpWebSocket@io.ktor.server.application.Application(kotlin.Function0<io.modelcontextprotocol.kotlin.sdk.server.Server>){}[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,36 +367,6 @@ public fun Application.mcpStatelessStreamableHttp(
)
}

/**
* Retained only so that existing call sites get a migration hint instead of an unresolved parameter name.
*
* @param eventStore never consulted by a stateless endpoint. Resumption is driven by a `GET` carrying
* `Last-Event-ID`, and this endpoint answers `GET` with `405 Method Not Allowed`, so no stream
* exists to store events on or replay them to. Use [mcpStreamableHttp] when you need resumability.
*/
@Deprecated(
"Use mcpStatelessStreamableHttp without eventStore.",
ReplaceWith("mcpStatelessStreamableHttp(path, enableDnsRebindingProtection, allowedHosts, allowedOrigins, block)"),
DeprecationLevel.ERROR,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Problem: the eventStore overload goes straight from ERROR to deleted, so the JVM method and the klib symbol disappear in a single release. StdioServerTransport(inputStream, outputStream) in this same PR is deliberately parked at HIDDEN for exactly that reason; this one skips that step.

Failure scenario: an app depends on a library compiled against 0.14.0 that calls mcpStatelessStreamableHttp(path, …, eventStore = store, block). The app bumps kotlin-sdk-server to the next release without recompiling that library. Nothing fails at compile time — route registration throws NoSuchMethodError the first time it runs.

Suggested fix: keep the declaration one more release with level = DeprecationLevel.HIDDEN and the body unchanged (it already delegates to the supported overload). That removes it from source resolution while leaving the method and klib symbol in place, then delete it in the release after.

)
@Suppress("UnusedParameter")
public fun Application.mcpStatelessStreamableHttp(
path: String = "/mcp",
enableDnsRebindingProtection: Boolean = true,
allowedHosts: List<String>? = null,
allowedOrigins: List<String>? = null,
eventStore: EventStore?,
block: RoutingContext.() -> Server,
) {
mcpStatelessStreamableHttp(
path = path,
enableDnsRebindingProtection = enableDnsRebindingProtection,
allowedHosts = allowedHosts,
allowedOrigins = allowedOrigins,
block = block,
)
}

private suspend fun ServerSSESession.mcpSseEndpoint(
postEndpoint: String,
transportManager: TransportManager<SseServerTransport>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public class StdioServerTransport private constructor(
@Deprecated(
message = "Use StdioServerTransport(input, output) { ... } instead.",
replaceWith = ReplaceWith("StdioServerTransport(input = inputStream, output = outputStream)"),
level = DeprecationLevel.WARNING,
level = DeprecationLevel.HIDDEN,
)
public constructor(inputStream: Source, outputStream: Sink) : this(
input = inputStream,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ private sealed interface PostRefusal {
@OptIn(ExperimentalUuidApi::class, ExperimentalAtomicApi::class)
public class StreamableHttpServerTransport(private val configuration: Configuration) : AbstractTransport() {

@Deprecated("Use default constructor with explicit Configuration()")
@Deprecated("Use default constructor with explicit Configuration()", level = DeprecationLevel.ERROR)
public constructor() : this(configuration = Configuration())

/**
Expand All @@ -120,6 +120,7 @@ public class StreamableHttpServerTransport(private val configuration: Configurat
replaceWith = ReplaceWith(
"StreamableHttpServerTransport(Configuration(enableJsonResponse = enableJsonResponse, enableDnsRebindingProtection = enableDnsRebindingProtection, allowedHosts = allowedHosts, allowedOrigins = allowedOrigins, eventStore = eventStore, retryIntervalMillis = retryIntervalMillis))",
),
level = DeprecationLevel.ERROR,
)
public constructor(
enableJsonResponse: Boolean = false,
Expand Down Expand Up @@ -155,17 +156,17 @@ public class StreamableHttpServerTransport(private val configuration: Configurat
public val enableJsonResponse: Boolean = false,
@Deprecated(
message = "Use install(DnsRebindingProtection) on your Ktor route instead",
level = DeprecationLevel.WARNING,
level = DeprecationLevel.ERROR,
)
public val enableDnsRebindingProtection: Boolean = false,
@Deprecated(
message = "Use install(DnsRebindingProtection) on your Ktor route instead",
level = DeprecationLevel.WARNING,
level = DeprecationLevel.ERROR,
)
public val allowedHosts: List<String>? = null,
@Deprecated(
message = "Use install(DnsRebindingProtection) on your Ktor route instead",
level = DeprecationLevel.WARNING,
level = DeprecationLevel.ERROR,
)
public val allowedOrigins: List<String>? = null,
public val eventStore: EventStore? = null,
Expand Down Expand Up @@ -821,6 +822,7 @@ public class StreamableHttpServerTransport(private val configuration: Configurat
}
}

@Suppress("DEPRECATION_ERROR")
private fun validateHeaders(call: ApplicationCall): String? {
if (!configuration.enableDnsRebindingProtection) return null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ private fun Application.installCors() {
fun runMcpServerUsingStdio() {
val server = configureServer()
val transport = StdioServerTransport(
inputStream = System.`in`.asSource().buffered(),
outputStream = System.out.asSink().buffered(),
input = System.`in`.asSource().buffered(),
output = System.out.asSink().buffered(),
)

runBlocking {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ fun runMcpServer() {
server.registerTools(httpClient)

val transport = StdioServerTransport(
System.`in`.asInput(),
System.out.asSink().buffered(),
input = System.`in`.asInput(),
output = System.out.asSink().buffered(),
)

runBlocking {
Expand Down
Loading