Add ktlint (#213)
* Add ktlint * Simplify `initClient` function and clean imports in SseIntegrationTest.
This commit is contained in:
parent
b0f075900a
commit
91cf1205af
40 changed files with 800 additions and 758 deletions
37
.editorconfig
Normal file
37
.editorconfig
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = 120
|
||||
|
||||
[*.json]
|
||||
indent_size = 2
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.{kt,kts}]
|
||||
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
|
||||
|
||||
# Disable wildcard imports entirely
|
||||
ij_kotlin_name_count_to_use_star_import = 2147483647
|
||||
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
|
||||
ij_kotlin_packages_to_use_import_on_demand = unset
|
||||
|
||||
ktlint_code_style = intellij_idea
|
||||
ktlint_experimental = enabled
|
||||
ktlint_standard_filename = disabled
|
||||
ktlint_standard_no-empty-first-line-in-class-body = disabled
|
||||
ktlint_class_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than = 4
|
||||
ktlint_function_signature_rule_force_multiline_when_parameter_count_greater_or_equal_than = 4
|
||||
ktlint_standard_chain-method-continuation = disabled
|
||||
ktlint_ignore_back_ticked_identifier = true
|
||||
ktlint_standard_multiline-expression-wrapping = disabled
|
||||
ktlint_standard_when-entry-bracing = disabled
|
||||
|
||||
[*/build/**/*]
|
||||
ktlint = disabled
|
||||
|
|
@ -1,4 +1,12 @@
|
|||
plugins {
|
||||
alias(libs.plugins.ktlint)
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = "io.modelcontextprotocol"
|
||||
version = "0.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply(plugin = "org.jlleitschuh.gradle.ktlint")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
kotlin = "2.2.0"
|
||||
dokka = "2.0.0"
|
||||
atomicfu = "0.29.0"
|
||||
ktlint = "13.0.0"
|
||||
|
||||
# libraries version
|
||||
serialization = "1.9.0"
|
||||
|
|
@ -57,6 +58,7 @@ ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serializatio
|
|||
|
||||
[plugins]
|
||||
kotlinx-binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binaryCompatibilityValidatorPlugin" }
|
||||
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" }
|
||||
|
||||
# Samples
|
||||
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
|
|
|
|||
|
|
@ -11,9 +11,15 @@ plugins {
|
|||
}
|
||||
|
||||
kotlin {
|
||||
iosArm64(); iosX64(); iosSimulatorArm64()
|
||||
watchosX64(); watchosArm64(); watchosSimulatorArm64()
|
||||
tvosX64(); tvosArm64(); tvosSimulatorArm64()
|
||||
iosArm64()
|
||||
iosX64()
|
||||
iosSimulatorArm64()
|
||||
watchosX64()
|
||||
watchosArm64()
|
||||
watchosSimulatorArm64()
|
||||
tvosX64()
|
||||
tvosArm64()
|
||||
tvosSimulatorArm64()
|
||||
js {
|
||||
browser()
|
||||
nodejs()
|
||||
|
|
@ -40,4 +46,4 @@ kotlin {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,10 +80,8 @@ public class ClientOptions(
|
|||
* @param clientInfo Information about the client implementation (name, version).
|
||||
* @param options Configuration options for this client.
|
||||
*/
|
||||
public open class Client(
|
||||
private val clientInfo: Implementation,
|
||||
options: ClientOptions = ClientOptions(),
|
||||
) : Protocol(options) {
|
||||
public open class Client(private val clientInfo: Implementation, options: ClientOptions = ClientOptions()) :
|
||||
Protocol(options) {
|
||||
|
||||
/**
|
||||
* Retrieves the server's reported capabilities after the initialization process completes.
|
||||
|
|
@ -144,13 +142,13 @@ public open class Client(
|
|||
val message = InitializeRequest(
|
||||
protocolVersion = LATEST_PROTOCOL_VERSION,
|
||||
capabilities = capabilities,
|
||||
clientInfo = clientInfo
|
||||
clientInfo = clientInfo,
|
||||
)
|
||||
val result = request<InitializeResult>(message)
|
||||
|
||||
if (!SUPPORTED_PROTOCOL_VERSIONS.contains(result.protocolVersion)) {
|
||||
throw IllegalStateException(
|
||||
"Server's protocol version is not supported: ${result.protocolVersion}"
|
||||
"Server's protocol version is not supported: ${result.protocolVersion}",
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -165,11 +163,9 @@ public open class Client(
|
|||
}
|
||||
|
||||
throw error
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun assertCapabilityForMethod(method: Method) {
|
||||
when (method) {
|
||||
Method.Defined.LoggingSetLevel -> {
|
||||
|
|
@ -181,7 +177,7 @@ public open class Client(
|
|||
Method.Defined.PromptsGet,
|
||||
Method.Defined.PromptsList,
|
||||
Method.Defined.CompletionComplete,
|
||||
-> {
|
||||
-> {
|
||||
if (serverCapabilities?.prompts == null) {
|
||||
throw IllegalStateException("Server does not support prompts (required for $method)")
|
||||
}
|
||||
|
|
@ -192,20 +188,20 @@ public open class Client(
|
|||
Method.Defined.ResourcesRead,
|
||||
Method.Defined.ResourcesSubscribe,
|
||||
Method.Defined.ResourcesUnsubscribe,
|
||||
-> {
|
||||
-> {
|
||||
val resCaps = serverCapabilities?.resources
|
||||
?: error("Server does not support resources (required for $method)")
|
||||
|
||||
if (method == Method.Defined.ResourcesSubscribe && resCaps.subscribe != true) {
|
||||
throw IllegalStateException(
|
||||
"Server does not support resource subscriptions (required for $method)"
|
||||
"Server does not support resource subscriptions (required for $method)",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Method.Defined.ToolsCall,
|
||||
Method.Defined.ToolsList,
|
||||
-> {
|
||||
-> {
|
||||
if (serverCapabilities?.tools == null) {
|
||||
throw IllegalStateException("Server does not support tools (required for $method)")
|
||||
}
|
||||
|
|
@ -213,7 +209,7 @@ public open class Client(
|
|||
|
||||
Method.Defined.Initialize,
|
||||
Method.Defined.Ping,
|
||||
-> {
|
||||
-> {
|
||||
// No specific capability required
|
||||
}
|
||||
|
||||
|
|
@ -228,7 +224,7 @@ public open class Client(
|
|||
Method.Defined.NotificationsRootsListChanged -> {
|
||||
if (capabilities.roots?.listChanged != true) {
|
||||
throw IllegalStateException(
|
||||
"Client does not support roots list changed notifications (required for $method)"
|
||||
"Client does not support roots list changed notifications (required for $method)",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -236,7 +232,7 @@ public open class Client(
|
|||
Method.Defined.NotificationsInitialized,
|
||||
Method.Defined.NotificationsCancelled,
|
||||
Method.Defined.NotificationsProgress,
|
||||
-> {
|
||||
-> {
|
||||
// Always allowed
|
||||
}
|
||||
|
||||
|
|
@ -251,7 +247,7 @@ public open class Client(
|
|||
Method.Defined.SamplingCreateMessage -> {
|
||||
if (capabilities.sampling == null) {
|
||||
throw IllegalStateException(
|
||||
"Client does not support sampling capability (required for $method)"
|
||||
"Client does not support sampling capability (required for $method)",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -259,7 +255,7 @@ public open class Client(
|
|||
Method.Defined.RootsList -> {
|
||||
if (capabilities.roots == null) {
|
||||
throw IllegalStateException(
|
||||
"Client does not support roots capability (required for $method)"
|
||||
"Client does not support roots capability (required for $method)",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -267,7 +263,7 @@ public open class Client(
|
|||
Method.Defined.ElicitationCreate -> {
|
||||
if (capabilities.elicitation == null) {
|
||||
throw IllegalStateException(
|
||||
"Client does not support elicitation capability (required for $method)"
|
||||
"Client does not support elicitation capability (required for $method)",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -280,16 +276,14 @@ public open class Client(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sends a ping request to the server to check connectivity.
|
||||
*
|
||||
* @param options Optional request options.
|
||||
* @throws IllegalStateException If the server does not support the ping method (unlikely).
|
||||
*/
|
||||
public suspend fun ping(options: RequestOptions? = null): EmptyRequestResult {
|
||||
return request<EmptyRequestResult>(PingRequest(), options)
|
||||
}
|
||||
public suspend fun ping(options: RequestOptions? = null): EmptyRequestResult =
|
||||
request<EmptyRequestResult>(PingRequest(), options)
|
||||
|
||||
/**
|
||||
* Sends a completion request to the server, typically to generate or complete some content.
|
||||
|
|
@ -299,9 +293,8 @@ public open class Client(
|
|||
* @return The completion result returned by the server, or `null` if none.
|
||||
* @throws IllegalStateException If the server does not support prompts or completion.
|
||||
*/
|
||||
public suspend fun complete(params: CompleteRequest, options: RequestOptions? = null): CompleteResult {
|
||||
return request(params, options)
|
||||
}
|
||||
public suspend fun complete(params: CompleteRequest, options: RequestOptions? = null): CompleteResult =
|
||||
request(params, options)
|
||||
|
||||
/**
|
||||
* Sets the logging level on the server.
|
||||
|
|
@ -310,9 +303,8 @@ public open class Client(
|
|||
* @param options Optional request options.
|
||||
* @throws IllegalStateException If the server does not support logging.
|
||||
*/
|
||||
public suspend fun setLoggingLevel(level: LoggingLevel, options: RequestOptions? = null): EmptyRequestResult {
|
||||
return request<EmptyRequestResult>(SetLevelRequest(level), options)
|
||||
}
|
||||
public suspend fun setLoggingLevel(level: LoggingLevel, options: RequestOptions? = null): EmptyRequestResult =
|
||||
request<EmptyRequestResult>(SetLevelRequest(level), options)
|
||||
|
||||
/**
|
||||
* Retrieves a prompt by name from the server.
|
||||
|
|
@ -322,9 +314,8 @@ public open class Client(
|
|||
* @return The requested prompt details, or `null` if not found.
|
||||
* @throws IllegalStateException If the server does not support prompts.
|
||||
*/
|
||||
public suspend fun getPrompt(request: GetPromptRequest, options: RequestOptions? = null): GetPromptResult {
|
||||
return request(request, options)
|
||||
}
|
||||
public suspend fun getPrompt(request: GetPromptRequest, options: RequestOptions? = null): GetPromptResult =
|
||||
request(request, options)
|
||||
|
||||
/**
|
||||
* Lists all available prompts from the server.
|
||||
|
|
@ -337,9 +328,7 @@ public open class Client(
|
|||
public suspend fun listPrompts(
|
||||
request: ListPromptsRequest = ListPromptsRequest(),
|
||||
options: RequestOptions? = null,
|
||||
): ListPromptsResult {
|
||||
return request(request, options)
|
||||
}
|
||||
): ListPromptsResult = request(request, options)
|
||||
|
||||
/**
|
||||
* Lists all available resources from the server.
|
||||
|
|
@ -352,9 +341,7 @@ public open class Client(
|
|||
public suspend fun listResources(
|
||||
request: ListResourcesRequest = ListResourcesRequest(),
|
||||
options: RequestOptions? = null,
|
||||
): ListResourcesResult {
|
||||
return request(request, options)
|
||||
}
|
||||
): ListResourcesResult = request(request, options)
|
||||
|
||||
/**
|
||||
* Lists resource templates available on the server.
|
||||
|
|
@ -367,9 +354,7 @@ public open class Client(
|
|||
public suspend fun listResourceTemplates(
|
||||
request: ListResourceTemplatesRequest,
|
||||
options: RequestOptions? = null,
|
||||
): ListResourceTemplatesResult {
|
||||
return request(request, options)
|
||||
}
|
||||
): ListResourceTemplatesResult = request(request, options)
|
||||
|
||||
/**
|
||||
* Reads a resource from the server by its URI.
|
||||
|
|
@ -382,9 +367,7 @@ public open class Client(
|
|||
public suspend fun readResource(
|
||||
request: ReadResourceRequest,
|
||||
options: RequestOptions? = null,
|
||||
): ReadResourceResult {
|
||||
return request(request, options)
|
||||
}
|
||||
): ReadResourceResult = request(request, options)
|
||||
|
||||
/**
|
||||
* Subscribes to resource changes on the server.
|
||||
|
|
@ -396,9 +379,7 @@ public open class Client(
|
|||
public suspend fun subscribeResource(
|
||||
request: SubscribeRequest,
|
||||
options: RequestOptions? = null,
|
||||
): EmptyRequestResult {
|
||||
return request(request, options)
|
||||
}
|
||||
): EmptyRequestResult = request(request, options)
|
||||
|
||||
/**
|
||||
* Unsubscribes from resource changes on the server.
|
||||
|
|
@ -410,9 +391,7 @@ public open class Client(
|
|||
public suspend fun unsubscribeResource(
|
||||
request: UnsubscribeRequest,
|
||||
options: RequestOptions? = null,
|
||||
): EmptyRequestResult {
|
||||
return request(request, options)
|
||||
}
|
||||
): EmptyRequestResult = request(request, options)
|
||||
|
||||
/**
|
||||
* Calls a tool on the server by name, passing the specified arguments.
|
||||
|
|
@ -443,7 +422,7 @@ public open class Client(
|
|||
|
||||
val request = CallToolRequest(
|
||||
name = name,
|
||||
arguments = JsonObject(jsonArguments)
|
||||
arguments = JsonObject(jsonArguments),
|
||||
)
|
||||
return callTool(request, compatibility, options)
|
||||
}
|
||||
|
|
@ -461,12 +440,10 @@ public open class Client(
|
|||
request: CallToolRequest,
|
||||
compatibility: Boolean = false,
|
||||
options: RequestOptions? = null,
|
||||
): CallToolResultBase? {
|
||||
return if (compatibility) {
|
||||
request<CompatibilityCallToolResult>(request, options)
|
||||
} else {
|
||||
request<CallToolResult>(request, options)
|
||||
}
|
||||
): CallToolResultBase? = if (compatibility) {
|
||||
request<CompatibilityCallToolResult>(request, options)
|
||||
} else {
|
||||
request<CallToolResult>(request, options)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -480,9 +457,7 @@ public open class Client(
|
|||
public suspend fun listTools(
|
||||
request: ListToolsRequest = ListToolsRequest(),
|
||||
options: RequestOptions? = null,
|
||||
): ListToolsResult {
|
||||
return request(request, options)
|
||||
}
|
||||
): ListToolsResult = request(request, options)
|
||||
|
||||
/**
|
||||
* Registers a single root.
|
||||
|
|
@ -491,10 +466,7 @@ public open class Client(
|
|||
* @param name A human-readable name for the root.
|
||||
* @throws IllegalStateException If the client does not support roots.
|
||||
*/
|
||||
public fun addRoot(
|
||||
uri: String,
|
||||
name: String,
|
||||
) {
|
||||
public fun addRoot(uri: String, name: String) {
|
||||
if (capabilities.roots == null) {
|
||||
logger.error { "Failed to add root '$name': Client does not support roots capability" }
|
||||
throw IllegalStateException("Client does not support roots capability.")
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import kotlin.time.Duration
|
|||
*
|
||||
* @param urlString Optional URL of the MCP server.
|
||||
* @param reconnectionTime Optional duration to wait before attempting to reconnect.
|
||||
* @param requestBuilder Optional lambda to configure the HTTP request.
|
||||
* @param requestBuilder Optional lambda to configure the HTTP request.
|
||||
* @return A [SSEClientTransport] configured for MCP communication.
|
||||
*/
|
||||
public fun HttpClient.mcpSseTransport(
|
||||
|
|
@ -38,8 +38,8 @@ public suspend fun HttpClient.mcpSse(
|
|||
val client = Client(
|
||||
Implementation(
|
||||
name = IMPLEMENTATION_NAME,
|
||||
version = LIB_VERSION
|
||||
)
|
||||
version = LIB_VERSION,
|
||||
),
|
||||
)
|
||||
client.connect(transport)
|
||||
return client
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ public class SseClientTransport(
|
|||
}
|
||||
|
||||
"endpoint" -> handleEndpoint(event.data.orEmpty())
|
||||
|
||||
else -> handleMessage(event.data.orEmpty())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,10 +35,7 @@ import kotlin.coroutines.CoroutineContext
|
|||
* @param output The output stream where messages are sent.
|
||||
*/
|
||||
@OptIn(ExperimentalAtomicApi::class)
|
||||
public class StdioClientTransport(
|
||||
private val input: Source,
|
||||
private val output: Sink
|
||||
) : AbstractTransport() {
|
||||
public class StdioClientTransport(private val input: Source, private val output: Sink) : AbstractTransport() {
|
||||
private val logger = KotlinLogging.logger {}
|
||||
private val ioCoroutineContext: CoroutineContext = IODispatcher
|
||||
private val scope by lazy {
|
||||
|
|
|
|||
|
|
@ -50,10 +50,8 @@ private const val MCP_RESUMPTION_TOKEN_HEADER = "Last-Event-ID"
|
|||
/**
|
||||
* Error class for Streamable HTTP transport errors.
|
||||
*/
|
||||
public class StreamableHttpError(
|
||||
public val code: Int? = null,
|
||||
message: String? = null
|
||||
) : Exception("Streamable HTTP error: $message")
|
||||
public class StreamableHttpError(public val code: Int? = null, message: String? = null) :
|
||||
Exception("Streamable HTTP error: $message")
|
||||
|
||||
/**
|
||||
* Client transport for Streamable HTTP: this implements the MCP Streamable HTTP transport specification.
|
||||
|
|
@ -102,15 +100,16 @@ public class StreamableHttpClientTransport(
|
|||
public suspend fun send(
|
||||
message: JSONRPCMessage,
|
||||
resumptionToken: String?,
|
||||
onResumptionToken: ((String) -> Unit)? = null
|
||||
onResumptionToken: ((String) -> Unit)? = null,
|
||||
) {
|
||||
logger.debug { "Client sending message via POST to $url: ${McpJson.encodeToString(message)}" }
|
||||
|
||||
// If we have a resumption token, reconnect the SSE stream with it
|
||||
resumptionToken?.let { token ->
|
||||
startSseSession(
|
||||
resumptionToken = token, onResumptionToken = onResumptionToken,
|
||||
replayMessageId = if (message is JSONRPCRequest) message.id else null
|
||||
resumptionToken = token,
|
||||
onResumptionToken = onResumptionToken,
|
||||
replayMessageId = if (message is JSONRPCRequest) message.id else null,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
|
@ -147,8 +146,9 @@ public class StreamableHttpClientTransport(
|
|||
}
|
||||
|
||||
ContentType.Text.EventStream -> handleInlineSse(
|
||||
response, onResumptionToken = onResumptionToken,
|
||||
replayMessageId = if (message is JSONRPCRequest) message.id else null
|
||||
response,
|
||||
onResumptionToken = onResumptionToken,
|
||||
replayMessageId = if (message is JSONRPCRequest) message.id else null,
|
||||
)
|
||||
|
||||
else -> {
|
||||
|
|
@ -197,7 +197,7 @@ public class StreamableHttpClientTransport(
|
|||
if (!response.status.isSuccess() && response.status != HttpStatusCode.MethodNotAllowed) {
|
||||
val error = StreamableHttpError(
|
||||
response.status.value,
|
||||
"Failed to terminate session: ${response.status.description}"
|
||||
"Failed to terminate session: ${response.status.description}",
|
||||
)
|
||||
logger.error(error) { "Failed to terminate session" }
|
||||
_onError(error)
|
||||
|
|
@ -212,7 +212,7 @@ public class StreamableHttpClientTransport(
|
|||
private suspend fun startSseSession(
|
||||
resumptionToken: String? = null,
|
||||
replayMessageId: RequestId? = null,
|
||||
onResumptionToken: ((String) -> Unit)? = null
|
||||
onResumptionToken: ((String) -> Unit)? = null,
|
||||
) {
|
||||
sseSession?.cancel()
|
||||
sseJob?.cancelAndJoin()
|
||||
|
|
@ -254,7 +254,7 @@ public class StreamableHttpClientTransport(
|
|||
private suspend fun collectSse(
|
||||
session: ClientSSESession,
|
||||
replayMessageId: RequestId?,
|
||||
onResumptionToken: ((String) -> Unit)?
|
||||
onResumptionToken: ((String) -> Unit)?,
|
||||
) {
|
||||
try {
|
||||
session.incoming.collect { event ->
|
||||
|
|
@ -290,7 +290,7 @@ public class StreamableHttpClientTransport(
|
|||
private suspend fun handleInlineSse(
|
||||
response: HttpResponse,
|
||||
replayMessageId: RequestId?,
|
||||
onResumptionToken: ((String) -> Unit)?
|
||||
onResumptionToken: ((String) -> Unit)?,
|
||||
) {
|
||||
logger.trace { "Handling inline SSE from POST response" }
|
||||
val channel = response.bodyAsChannel()
|
||||
|
|
|
|||
|
|
@ -39,4 +39,4 @@ public suspend fun HttpClient.mcpStreamableHttp(
|
|||
val client = Client(Implementation(name = IMPLEMENTATION_NAME, version = LIB_VERSION))
|
||||
client.connect(transport)
|
||||
return client
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ public suspend fun HttpClient.mcpWebSocket(
|
|||
val client = Client(
|
||||
Implementation(
|
||||
name = IMPLEMENTATION_NAME,
|
||||
version = LIB_VERSION
|
||||
)
|
||||
version = LIB_VERSION,
|
||||
),
|
||||
)
|
||||
client.connect(transport)
|
||||
return client
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class StreamableHttpClientTransportTest {
|
|||
val message = JSONRPCRequest(
|
||||
id = RequestId.StringId("test-id"),
|
||||
method = "test",
|
||||
params = buildJsonObject { }
|
||||
params = buildJsonObject { },
|
||||
)
|
||||
|
||||
val transport = createTransport { request ->
|
||||
|
|
@ -61,7 +61,7 @@ class StreamableHttpClientTransportTest {
|
|||
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.Accepted
|
||||
status = HttpStatusCode.Accepted,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -76,26 +76,30 @@ class StreamableHttpClientTransportTest {
|
|||
id = RequestId.StringId("test-id"),
|
||||
method = "initialize",
|
||||
params = buildJsonObject {
|
||||
put("clientInfo", buildJsonObject {
|
||||
put("name", JsonPrimitive("test-client"))
|
||||
put("version", JsonPrimitive("1.0"))
|
||||
})
|
||||
put(
|
||||
"clientInfo",
|
||||
buildJsonObject {
|
||||
put("name", JsonPrimitive("test-client"))
|
||||
put("version", JsonPrimitive("1.0"))
|
||||
},
|
||||
)
|
||||
put("protocolVersion", JsonPrimitive("2025-06-18"))
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
val transport = createTransport { request ->
|
||||
when (val msg = McpJson.decodeFromString<JSONRPCMessage>((request.body as TextContent).text)) {
|
||||
is JSONRPCRequest if msg.method == "initialize" -> respond(
|
||||
content = "", status = HttpStatusCode.OK,
|
||||
headers = headersOf("mcp-session-id", "test-session-id")
|
||||
content = "",
|
||||
status = HttpStatusCode.OK,
|
||||
headers = headersOf("mcp-session-id", "test-session-id"),
|
||||
)
|
||||
|
||||
is JSONRPCNotification if msg.method == "test" -> {
|
||||
assertEquals("test-session-id", request.headers["mcp-session-id"])
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.Accepted
|
||||
status = HttpStatusCode.Accepted,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +126,7 @@ class StreamableHttpClientTransportTest {
|
|||
assertEquals("test-session-id", request.headers["mcp-session-id"])
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.OK
|
||||
status = HttpStatusCode.OK,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +145,7 @@ class StreamableHttpClientTransportTest {
|
|||
assertEquals(HttpMethod.Delete, request.method)
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.MethodNotAllowed
|
||||
status = HttpStatusCode.MethodNotAllowed,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -160,7 +164,7 @@ class StreamableHttpClientTransportTest {
|
|||
assertEquals("2025-06-18", request.headers["mcp-protocol-version"])
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.Accepted
|
||||
status = HttpStatusCode.Accepted,
|
||||
)
|
||||
}
|
||||
transport.protocolVersion = "2025-06-18"
|
||||
|
|
@ -170,7 +174,8 @@ class StreamableHttpClientTransportTest {
|
|||
transport.close()
|
||||
}
|
||||
|
||||
@Ignore //Engine doesn't support SSECapability: https://youtrack.jetbrains.com/issue/KTOR-8177/MockEngine-Add-SSE-support
|
||||
// Engine doesn't support SSECapability: https://youtrack.jetbrains.com/issue/KTOR-8177/MockEngine-Add-SSE-support
|
||||
@Ignore
|
||||
@Test
|
||||
fun testNotificationSchemaE2E() = runTest {
|
||||
val receivedMessages = mutableListOf<JSONRPCMessage>()
|
||||
|
|
@ -182,7 +187,7 @@ class StreamableHttpClientTransportTest {
|
|||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.Accepted,
|
||||
headers = headersOf("mcp-session-id", "notification-test-session")
|
||||
headers = headersOf("mcp-session-id", "notification-test-session"),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +198,9 @@ class StreamableHttpClientTransportTest {
|
|||
// Server sends various notifications
|
||||
appendLine("event: message")
|
||||
appendLine("id: 1")
|
||||
appendLine("""data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":"upload-123","progress":50,"total":100}}""")
|
||||
appendLine(
|
||||
"""data: {"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":"upload-123","progress":50,"total":100}}""",
|
||||
)
|
||||
appendLine()
|
||||
|
||||
appendLine("event: message")
|
||||
|
|
@ -210,8 +217,9 @@ class StreamableHttpClientTransportTest {
|
|||
content = ByteReadChannel(sseContent),
|
||||
status = HttpStatusCode.OK,
|
||||
headers = headersOf(
|
||||
HttpHeaders.ContentType, ContentType.Text.EventStream.toString()
|
||||
)
|
||||
HttpHeaders.ContentType,
|
||||
ContentType.Text.EventStream.toString(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -219,7 +227,7 @@ class StreamableHttpClientTransportTest {
|
|||
HttpMethod.Post -> {
|
||||
respond(
|
||||
content = "",
|
||||
status = HttpStatusCode.Accepted
|
||||
status = HttpStatusCode.Accepted,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -238,11 +246,14 @@ class StreamableHttpClientTransportTest {
|
|||
method = "notifications/initialized",
|
||||
params = buildJsonObject {
|
||||
put("protocolVersion", JsonPrimitive("1.0"))
|
||||
put("capabilities", buildJsonObject {
|
||||
put("tools", JsonPrimitive(true))
|
||||
put("resources", JsonPrimitive(true))
|
||||
})
|
||||
}
|
||||
put(
|
||||
"capabilities",
|
||||
buildJsonObject {
|
||||
put("tools", JsonPrimitive(true))
|
||||
put("resources", JsonPrimitive(true))
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
transport.send(initializedNotification)
|
||||
|
|
@ -274,25 +285,28 @@ class StreamableHttpClientTransportTest {
|
|||
params = buildJsonObject {
|
||||
put("progressToken", JsonPrimitive("download-456"))
|
||||
put("progress", JsonPrimitive(75))
|
||||
}
|
||||
},
|
||||
),
|
||||
JSONRPCNotification(
|
||||
method = "notifications/cancelled",
|
||||
params = buildJsonObject {
|
||||
put("requestId", JsonPrimitive("req-789"))
|
||||
put("reason", JsonPrimitive("user_cancelled"))
|
||||
}
|
||||
},
|
||||
),
|
||||
JSONRPCNotification(
|
||||
method = "notifications/message",
|
||||
params = buildJsonObject {
|
||||
put("level", JsonPrimitive("info"))
|
||||
put("message", JsonPrimitive("Operation completed"))
|
||||
put("data", buildJsonObject {
|
||||
put("duration", JsonPrimitive(1234))
|
||||
})
|
||||
}
|
||||
)
|
||||
put(
|
||||
"data",
|
||||
buildJsonObject {
|
||||
put("duration", JsonPrimitive(1234))
|
||||
},
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
// Send all client notifications
|
||||
|
|
@ -305,7 +319,8 @@ class StreamableHttpClientTransportTest {
|
|||
transport.close()
|
||||
}
|
||||
|
||||
@Ignore // Engine doesn't support SSECapability: https://youtrack.jetbrains.com/issue/KTOR-8177/MockEngine-Add-SSE-support
|
||||
// Engine doesn't support SSECapability: https://youtrack.jetbrains.com/issue/KTOR-8177/MockEngine-Add-SSE-support
|
||||
@Ignore
|
||||
@Test
|
||||
fun testNotificationWithResumptionToken() = runTest {
|
||||
var resumptionTokenReceived: String? = null
|
||||
|
|
@ -320,15 +335,18 @@ class StreamableHttpClientTransportTest {
|
|||
val sseContent = buildString {
|
||||
appendLine("event: message")
|
||||
appendLine("id: resume-100")
|
||||
appendLine("""data: {"jsonrpc":"2.0","method":"notifications/resumed","params":{"fromToken":"${lastEventIdSent}"}}""")
|
||||
appendLine(
|
||||
"""data: {"jsonrpc":"2.0","method":"notifications/resumed","params":{"fromToken":"$lastEventIdSent"}}""",
|
||||
)
|
||||
appendLine()
|
||||
}
|
||||
respond(
|
||||
content = ByteReadChannel(sseContent),
|
||||
status = HttpStatusCode.OK,
|
||||
headers = headersOf(
|
||||
HttpHeaders.ContentType, ContentType.Text.EventStream.toString()
|
||||
)
|
||||
HttpHeaders.ContentType,
|
||||
ContentType.Text.EventStream.toString(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -344,12 +362,12 @@ class StreamableHttpClientTransportTest {
|
|||
method = "notifications/test",
|
||||
params = buildJsonObject {
|
||||
put("data", JsonPrimitive("test-data"))
|
||||
}
|
||||
},
|
||||
),
|
||||
resumptionToken = "previous-token-99",
|
||||
onResumptionToken = { token ->
|
||||
resumptionTokenReceived = token
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// Wait for response
|
||||
|
|
|
|||
|
|
@ -11,9 +11,15 @@ plugins {
|
|||
}
|
||||
|
||||
kotlin {
|
||||
iosArm64(); iosX64(); iosSimulatorArm64()
|
||||
watchosX64(); watchosArm64(); watchosSimulatorArm64()
|
||||
tvosX64(); tvosArm64(); tvosSimulatorArm64()
|
||||
iosArm64()
|
||||
iosX64()
|
||||
iosSimulatorArm64()
|
||||
watchosX64()
|
||||
watchosArm64()
|
||||
watchosSimulatorArm64()
|
||||
tvosX64()
|
||||
tvosArm64()
|
||||
tvosSimulatorArm64()
|
||||
js {
|
||||
browser()
|
||||
nodejs()
|
||||
|
|
@ -42,4 +48,4 @@ kotlin {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ public data class RequestOptions(
|
|||
/**
|
||||
* Extra data given to request handlers.
|
||||
*/
|
||||
public class RequestHandlerExtra()
|
||||
public class RequestHandlerExtra
|
||||
|
||||
internal val COMPLETED = CompletableDeferred(Unit).also { it.complete(Unit) }
|
||||
|
||||
|
|
@ -117,15 +117,20 @@ internal val COMPLETED = CompletableDeferred(Unit).also { it.complete(Unit) }
|
|||
* Implements MCP protocol framing on top of a pluggable transport, including
|
||||
* features like request/response linking, notifications, and progress.
|
||||
*/
|
||||
public abstract class Protocol(
|
||||
@PublishedApi internal val options: ProtocolOptions?,
|
||||
) {
|
||||
public abstract class Protocol(@PublishedApi internal val options: ProtocolOptions?) {
|
||||
public var transport: Transport? = null
|
||||
private set
|
||||
|
||||
private val _requestHandlers: AtomicRef<PersistentMap<String, suspend (JSONRPCRequest, RequestHandlerExtra) -> RequestResult?>> =
|
||||
private val _requestHandlers:
|
||||
AtomicRef<PersistentMap<String, suspend (JSONRPCRequest, RequestHandlerExtra) -> RequestResult?>> =
|
||||
atomic(persistentMapOf())
|
||||
public val requestHandlers: Map<String, suspend (request: JSONRPCRequest, extra: RequestHandlerExtra) -> RequestResult?>
|
||||
public val requestHandlers: Map<
|
||||
String,
|
||||
suspend (
|
||||
request: JSONRPCRequest,
|
||||
extra: RequestHandlerExtra,
|
||||
) -> RequestResult?,
|
||||
>
|
||||
get() = _requestHandlers.value
|
||||
|
||||
private val _notificationHandlers =
|
||||
|
|
@ -133,7 +138,8 @@ public abstract class Protocol(
|
|||
public val notificationHandlers: Map<String, suspend (notification: JSONRPCNotification) -> Unit>
|
||||
get() = _notificationHandlers.value
|
||||
|
||||
private val _responseHandlers: AtomicRef<PersistentMap<RequestId, (response: JSONRPCResponse?, error: Exception?) -> Unit>> =
|
||||
private val _responseHandlers:
|
||||
AtomicRef<PersistentMap<RequestId, (response: JSONRPCResponse?, error: Exception?) -> Unit>> =
|
||||
atomic(persistentMapOf())
|
||||
public val responseHandlers: Map<RequestId, (response: JSONRPCResponse?, error: Exception?) -> Unit>
|
||||
get() = _responseHandlers.value
|
||||
|
|
@ -161,7 +167,9 @@ public abstract class Protocol(
|
|||
/**
|
||||
* A handler to invoke for any request types that do not have their own handler installed.
|
||||
*/
|
||||
public var fallbackRequestHandler: (suspend (request: JSONRPCRequest, extra: RequestHandlerExtra) -> RequestResult?)? =
|
||||
public var fallbackRequestHandler: (
|
||||
suspend (request: JSONRPCRequest, extra: RequestHandlerExtra) -> RequestResult?
|
||||
)? =
|
||||
null
|
||||
|
||||
/**
|
||||
|
|
@ -251,8 +259,8 @@ public abstract class Protocol(
|
|||
error = JSONRPCError(
|
||||
ErrorCode.Defined.MethodNotFound,
|
||||
message = "Server does not support ${request.method}",
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
} catch (cause: Throwable) {
|
||||
LOGGER.error(cause) { "Error sending method not found response" }
|
||||
|
|
@ -268,10 +276,9 @@ public abstract class Protocol(
|
|||
transport?.send(
|
||||
JSONRPCResponse(
|
||||
id = request.id,
|
||||
result = result
|
||||
)
|
||||
result = result,
|
||||
),
|
||||
)
|
||||
|
||||
} catch (cause: Throwable) {
|
||||
LOGGER.error(cause) { "Error handling request: ${request.method} (id: ${request.id})" }
|
||||
|
||||
|
|
@ -281,19 +288,23 @@ public abstract class Protocol(
|
|||
id = request.id,
|
||||
error = JSONRPCError(
|
||||
code = ErrorCode.Defined.InternalError,
|
||||
message = cause.message ?: "Internal error"
|
||||
)
|
||||
)
|
||||
message = cause.message ?: "Internal error",
|
||||
),
|
||||
),
|
||||
)
|
||||
} catch (sendError: Throwable) {
|
||||
LOGGER.error(sendError) { "Failed to send error response for request: ${request.method} (id: ${request.id})" }
|
||||
LOGGER.error(sendError) {
|
||||
"Failed to send error response for request: ${request.method} (id: ${request.id})"
|
||||
}
|
||||
// Optionally implement fallback behavior here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onProgress(notification: ProgressNotification) {
|
||||
LOGGER.trace { "Received progress notification: token=${notification.params.progressToken}, progress=${notification.params.progress}/${notification.params.total}" }
|
||||
LOGGER.trace {
|
||||
"Received progress notification: token=${notification.params.progressToken}, progress=${notification.params.progress}/${notification.params.total}"
|
||||
}
|
||||
val progress = notification.params.progress
|
||||
val total = notification.params.total
|
||||
val message = notification.params.message
|
||||
|
|
@ -378,10 +389,7 @@ public abstract class Protocol(
|
|||
*
|
||||
* Do not use this method to emit notifications! Use notification() instead.
|
||||
*/
|
||||
public suspend fun <T : RequestResult> request(
|
||||
request: Request,
|
||||
options: RequestOptions? = null,
|
||||
): T {
|
||||
public suspend fun <T : RequestResult> request(request: Request, options: RequestOptions? = null): T {
|
||||
LOGGER.trace { "Sending request: ${request.method}" }
|
||||
val result = CompletableDeferred<T>()
|
||||
val transport = this@Protocol.transport ?: throw Error("Not connected")
|
||||
|
|
@ -427,14 +435,14 @@ public abstract class Protocol(
|
|||
|
||||
val notification = CancelledNotification(
|
||||
params = CancelledNotification.Params(
|
||||
requestId = messageId,
|
||||
reason = reason.message ?: "Unknown"
|
||||
)
|
||||
requestId = messageId,
|
||||
reason = reason.message ?: "Unknown",
|
||||
),
|
||||
)
|
||||
|
||||
val serialized = JSONRPCNotification(
|
||||
notification.method.value,
|
||||
params = McpJson.encodeToJsonElement(notification)
|
||||
params = McpJson.encodeToJsonElement(notification),
|
||||
)
|
||||
transport.send(serialized)
|
||||
|
||||
|
|
@ -454,7 +462,7 @@ public abstract class Protocol(
|
|||
McpError(
|
||||
ErrorCode.Defined.RequestTimeout.code,
|
||||
"Request timed out",
|
||||
JsonObject(mutableMapOf("timeout" to JsonPrimitive(timeout.inWholeMilliseconds)))
|
||||
JsonObject(mutableMapOf("timeout" to JsonPrimitive(timeout.inWholeMilliseconds))),
|
||||
),
|
||||
)
|
||||
result.cancel(cause)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ public class ReadBuffer {
|
|||
var lfIndex = buffer.indexOf('\n'.code.toByte())
|
||||
val line = when (lfIndex) {
|
||||
-1L -> return null
|
||||
|
||||
0L -> {
|
||||
buffer.skip(1)
|
||||
return null
|
||||
|
|
@ -44,11 +45,6 @@ public class ReadBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
internal fun deserializeMessage(line: String): JSONRPCMessage {
|
||||
return McpJson.decodeFromString<JSONRPCMessage>(line)
|
||||
}
|
||||
|
||||
public fun serializeMessage(message: JSONRPCMessage): String {
|
||||
return McpJson.encodeToString(message) + "\n"
|
||||
}
|
||||
internal fun deserializeMessage(line: String): JSONRPCMessage = McpJson.decodeFromString<JSONRPCMessage>(line)
|
||||
|
||||
public fun serializeMessage(message: JSONRPCMessage): String = McpJson.encodeToString(message) + "\n"
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public abstract class WebSocketMcpTransport : AbstractTransport() {
|
|||
if (!initialized.compareAndSet(expectedValue = false, newValue = true)) {
|
||||
error(
|
||||
"WebSocketClientTransport already started! " +
|
||||
"If using Client class, note that connect() calls start() automatically.",
|
||||
"If using Client class, note that connect() calls start() automatically.",
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,12 +168,10 @@ public sealed interface Notification {
|
|||
*
|
||||
* @return The JSON-RPC notification representation.
|
||||
*/
|
||||
public fun Notification.toJSON(): JSONRPCNotification {
|
||||
return JSONRPCNotification(
|
||||
method = method.value,
|
||||
params = McpJson.encodeToJsonElement(params),
|
||||
)
|
||||
}
|
||||
public fun Notification.toJSON(): JSONRPCNotification = JSONRPCNotification(
|
||||
method = method.value,
|
||||
params = McpJson.encodeToJsonElement(params),
|
||||
)
|
||||
|
||||
/**
|
||||
* Decodes a JSON-RPC notification into a protocol-specific [Notification].
|
||||
|
|
@ -200,9 +198,9 @@ public sealed interface RequestResult : WithMeta
|
|||
* @param _meta Additional metadata for the response. Defaults to an empty JSON object.
|
||||
*/
|
||||
@Serializable
|
||||
public data class EmptyRequestResult(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ServerResult, ClientResult
|
||||
public data class EmptyRequestResult(override val _meta: JsonObject = EmptyJsonObject) :
|
||||
ServerResult,
|
||||
ClientResult
|
||||
|
||||
/**
|
||||
* A uniquely identifying ID for a request in JSON-RPC.
|
||||
|
|
@ -282,7 +280,6 @@ public sealed interface ErrorCode {
|
|||
MethodNotFound(-32601),
|
||||
InvalidParams(-32602),
|
||||
InternalError(-32603),
|
||||
;
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
|
@ -293,11 +290,8 @@ public sealed interface ErrorCode {
|
|||
* A response to a request that indicates an error occurred.
|
||||
*/
|
||||
@Serializable
|
||||
public data class JSONRPCError(
|
||||
val code: ErrorCode,
|
||||
val message: String,
|
||||
val data: JsonObject = EmptyJsonObject,
|
||||
) : JSONRPCMessage
|
||||
public data class JSONRPCError(val code: ErrorCode, val message: String, val data: JsonObject = EmptyJsonObject) :
|
||||
JSONRPCMessage
|
||||
|
||||
/**
|
||||
* Base interface for notification parameters with optional metadata.
|
||||
|
|
@ -316,9 +310,9 @@ public sealed interface NotificationParams : WithMeta
|
|||
* A client MUST NOT attempt to cancel its `initialize` request.
|
||||
*/
|
||||
@Serializable
|
||||
public data class CancelledNotification(
|
||||
override val params: Params,
|
||||
) : ClientNotification, ServerNotification {
|
||||
public data class CancelledNotification(override val params: Params) :
|
||||
ClientNotification,
|
||||
ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsCancelled
|
||||
|
||||
@Serializable
|
||||
|
|
@ -342,10 +336,7 @@ public data class CancelledNotification(
|
|||
* Describes the name and version of an MCP implementation.
|
||||
*/
|
||||
@Serializable
|
||||
public data class Implementation(
|
||||
val name: String,
|
||||
val version: String,
|
||||
)
|
||||
public data class Implementation(val name: String, val version: String)
|
||||
|
||||
/**
|
||||
* Capabilities a client may support.
|
||||
|
|
@ -383,7 +374,7 @@ public data class ClientCapabilities(
|
|||
/**
|
||||
* Represents a request sent by the client.
|
||||
*/
|
||||
//@Serializable(with = ClientRequestPolymorphicSerializer::class)
|
||||
// @Serializable(with = ClientRequestPolymorphicSerializer::class)
|
||||
public interface ClientRequest : Request
|
||||
|
||||
/**
|
||||
|
|
@ -401,7 +392,7 @@ public sealed interface ClientResult : RequestResult
|
|||
/**
|
||||
* Represents a request sent by the server.
|
||||
*/
|
||||
//@Serializable(with = ServerRequestPolymorphicSerializer::class)
|
||||
// @Serializable(with = ServerRequestPolymorphicSerializer::class)
|
||||
public sealed interface ServerRequest : Request
|
||||
|
||||
/**
|
||||
|
|
@ -423,8 +414,12 @@ public sealed interface ServerResult : RequestResult
|
|||
*/
|
||||
@Serializable
|
||||
public data class UnknownMethodRequestOrNotification(
|
||||
override val method: Method, override val params: NotificationParams? = null,
|
||||
) : ClientNotification, ClientRequest, ServerNotification, ServerRequest
|
||||
override val method: Method,
|
||||
override val params: NotificationParams? = null,
|
||||
) : ClientNotification,
|
||||
ClientRequest,
|
||||
ServerNotification,
|
||||
ServerRequest
|
||||
|
||||
/**
|
||||
* This request is sent from the client to the server when it first connects, asking it to begin initialization.
|
||||
|
|
@ -435,7 +430,8 @@ public data class InitializeRequest(
|
|||
val capabilities: ClientCapabilities,
|
||||
val clientInfo: Implementation,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest, WithMeta {
|
||||
) : ClientRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.Initialize
|
||||
}
|
||||
|
||||
|
|
@ -521,15 +517,11 @@ public data class InitializeResult(
|
|||
* This notification is sent from the client to the server after initialization has finished.
|
||||
*/
|
||||
@Serializable
|
||||
public data class InitializedNotification(
|
||||
override val params: Params = Params(),
|
||||
) : ClientNotification {
|
||||
public data class InitializedNotification(override val params: Params = Params()) : ClientNotification {
|
||||
override val method: Method = Method.Defined.NotificationsInitialized
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
public data class Params(override val _meta: JsonObject = EmptyJsonObject) : NotificationParams
|
||||
}
|
||||
|
||||
/* Ping */
|
||||
|
|
@ -538,7 +530,9 @@ public data class InitializedNotification(
|
|||
* The receiver must promptly respond, or else it may be disconnected.
|
||||
*/
|
||||
@Serializable
|
||||
public class PingRequest : ServerRequest, ClientRequest {
|
||||
public class PingRequest :
|
||||
ServerRequest,
|
||||
ClientRequest {
|
||||
override val method: Method = Method.Defined.Ping
|
||||
}
|
||||
|
||||
|
|
@ -592,9 +586,9 @@ public open class Progress(
|
|||
* An out-of-band notification used to inform the receiver of a progress update for a long-running request.
|
||||
*/
|
||||
@Serializable
|
||||
public data class ProgressNotification(
|
||||
override val params: Params,
|
||||
) : ClientNotification, ServerNotification {
|
||||
public data class ProgressNotification(override val params: Params) :
|
||||
ClientNotification,
|
||||
ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsProgress
|
||||
|
||||
@Serializable
|
||||
|
|
@ -618,7 +612,8 @@ public data class ProgressNotification(
|
|||
*/
|
||||
override val message: String? = null,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams, ProgressBase
|
||||
) : NotificationParams,
|
||||
ProgressBase
|
||||
}
|
||||
|
||||
/* Pagination */
|
||||
|
|
@ -626,7 +621,9 @@ public data class ProgressNotification(
|
|||
* Represents a request supporting pagination.
|
||||
*/
|
||||
@Serializable
|
||||
public sealed interface PaginatedRequest : Request, WithMeta {
|
||||
public sealed interface PaginatedRequest :
|
||||
Request,
|
||||
WithMeta {
|
||||
/**
|
||||
* The cursor indicating the pagination position.
|
||||
*/
|
||||
|
|
@ -669,11 +666,8 @@ public sealed interface ResourceContents {
|
|||
* @property text The text of the item. This must only be set if the item can actually be represented as text (not binary data).
|
||||
*/
|
||||
@Serializable
|
||||
public data class TextResourceContents(
|
||||
val text: String,
|
||||
override val uri: String,
|
||||
override val mimeType: String?,
|
||||
) : ResourceContents
|
||||
public data class TextResourceContents(val text: String, override val uri: String, override val mimeType: String?) :
|
||||
ResourceContents
|
||||
|
||||
/**
|
||||
* Represents the binary contents of a resource encoded as a base64 string.
|
||||
|
|
@ -681,20 +675,14 @@ public data class TextResourceContents(
|
|||
* @property blob A base64-encoded string representing the binary data of the item.
|
||||
*/
|
||||
@Serializable
|
||||
public data class BlobResourceContents(
|
||||
val blob: String,
|
||||
override val uri: String,
|
||||
override val mimeType: String?,
|
||||
) : ResourceContents
|
||||
public data class BlobResourceContents(val blob: String, override val uri: String, override val mimeType: String?) :
|
||||
ResourceContents
|
||||
|
||||
/**
|
||||
* Represents resource contents with unknown or unspecified data.
|
||||
*/
|
||||
@Serializable
|
||||
public data class UnknownResourceContents(
|
||||
override val uri: String,
|
||||
override val mimeType: String?,
|
||||
) : ResourceContents
|
||||
public data class UnknownResourceContents(override val uri: String, override val mimeType: String?) : ResourceContents
|
||||
|
||||
/**
|
||||
* A known resource that the server is capable of reading.
|
||||
|
|
@ -758,8 +746,9 @@ public data class ResourceTemplate(
|
|||
@Serializable
|
||||
public data class ListResourcesRequest(
|
||||
override val cursor: Cursor? = null,
|
||||
override val _meta: JsonObject = EmptyJsonObject
|
||||
) : ClientRequest, PaginatedRequest {
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest,
|
||||
PaginatedRequest {
|
||||
override val method: Method = Method.Defined.ResourcesList
|
||||
}
|
||||
|
||||
|
|
@ -771,7 +760,8 @@ public class ListResourcesResult(
|
|||
public val resources: List<Resource>,
|
||||
override val nextCursor: Cursor? = null,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ServerResult, PaginatedResult
|
||||
) : ServerResult,
|
||||
PaginatedResult
|
||||
|
||||
/**
|
||||
* Sent from the client to request a list of resource templates the server has.
|
||||
|
|
@ -779,8 +769,9 @@ public class ListResourcesResult(
|
|||
@Serializable
|
||||
public data class ListResourceTemplatesRequest(
|
||||
override val cursor: Cursor?,
|
||||
override val _meta: JsonObject = EmptyJsonObject
|
||||
) : ClientRequest, PaginatedRequest {
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest,
|
||||
PaginatedRequest {
|
||||
override val method: Method = Method.Defined.ResourcesTemplatesList
|
||||
}
|
||||
|
||||
|
|
@ -792,16 +783,16 @@ public class ListResourceTemplatesResult(
|
|||
public val resourceTemplates: List<ResourceTemplate>,
|
||||
override val nextCursor: Cursor? = null,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ServerResult, PaginatedResult
|
||||
) : ServerResult,
|
||||
PaginatedResult
|
||||
|
||||
/**
|
||||
* Sent from the client to the server to read a specific resource URI.
|
||||
*/
|
||||
@Serializable
|
||||
public data class ReadResourceRequest(
|
||||
val uri: String,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest, WithMeta {
|
||||
public data class ReadResourceRequest(val uri: String, override val _meta: JsonObject = EmptyJsonObject) :
|
||||
ClientRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.ResourcesRead
|
||||
}
|
||||
|
||||
|
|
@ -820,15 +811,11 @@ public class ReadResourceResult(
|
|||
* Servers may issue this without any previous subscription from the client.
|
||||
*/
|
||||
@Serializable
|
||||
public data class ResourceListChangedNotification(
|
||||
override val params: Params = Params(),
|
||||
) : ServerNotification {
|
||||
public data class ResourceListChangedNotification(override val params: Params = Params()) : ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsResourcesListChanged
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
public data class Params(override val _meta: JsonObject = EmptyJsonObject) : NotificationParams
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -841,7 +828,8 @@ public data class SubscribeRequest(
|
|||
*/
|
||||
val uri: String,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest, WithMeta {
|
||||
) : ClientRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.ResourcesSubscribe
|
||||
}
|
||||
|
||||
|
|
@ -855,7 +843,8 @@ public data class UnsubscribeRequest(
|
|||
*/
|
||||
val uri: String,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest, WithMeta {
|
||||
) : ClientRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.ResourcesUnsubscribe
|
||||
}
|
||||
|
||||
|
|
@ -863,9 +852,7 @@ public data class UnsubscribeRequest(
|
|||
* A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a resources/subscribe request.
|
||||
*/
|
||||
@Serializable
|
||||
public data class ResourceUpdatedNotification(
|
||||
override val params: Params,
|
||||
) : ServerNotification {
|
||||
public data class ResourceUpdatedNotification(override val params: Params) : ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsResourcesUpdated
|
||||
|
||||
@Serializable
|
||||
|
|
@ -923,8 +910,9 @@ public class Prompt(
|
|||
@Serializable
|
||||
public data class ListPromptsRequest(
|
||||
override val cursor: Cursor? = null,
|
||||
override val _meta: JsonObject = EmptyJsonObject
|
||||
) : ClientRequest, PaginatedRequest {
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest,
|
||||
PaginatedRequest {
|
||||
override val method: Method = Method.Defined.PromptsList
|
||||
}
|
||||
|
||||
|
|
@ -936,7 +924,8 @@ public class ListPromptsResult(
|
|||
public val prompts: List<Prompt>,
|
||||
override val nextCursor: Cursor? = null,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ServerResult, PaginatedResult
|
||||
) : ServerResult,
|
||||
PaginatedResult
|
||||
|
||||
/**
|
||||
* Used by the client to get a prompt provided by the server.
|
||||
|
|
@ -954,7 +943,8 @@ public data class GetPromptRequest(
|
|||
val arguments: Map<String, String>?,
|
||||
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest, WithMeta {
|
||||
) : ClientRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.PromptsGet
|
||||
}
|
||||
|
||||
|
|
@ -1033,22 +1023,17 @@ public data class AudioContent(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unknown content provided to or from an LLM.
|
||||
*/
|
||||
@Serializable
|
||||
public data class UnknownContent(
|
||||
override val type: String,
|
||||
) : PromptMessageContentMultimodal
|
||||
public data class UnknownContent(override val type: String) : PromptMessageContentMultimodal
|
||||
|
||||
/**
|
||||
* The contents of a resource, embedded into a prompt or tool call result.
|
||||
*/
|
||||
@Serializable
|
||||
public data class EmbeddedResource(
|
||||
val resource: ResourceContents,
|
||||
) : PromptMessageContent {
|
||||
public data class EmbeddedResource(val resource: ResourceContents) : PromptMessageContent {
|
||||
override val type: String = TYPE
|
||||
|
||||
public companion object {
|
||||
|
|
@ -1062,17 +1047,15 @@ public data class EmbeddedResource(
|
|||
@Suppress("EnumEntryName")
|
||||
@Serializable
|
||||
public enum class Role {
|
||||
user, assistant,
|
||||
user,
|
||||
assistant,
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a message returned as part of a prompt.
|
||||
*/
|
||||
@Serializable
|
||||
public data class PromptMessage(
|
||||
val role: Role,
|
||||
val content: PromptMessageContent,
|
||||
)
|
||||
public data class PromptMessage(val role: Role, val content: PromptMessageContent)
|
||||
|
||||
/**
|
||||
* The server's response to a prompts/get request from the client.
|
||||
|
|
@ -1092,15 +1075,11 @@ public class GetPromptResult(
|
|||
* Servers may issue this without any previous subscription from the client.
|
||||
*/
|
||||
@Serializable
|
||||
public data class PromptListChangedNotification(
|
||||
override val params: Params = Params(),
|
||||
) : ServerNotification {
|
||||
public data class PromptListChangedNotification(override val params: Params = Params()) : ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsPromptsListChanged
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
public data class Params(override val _meta: JsonObject = EmptyJsonObject) : NotificationParams
|
||||
}
|
||||
|
||||
/* Tools */
|
||||
|
|
@ -1155,7 +1134,6 @@ public data class ToolAnnotations(
|
|||
val openWorldHint: Boolean? = true,
|
||||
)
|
||||
|
||||
|
||||
/**
|
||||
* Definition for a tool the client can call.
|
||||
*/
|
||||
|
|
@ -1187,20 +1165,14 @@ public data class Tool(
|
|||
val annotations: ToolAnnotations?,
|
||||
) {
|
||||
@Serializable
|
||||
public data class Input(
|
||||
val properties: JsonObject = EmptyJsonObject,
|
||||
val required: List<String>? = null,
|
||||
) {
|
||||
public data class Input(val properties: JsonObject = EmptyJsonObject, val required: List<String>? = null) {
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@EncodeDefault
|
||||
val type: String = "object"
|
||||
}
|
||||
|
||||
@Serializable
|
||||
public data class Output(
|
||||
val properties: JsonObject = EmptyJsonObject,
|
||||
val required: List<String>? = null,
|
||||
) {
|
||||
public data class Output(val properties: JsonObject = EmptyJsonObject, val required: List<String>? = null) {
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@EncodeDefault
|
||||
val type: String = "object"
|
||||
|
|
@ -1213,8 +1185,9 @@ public data class Tool(
|
|||
@Serializable
|
||||
public data class ListToolsRequest(
|
||||
override val cursor: Cursor? = null,
|
||||
override val _meta: JsonObject = EmptyJsonObject
|
||||
) : ClientRequest, PaginatedRequest {
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest,
|
||||
PaginatedRequest {
|
||||
override val method: Method = Method.Defined.ToolsList
|
||||
}
|
||||
|
||||
|
|
@ -1226,7 +1199,8 @@ public class ListToolsResult(
|
|||
public val tools: List<Tool>,
|
||||
override val nextCursor: Cursor?,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ServerResult, PaginatedResult
|
||||
) : ServerResult,
|
||||
PaginatedResult
|
||||
|
||||
/**
|
||||
* The server's response to a tool call.
|
||||
|
|
@ -1269,7 +1243,8 @@ public data class CallToolRequest(
|
|||
val name: String,
|
||||
val arguments: JsonObject = EmptyJsonObject,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest, WithMeta {
|
||||
) : ClientRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.ToolsCall
|
||||
}
|
||||
|
||||
|
|
@ -1278,15 +1253,11 @@ public data class CallToolRequest(
|
|||
* Servers may issue this without any previous subscription from the client.
|
||||
*/
|
||||
@Serializable
|
||||
public data class ToolListChangedNotification(
|
||||
override val params: Params = Params(),
|
||||
) : ServerNotification {
|
||||
public data class ToolListChangedNotification(override val params: Params = Params()) : ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsToolsListChanged
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
public data class Params(override val _meta: JsonObject = EmptyJsonObject) : NotificationParams
|
||||
}
|
||||
|
||||
/* Logging */
|
||||
|
|
@ -1304,7 +1275,6 @@ public enum class LoggingLevel {
|
|||
critical,
|
||||
alert,
|
||||
emergency,
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1313,9 +1283,7 @@ public enum class LoggingLevel {
|
|||
* the server MAY decide which messages to send automatically.
|
||||
*/
|
||||
@Serializable
|
||||
public data class LoggingMessageNotification(
|
||||
override val params: Params,
|
||||
) : ServerNotification {
|
||||
public data class LoggingMessageNotification(override val params: Params) : ServerNotification {
|
||||
override val method: Method = Method.Defined.NotificationsMessage
|
||||
|
||||
@Serializable
|
||||
|
|
@ -1345,7 +1313,8 @@ public data class LoggingMessageNotification(
|
|||
*/
|
||||
val level: LoggingLevel,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest, WithMeta {
|
||||
) : ClientRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.LoggingSetLevel
|
||||
}
|
||||
}
|
||||
|
|
@ -1404,10 +1373,7 @@ public class ModelPreferences(
|
|||
* Describes a message issued to or received from an LLM API.
|
||||
*/
|
||||
@Serializable
|
||||
public data class SamplingMessage(
|
||||
val role: Role,
|
||||
val content: PromptMessageContentMultimodal,
|
||||
)
|
||||
public data class SamplingMessage(val role: Role, val content: PromptMessageContentMultimodal)
|
||||
|
||||
/**
|
||||
* A request from the server to sample an LLM via the client.
|
||||
|
|
@ -1441,7 +1407,8 @@ public data class CreateMessageRequest(
|
|||
*/
|
||||
val modelPreferences: ModelPreferences?,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ServerRequest, WithMeta {
|
||||
) : ServerRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.SamplingCreateMessage
|
||||
|
||||
@Serializable
|
||||
|
|
@ -1536,9 +1503,7 @@ public data class PromptReference(
|
|||
* Identifies a prompt.
|
||||
*/
|
||||
@Serializable
|
||||
public data class UnknownReference(
|
||||
override val type: String,
|
||||
) : Reference
|
||||
public data class UnknownReference(override val type: String) : Reference
|
||||
|
||||
/**
|
||||
* A request from the client to the server to ask for completion options.
|
||||
|
|
@ -1551,7 +1516,8 @@ public data class CompleteRequest(
|
|||
*/
|
||||
val argument: Argument,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientRequest, WithMeta {
|
||||
) : ClientRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.CompletionComplete
|
||||
|
||||
@Serializable
|
||||
|
|
@ -1571,10 +1537,8 @@ public data class CompleteRequest(
|
|||
* The server's response to a completion/complete request
|
||||
*/
|
||||
@Serializable
|
||||
public data class CompleteResult(
|
||||
val completion: Completion,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ServerResult {
|
||||
public data class CompleteResult(val completion: Completion, override val _meta: JsonObject = EmptyJsonObject) :
|
||||
ServerResult {
|
||||
@Suppress("CanBeParameter")
|
||||
@Serializable
|
||||
public class Completion(
|
||||
|
|
@ -1626,7 +1590,9 @@ public data class Root(
|
|||
* Sent from the server to request a list of root URIs from the client.
|
||||
*/
|
||||
@Serializable
|
||||
public class ListRootsRequest(override val _meta: JsonObject = EmptyJsonObject) : ServerRequest, WithMeta {
|
||||
public class ListRootsRequest(override val _meta: JsonObject = EmptyJsonObject) :
|
||||
ServerRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.RootsList
|
||||
}
|
||||
|
||||
|
|
@ -1634,24 +1600,18 @@ public class ListRootsRequest(override val _meta: JsonObject = EmptyJsonObject)
|
|||
* The client's response to a roots/list request from the server.
|
||||
*/
|
||||
@Serializable
|
||||
public class ListRootsResult(
|
||||
public val roots: List<Root>,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientResult
|
||||
public class ListRootsResult(public val roots: List<Root>, override val _meta: JsonObject = EmptyJsonObject) :
|
||||
ClientResult
|
||||
|
||||
/**
|
||||
* A notification from the client to the server, informing it that the list of roots has changed.
|
||||
*/
|
||||
@Serializable
|
||||
public data class RootsListChangedNotification(
|
||||
override val params: Params = Params(),
|
||||
) : ClientNotification {
|
||||
public data class RootsListChangedNotification(override val params: Params = Params()) : ClientNotification {
|
||||
override val method: Method = Method.Defined.NotificationsRootsListChanged
|
||||
|
||||
@Serializable
|
||||
public data class Params(
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : NotificationParams
|
||||
public data class Params(override val _meta: JsonObject = EmptyJsonObject) : NotificationParams
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1662,7 +1622,8 @@ public data class CreateElicitationRequest(
|
|||
public val message: String,
|
||||
public val requestedSchema: RequestedSchema,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ServerRequest, WithMeta {
|
||||
) : ServerRequest,
|
||||
WithMeta {
|
||||
override val method: Method = Method.Defined.ElicitationCreate
|
||||
|
||||
@Serializable
|
||||
|
|
@ -1705,5 +1666,5 @@ public data class CreateElicitationResult(
|
|||
*/
|
||||
public class McpError(public val code: Int, message: String, public val data: JsonObject = EmptyJsonObject) :
|
||||
Exception() {
|
||||
override val message: String = "MCP error ${code}: $message"
|
||||
override val message: String = "MCP error $code: $message"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,38 +73,35 @@ internal object StopReasonSerializer : KSerializer<StopReason> {
|
|||
}
|
||||
|
||||
internal object ReferencePolymorphicSerializer : JsonContentPolymorphicSerializer<Reference>(Reference::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<Reference> {
|
||||
return when (element.jsonObject.getValue("type").jsonPrimitive.content) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<Reference> =
|
||||
when (element.jsonObject.getValue("type").jsonPrimitive.content) {
|
||||
ResourceReference.TYPE -> ResourceReference.serializer()
|
||||
PromptReference.TYPE -> PromptReference.serializer()
|
||||
else -> UnknownReference.serializer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object PromptMessageContentPolymorphicSerializer :
|
||||
JsonContentPolymorphicSerializer<PromptMessageContent>(PromptMessageContent::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<PromptMessageContent> {
|
||||
return when (element.jsonObject.getValue("type").jsonPrimitive.content) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<PromptMessageContent> =
|
||||
when (element.jsonObject.getValue("type").jsonPrimitive.content) {
|
||||
ImageContent.TYPE -> ImageContent.serializer()
|
||||
TextContent.TYPE -> TextContent.serializer()
|
||||
EmbeddedResource.TYPE -> EmbeddedResource.serializer()
|
||||
AudioContent.TYPE -> AudioContent.serializer()
|
||||
else -> UnknownContent.serializer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object PromptMessageContentMultimodalPolymorphicSerializer :
|
||||
JsonContentPolymorphicSerializer<PromptMessageContentMultimodal>(PromptMessageContentMultimodal::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<PromptMessageContentMultimodal> {
|
||||
return when (element.jsonObject.getValue("type").jsonPrimitive.content) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<PromptMessageContentMultimodal> =
|
||||
when (element.jsonObject.getValue("type").jsonPrimitive.content) {
|
||||
ImageContent.TYPE -> ImageContent.serializer()
|
||||
TextContent.TYPE -> TextContent.serializer()
|
||||
AudioContent.TYPE -> AudioContent.serializer()
|
||||
else -> UnknownContent.serializer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object ResourceContentsPolymorphicSerializer :
|
||||
|
|
@ -125,54 +122,48 @@ internal fun selectRequestDeserializer(method: String): DeserializationStrategy<
|
|||
return CustomRequest.serializer()
|
||||
}
|
||||
|
||||
internal fun selectClientRequestDeserializer(method: String): DeserializationStrategy<ClientRequest>? {
|
||||
return when (method) {
|
||||
Method.Defined.Ping.value -> PingRequest.serializer()
|
||||
Method.Defined.Initialize.value -> InitializeRequest.serializer()
|
||||
Method.Defined.CompletionComplete.value -> CompleteRequest.serializer()
|
||||
Method.Defined.LoggingSetLevel.value -> SetLevelRequest.serializer()
|
||||
Method.Defined.PromptsGet.value -> GetPromptRequest.serializer()
|
||||
Method.Defined.PromptsList.value -> ListPromptsRequest.serializer()
|
||||
Method.Defined.ResourcesList.value -> ListResourcesRequest.serializer()
|
||||
Method.Defined.ResourcesTemplatesList.value -> ListResourceTemplatesRequest.serializer()
|
||||
Method.Defined.ResourcesRead.value -> ReadResourceRequest.serializer()
|
||||
Method.Defined.ResourcesSubscribe.value -> SubscribeRequest.serializer()
|
||||
Method.Defined.ResourcesUnsubscribe.value -> UnsubscribeRequest.serializer()
|
||||
Method.Defined.ToolsCall.value -> CallToolRequest.serializer()
|
||||
Method.Defined.ToolsList.value -> ListToolsRequest.serializer()
|
||||
else -> null
|
||||
}
|
||||
internal fun selectClientRequestDeserializer(method: String): DeserializationStrategy<ClientRequest>? = when (method) {
|
||||
Method.Defined.Ping.value -> PingRequest.serializer()
|
||||
Method.Defined.Initialize.value -> InitializeRequest.serializer()
|
||||
Method.Defined.CompletionComplete.value -> CompleteRequest.serializer()
|
||||
Method.Defined.LoggingSetLevel.value -> SetLevelRequest.serializer()
|
||||
Method.Defined.PromptsGet.value -> GetPromptRequest.serializer()
|
||||
Method.Defined.PromptsList.value -> ListPromptsRequest.serializer()
|
||||
Method.Defined.ResourcesList.value -> ListResourcesRequest.serializer()
|
||||
Method.Defined.ResourcesTemplatesList.value -> ListResourceTemplatesRequest.serializer()
|
||||
Method.Defined.ResourcesRead.value -> ReadResourceRequest.serializer()
|
||||
Method.Defined.ResourcesSubscribe.value -> SubscribeRequest.serializer()
|
||||
Method.Defined.ResourcesUnsubscribe.value -> UnsubscribeRequest.serializer()
|
||||
Method.Defined.ToolsCall.value -> CallToolRequest.serializer()
|
||||
Method.Defined.ToolsList.value -> ListToolsRequest.serializer()
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun selectClientNotificationDeserializer(element: JsonElement): DeserializationStrategy<ClientNotification>? {
|
||||
return when (element.jsonObject.getValue("method").jsonPrimitive.content) {
|
||||
private fun selectClientNotificationDeserializer(element: JsonElement): DeserializationStrategy<ClientNotification>? =
|
||||
when (element.jsonObject.getValue("method").jsonPrimitive.content) {
|
||||
Method.Defined.NotificationsCancelled.value -> CancelledNotification.serializer()
|
||||
Method.Defined.NotificationsProgress.value -> ProgressNotification.serializer()
|
||||
Method.Defined.NotificationsInitialized.value -> InitializedNotification.serializer()
|
||||
Method.Defined.NotificationsRootsListChanged.value -> RootsListChangedNotification.serializer()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
internal object ClientNotificationPolymorphicSerializer :
|
||||
JsonContentPolymorphicSerializer<ClientNotification>(ClientNotification::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ClientNotification> {
|
||||
return selectClientNotificationDeserializer(element)
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ClientNotification> =
|
||||
selectClientNotificationDeserializer(element)
|
||||
?: UnknownMethodRequestOrNotification.serializer()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun selectServerRequestDeserializer(method: String): DeserializationStrategy<ServerRequest>? {
|
||||
return when (method) {
|
||||
Method.Defined.Ping.value -> PingRequest.serializer()
|
||||
Method.Defined.SamplingCreateMessage.value -> CreateMessageRequest.serializer()
|
||||
Method.Defined.RootsList.value -> ListRootsRequest.serializer()
|
||||
else -> null
|
||||
}
|
||||
internal fun selectServerRequestDeserializer(method: String): DeserializationStrategy<ServerRequest>? = when (method) {
|
||||
Method.Defined.Ping.value -> PingRequest.serializer()
|
||||
Method.Defined.SamplingCreateMessage.value -> CreateMessageRequest.serializer()
|
||||
Method.Defined.RootsList.value -> ListRootsRequest.serializer()
|
||||
else -> null
|
||||
}
|
||||
|
||||
internal fun selectServerNotificationDeserializer(element: JsonElement): DeserializationStrategy<ServerNotification>? {
|
||||
return when (element.jsonObject.getValue("method").jsonPrimitive.content) {
|
||||
internal fun selectServerNotificationDeserializer(element: JsonElement): DeserializationStrategy<ServerNotification>? =
|
||||
when (element.jsonObject.getValue("method").jsonPrimitive.content) {
|
||||
Method.Defined.NotificationsCancelled.value -> CancelledNotification.serializer()
|
||||
Method.Defined.NotificationsProgress.value -> ProgressNotification.serializer()
|
||||
Method.Defined.NotificationsMessage.value -> LoggingMessageNotification.serializer()
|
||||
|
|
@ -182,23 +173,20 @@ internal fun selectServerNotificationDeserializer(element: JsonElement): Deseria
|
|||
Method.Defined.NotificationsPromptsListChanged.value -> PromptListChangedNotification.serializer()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
internal object ServerNotificationPolymorphicSerializer :
|
||||
JsonContentPolymorphicSerializer<ServerNotification>(ServerNotification::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ServerNotification> {
|
||||
return selectServerNotificationDeserializer(element)
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ServerNotification> =
|
||||
selectServerNotificationDeserializer(element)
|
||||
?: UnknownMethodRequestOrNotification.serializer()
|
||||
}
|
||||
}
|
||||
|
||||
internal object NotificationPolymorphicSerializer :
|
||||
JsonContentPolymorphicSerializer<Notification>(Notification::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<Notification> {
|
||||
return selectClientNotificationDeserializer(element)
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<Notification> =
|
||||
selectClientNotificationDeserializer(element)
|
||||
?: selectServerNotificationDeserializer(element)
|
||||
?: UnknownMethodRequestOrNotification.serializer()
|
||||
}
|
||||
}
|
||||
|
||||
internal object RequestPolymorphicSerializer :
|
||||
|
|
@ -243,27 +231,24 @@ private fun selectClientResultDeserializer(element: JsonElement): Deserializatio
|
|||
|
||||
internal object ServerResultPolymorphicSerializer :
|
||||
JsonContentPolymorphicSerializer<ServerResult>(ServerResult::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ServerResult> {
|
||||
return selectServerResultDeserializer(element)
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ServerResult> =
|
||||
selectServerResultDeserializer(element)
|
||||
?: EmptyRequestResult.serializer()
|
||||
}
|
||||
}
|
||||
|
||||
internal object ClientResultPolymorphicSerializer :
|
||||
JsonContentPolymorphicSerializer<ClientResult>(ClientResult::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ClientResult> {
|
||||
return selectClientResultDeserializer(element)
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ClientResult> =
|
||||
selectClientResultDeserializer(element)
|
||||
?: EmptyRequestResult.serializer()
|
||||
}
|
||||
}
|
||||
|
||||
internal object RequestResultPolymorphicSerializer :
|
||||
JsonContentPolymorphicSerializer<RequestResult>(RequestResult::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<RequestResult> {
|
||||
return selectClientResultDeserializer(element)
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<RequestResult> =
|
||||
selectClientResultDeserializer(element)
|
||||
?: selectServerResultDeserializer(element)
|
||||
?: EmptyRequestResult.serializer()
|
||||
}
|
||||
}
|
||||
|
||||
internal object JSONRPCMessagePolymorphicSerializer :
|
||||
|
|
@ -315,7 +300,7 @@ public fun CallToolResult.Companion.ok(content: String, meta: JsonObject = Empty
|
|||
CallToolResult(
|
||||
content = listOf(TextContent(content)),
|
||||
isError = false,
|
||||
_meta = meta
|
||||
_meta = meta,
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
@ -325,5 +310,5 @@ public fun CallToolResult.Companion.error(content: String, meta: JsonObject = Em
|
|||
CallToolResult(
|
||||
content = listOf(TextContent(content)),
|
||||
isError = true,
|
||||
_meta = meta
|
||||
)
|
||||
_meta = meta,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class AudioContentSerializationTest {
|
|||
|
||||
private val audioContent = AudioContent(
|
||||
data = "base64-encoded-audio-data",
|
||||
mimeType = "audio/wav"
|
||||
mimeType = "audio/wav",
|
||||
)
|
||||
|
||||
@Test
|
||||
|
|
@ -30,4 +30,4 @@ class AudioContentSerializationTest {
|
|||
val content = McpJson.decodeFromString<AudioContent>(audioContentJson)
|
||||
assertEquals(expected = audioContent, actual = content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,4 +61,3 @@ class CallToolResultUtilsTest {
|
|||
assertEquals(meta, result._meta)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue