Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,8 @@ abstract class KotlinTestBase {

// Server transport reads from client and writes to client
val serverTransport = StdioServerTransport(
inputStream = clientToServerIn.asSource().buffered(),
outputStream = serverToClientOut.asSink().buffered(),
input = clientToServerIn.asSource().buffered(),
output = serverToClientOut.asSink().buffered(),
)
stdioServerTransport = serverTransport

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ abstract class TsTestBase {
// Create Kotlin server and attach stdio transport to the process streams
val server: Server = KotlinServerForTsClient().createMcpServer()
val transport = StdioServerTransport(
inputStream = process.inputStream.asSource().buffered(),
outputStream = process.outputStream.asSink().buffered(),
input = process.inputStream.asSource().buffered(),
output = process.outputStream.asSink().buffered(),
)

// Connect server in a background thread to avoid blocking
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
@@ -1,6 +1,7 @@
package io.modelcontextprotocol.kotlin.sdk.types

import io.modelcontextprotocol.kotlin.sdk.ExperimentalMcpApi
import io.modelcontextprotocol.kotlin.sdk.types.ElicitRequestFormParams
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonObjectBuilder
import kotlinx.serialization.json.buildJsonObject
Expand Down Expand Up @@ -153,7 +154,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 @@ -173,36 +173,6 @@ class ElicitationTest {
params.url shouldBe "https://example.com/auth"
}

// ── Deprecated compat ───────────────────────────────────────────────

@Test
fun `deprecated factory function should create ElicitRequestFormParams`() {
val schema = ElicitRequestParams.RequestedSchema(
properties = mapOf("name" to StringSchema()),
)
val params = ElicitRequestParams(message = "Test", requestedSchema = schema)
params.shouldBeInstanceOf<ElicitRequestFormParams>()
params.message shouldBe "Test"
params.requestedSchema shouldBe schema
}

@Test
fun `deprecated requestedSchema should return schema for form mode`() {
val schema = ElicitRequestParams.RequestedSchema(
properties = mapOf("x" to BooleanSchema()),
)
val request = ElicitRequest(ElicitRequestFormParams(message = "m", requestedSchema = schema))
request.requestedSchema shouldBe schema
}

@Test
fun `deprecated requestedSchema should return null for URL mode`() {
val request = ElicitRequest(
ElicitRequestURLParams(message = "m", elicitationId = "id", url = "https://example.com"),
)
request.requestedSchema.shouldBeNull()
}

// ── ElicitResult ────────────────────────────────────────────────────

@Test
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.ERROR,
)
public constructor(inputStream: Source, outputStream: Sink) : this(
input = inputStream,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,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 @@ -320,12 +320,6 @@ public class StreamableHttpServerTransport(private val configuration: Configurat
* (or apply equivalent middleware) to validate `Host` / `Origin` headers.
*/
public suspend fun handleRequest(session: ServerSSESession?, call: ApplicationCall) {
validateHeaders(call)?.let { reason ->
call.reject(HttpStatusCode.Forbidden, RPCError.ErrorCode.CONNECTION_CLOSED, reason)
_onError(Error(reason))
return
}

when (call.request.httpMethod) {
HttpMethod.Post -> handlePostRequest(session, call)

Expand Down Expand Up @@ -664,34 +658,6 @@ public class StreamableHttpServerTransport(private val configuration: Configurat
}
}

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

configuration.allowedHosts?.let { hosts ->
val hostHeader = call.request.headers[HttpHeaders.Host]
val hostname = hostHeader?.let { extractHostname(it) }?.lowercase()
val allowedHostsLowercase = hosts.map {
extractHostname(it)?.lowercase() ?: it.lowercase()
}

if (hostname == null || hostname !in allowedHostsLowercase) {
return "Invalid Host header: $hostHeader"
}
}

configuration.allowedOrigins?.let { origins ->
val originHeader = call.request.headers[HttpHeaders.Origin]?.lowercase()
val allowedOriginsLowercase = origins.map { it.lowercase() }

// Allow requests without Origin (non-browser clients cannot perform DNS rebinding)
if (originHeader != null && originHeader !in allowedOriginsLowercase) {
return "Invalid Origin header: $originHeader"
}
}

return null
}

private suspend fun flushSse(session: ServerSSESession?) {
try {
session?.send(data = "")
Expand Down
Loading