[WIP] StreamableHttpServerTransport implementation (#449)
# [WIP] StreamableHttpServerTransport implementation - Implement StreamableHttpServerTransport for MCP spec - Support both SSE streaming and direct HTTP JSON responses - Add event store interface for resumability > [!IMPORTANT] > The work is in progress. StreamableHttpServerTransport is not production-ready yet!!! Based on #235 ## How Has This Been Tested? <!-- Have you tested this in a real application? Which scenarios were tested? --> ## Breaking Changes None ## Types of changes - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update ## Checklist - [x] I have read the [MCP Documentation](https://modelcontextprotocol.io) - [x] My code follows the repository's style guidelines - [x] New and existing tests pass locally - [x] I have added appropriate error handling - [x] I have added or updated documentation as needed
This commit is contained in:
parent
2dd4688323
commit
10a0b67204
5 changed files with 1024 additions and 3 deletions
|
|
@ -4,6 +4,7 @@ import io.github.oshai.kotlinlogging.KotlinLogging
|
|||
import io.modelcontextprotocol.kotlin.sdk.types.CancelledNotification
|
||||
import io.modelcontextprotocol.kotlin.sdk.types.CancelledNotificationParams
|
||||
import io.modelcontextprotocol.kotlin.sdk.types.EmptyResult
|
||||
import io.modelcontextprotocol.kotlin.sdk.types.JSONRPCEmptyMessage
|
||||
import io.modelcontextprotocol.kotlin.sdk.types.JSONRPCError
|
||||
import io.modelcontextprotocol.kotlin.sdk.types.JSONRPCNotification
|
||||
import io.modelcontextprotocol.kotlin.sdk.types.JSONRPCRequest
|
||||
|
|
@ -249,6 +250,7 @@ public abstract class Protocol(@PublishedApi internal val options: ProtocolOptio
|
|||
is JSONRPCRequest -> onRequest(message)
|
||||
is JSONRPCNotification -> onNotification(message)
|
||||
is JSONRPCError -> onResponse(null, message)
|
||||
is JSONRPCEmptyMessage -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk.types
|
||||
|
||||
import io.modelcontextprotocol.kotlin.sdk.types.Icon.Theme.Dark
|
||||
import io.modelcontextprotocol.kotlin.sdk.types.Icon.Theme.Light
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
|
|
@ -12,6 +10,8 @@ import kotlinx.serialization.json.JsonObject
|
|||
|
||||
public const val LATEST_PROTOCOL_VERSION: String = "2025-06-18"
|
||||
|
||||
public const val DEFAULT_NEGOTIATED_PROTOCOL_VERSION: String = "2025-03-26"
|
||||
|
||||
public val SUPPORTED_PROTOCOL_VERSIONS: List<String> = listOf(
|
||||
LATEST_PROTOCOL_VERSION,
|
||||
"2025-03-26",
|
||||
|
|
|
|||
|
|
@ -85,6 +85,11 @@ public sealed interface JSONRPCMessage {
|
|||
public val jsonrpc: String
|
||||
}
|
||||
|
||||
@Serializable
|
||||
public data object JSONRPCEmptyMessage : JSONRPCMessage {
|
||||
override val jsonrpc: String = JSONRPC_VERSION
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// JSONRPCRequest
|
||||
// ============================================================================
|
||||
|
|
@ -197,7 +202,7 @@ public data class JSONRPCResponse(val id: RequestId, val result: RequestResult =
|
|||
* @property error Details about the error that occurred, including error code and message.
|
||||
*/
|
||||
@Serializable
|
||||
public data class JSONRPCError(val id: RequestId, val error: RPCError) : JSONRPCMessage {
|
||||
public data class JSONRPCError(val id: RequestId?, val error: RPCError) : JSONRPCMessage {
|
||||
@EncodeDefault
|
||||
override val jsonrpc: String = JSONRPC_VERSION
|
||||
}
|
||||
|
|
|
|||
|
|
@ -384,6 +384,7 @@ internal object JSONRPCMessagePolymorphicSerializer :
|
|||
"result" in jsonObject -> JSONRPCResponse.serializer()
|
||||
"method" in jsonObject && "id" in jsonObject -> JSONRPCRequest.serializer()
|
||||
"method" in jsonObject -> JSONRPCNotification.serializer()
|
||||
jsonObject.isEmpty() || jsonObject.keys == setOf("jsonrpc") -> JSONRPCEmptyMessage.serializer()
|
||||
else -> throw SerializationException("Invalid JSONRPCMessage type: ${jsonObject.keys}")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -430,4 +430,16 @@ class JsonRpcTest {
|
|||
request.method shouldBe "notifications/log"
|
||||
request.params shouldBeSameInstanceAs params
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize JSONRPCEmptyMessage`() {
|
||||
val json = """
|
||||
{
|
||||
"jsonrpc": "2.0"
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
val message = McpJson.decodeFromString<JSONRPCMessage>(json)
|
||||
message shouldBeSameInstanceAs JSONRPCEmptyMessage
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue