Add ktlint (#213)
* Add ktlint * Simplify `initClient` function and clean imports in SseIntegrationTest.
This commit is contained in:
parent
b0f075900a
commit
91cf1205af
10 changed files with 800 additions and 758 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,30 +55,42 @@ class ToolSerializationTest {
|
|||
annotations = null,
|
||||
inputSchema = Tool.Input(
|
||||
properties = buildJsonObject {
|
||||
put("location", buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("The city and state, e.g. San Francisco, CA"))
|
||||
})
|
||||
put(
|
||||
"location",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("The city and state, e.g. San Francisco, CA"))
|
||||
},
|
||||
)
|
||||
},
|
||||
required = listOf("location")
|
||||
required = listOf("location"),
|
||||
),
|
||||
outputSchema = Tool.Output(
|
||||
properties = buildJsonObject {
|
||||
put("temperature", buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Temperature in celsius"))
|
||||
})
|
||||
put("conditions", buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("Weather conditions description"))
|
||||
})
|
||||
put("humidity", buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Humidity percentage"))
|
||||
})
|
||||
put(
|
||||
"temperature",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Temperature in celsius"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"conditions",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("Weather conditions description"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"humidity",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Humidity percentage"))
|
||||
},
|
||||
)
|
||||
},
|
||||
required = listOf("temperature", "conditions", "humidity")
|
||||
)
|
||||
required = listOf("temperature", "conditions", "humidity"),
|
||||
),
|
||||
)
|
||||
|
||||
//region Serialize
|
||||
|
|
@ -120,23 +132,35 @@ class ToolSerializationTest {
|
|||
name = "get_weather",
|
||||
outputSchema = Tool.Output(
|
||||
properties = buildJsonObject {
|
||||
put("temperature", buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Temperature in celsius"))
|
||||
})
|
||||
put("conditions", buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("Weather conditions description"))
|
||||
})
|
||||
put("humidity", buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Humidity percentage"))
|
||||
})
|
||||
put(
|
||||
"temperature",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Temperature in celsius"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"conditions",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("Weather conditions description"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"humidity",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Humidity percentage"))
|
||||
},
|
||||
)
|
||||
},
|
||||
required = listOf("temperature", "conditions", "humidity")
|
||||
)
|
||||
required = listOf("temperature", "conditions", "humidity"),
|
||||
),
|
||||
)
|
||||
val expectedJson = createWeatherToolJson(name = "get_weather", outputSchema = """
|
||||
val expectedJson =
|
||||
createWeatherToolJson(
|
||||
name = "get_weather",
|
||||
outputSchema = """
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -155,7 +179,8 @@ class ToolSerializationTest {
|
|||
},
|
||||
"required": ["temperature", "conditions", "humidity"]
|
||||
}
|
||||
""".trimIndent())
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
val actualJson = McpJson.encodeToString(weatherTool)
|
||||
|
||||
|
|
@ -169,21 +194,30 @@ class ToolSerializationTest {
|
|||
title = "Get weather",
|
||||
outputSchema = Tool.Output(
|
||||
properties = buildJsonObject {
|
||||
put("temperature", buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Temperature in celsius"))
|
||||
})
|
||||
put("conditions", buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("Weather conditions description"))
|
||||
})
|
||||
put("humidity", buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Humidity percentage"))
|
||||
})
|
||||
put(
|
||||
"temperature",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Temperature in celsius"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"conditions",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("Weather conditions description"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"humidity",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Humidity percentage"))
|
||||
},
|
||||
)
|
||||
},
|
||||
required = listOf("temperature", "conditions", "humidity")
|
||||
)
|
||||
required = listOf("temperature", "conditions", "humidity"),
|
||||
),
|
||||
)
|
||||
val expectedJson = createWeatherToolJson(
|
||||
name = "get_weather",
|
||||
|
|
@ -207,7 +241,8 @@ class ToolSerializationTest {
|
|||
},
|
||||
"required": ["temperature", "conditions", "humidity"]
|
||||
}
|
||||
""".trimIndent())
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
val actualJson = McpJson.encodeToString(weatherTool)
|
||||
|
||||
|
|
@ -245,7 +280,10 @@ class ToolSerializationTest {
|
|||
|
||||
@Test
|
||||
fun `should deserialize get_weather tool with outputSchema optional property specified`() {
|
||||
val toolJson = createWeatherToolJson(name = "get_weather", outputSchema = """
|
||||
val toolJson =
|
||||
createWeatherToolJson(
|
||||
name = "get_weather",
|
||||
outputSchema = """
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -264,27 +302,37 @@ class ToolSerializationTest {
|
|||
},
|
||||
"required": ["temperature", "conditions", "humidity"]
|
||||
}
|
||||
""".trimIndent())
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
val expectedTool = createWeatherTool(
|
||||
name = "get_weather",
|
||||
outputSchema = Tool.Output(
|
||||
properties = buildJsonObject {
|
||||
put("temperature", buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Temperature in celsius"))
|
||||
})
|
||||
put("conditions", buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("Weather conditions description"))
|
||||
})
|
||||
put("humidity", buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Humidity percentage"))
|
||||
})
|
||||
put(
|
||||
"temperature",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Temperature in celsius"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"conditions",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("Weather conditions description"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"humidity",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Humidity percentage"))
|
||||
},
|
||||
)
|
||||
},
|
||||
required = listOf("temperature", "conditions", "humidity")
|
||||
)
|
||||
required = listOf("temperature", "conditions", "humidity"),
|
||||
),
|
||||
)
|
||||
|
||||
val actualTool = McpJson.decodeFromString<Tool>(toolJson)
|
||||
|
|
@ -316,28 +364,38 @@ class ToolSerializationTest {
|
|||
},
|
||||
"required": ["temperature", "conditions", "humidity"]
|
||||
}
|
||||
""".trimIndent())
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
val expectedTool = createWeatherTool(
|
||||
name = "get_weather",
|
||||
title = "Get weather",
|
||||
outputSchema = Tool.Output(
|
||||
properties = buildJsonObject {
|
||||
put("temperature", buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Temperature in celsius"))
|
||||
})
|
||||
put("conditions", buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("Weather conditions description"))
|
||||
})
|
||||
put("humidity", buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Humidity percentage"))
|
||||
})
|
||||
put(
|
||||
"temperature",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Temperature in celsius"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"conditions",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("Weather conditions description"))
|
||||
},
|
||||
)
|
||||
put(
|
||||
"humidity",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("number"))
|
||||
put("description", JsonPrimitive("Humidity percentage"))
|
||||
},
|
||||
)
|
||||
},
|
||||
required = listOf("temperature", "conditions", "humidity")
|
||||
)
|
||||
required = listOf("temperature", "conditions", "humidity"),
|
||||
),
|
||||
)
|
||||
|
||||
val actualTool = McpJson.decodeFromString<Tool>(toolJson)
|
||||
|
|
@ -352,9 +410,8 @@ class ToolSerializationTest {
|
|||
private fun createWeatherToolJson(
|
||||
name: String = "get_weather",
|
||||
title: String? = null,
|
||||
outputSchema: String? = null
|
||||
outputSchema: String? = null,
|
||||
): String {
|
||||
|
||||
val stringBuilder = StringBuilder()
|
||||
|
||||
stringBuilder
|
||||
|
|
@ -371,7 +428,8 @@ class ToolSerializationTest {
|
|||
.appendLine(",")
|
||||
.append(" \"description\": \"Get the current weather in a given location\"")
|
||||
.appendLine(",")
|
||||
.append("""
|
||||
.append(
|
||||
"""
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -382,46 +440,49 @@ class ToolSerializationTest {
|
|||
},
|
||||
"required": ["location"]
|
||||
}
|
||||
""".trimIndent())
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
if (outputSchema != null) {
|
||||
stringBuilder
|
||||
.appendLine(",")
|
||||
.append("""
|
||||
.append(
|
||||
"""
|
||||
"outputSchema": $outputSchema
|
||||
""".trimIndent())
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
|
||||
stringBuilder
|
||||
.appendLine()
|
||||
.appendLine("}")
|
||||
|
||||
|
||||
return stringBuilder.toString().trimIndent()
|
||||
}
|
||||
|
||||
private fun createWeatherTool(
|
||||
name: String = "get_weather",
|
||||
title: String? = null,
|
||||
outputSchema: Tool.Output? = null
|
||||
): Tool {
|
||||
return Tool(
|
||||
name = name,
|
||||
title = title,
|
||||
description = "Get the current weather in a given location",
|
||||
annotations = null,
|
||||
inputSchema = Tool.Input(
|
||||
properties = buildJsonObject {
|
||||
put("location", buildJsonObject {
|
||||
outputSchema: Tool.Output? = null,
|
||||
): Tool = Tool(
|
||||
name = name,
|
||||
title = title,
|
||||
description = "Get the current weather in a given location",
|
||||
annotations = null,
|
||||
inputSchema = Tool.Input(
|
||||
properties = buildJsonObject {
|
||||
put(
|
||||
"location",
|
||||
buildJsonObject {
|
||||
put("type", JsonPrimitive("string"))
|
||||
put("description", JsonPrimitive("The city and state, e.g. San Francisco, CA"))
|
||||
})
|
||||
},
|
||||
required = listOf("location")
|
||||
),
|
||||
outputSchema = outputSchema
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
required = listOf("location"),
|
||||
),
|
||||
outputSchema = outputSchema,
|
||||
)
|
||||
|
||||
//endregion Private Methods
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ class TypesTest {
|
|||
fun `should validate image content`() {
|
||||
val imageContent = ImageContent(
|
||||
data = "aGVsbG8=", // base64 encoded "hello"
|
||||
mimeType = "image/png"
|
||||
mimeType = "image/png",
|
||||
)
|
||||
|
||||
assertEquals("image", imageContent.type)
|
||||
|
|
@ -116,7 +116,7 @@ class TypesTest {
|
|||
fun `should serialize and deserialize image content correctly`() {
|
||||
val imageContent = ImageContent(
|
||||
data = "dGVzdA==", // base64 encoded "test"
|
||||
mimeType = "image/jpeg"
|
||||
mimeType = "image/jpeg",
|
||||
)
|
||||
|
||||
val json = McpJson.encodeToString<PromptMessageContent>(imageContent)
|
||||
|
|
@ -132,7 +132,7 @@ class TypesTest {
|
|||
fun `should validate audio content`() {
|
||||
val audioContent = AudioContent(
|
||||
data = "aGVsbG8=", // base64 encoded "hello"
|
||||
mimeType = "audio/mp3"
|
||||
mimeType = "audio/mp3",
|
||||
)
|
||||
|
||||
assertEquals("audio", audioContent.type)
|
||||
|
|
@ -144,7 +144,7 @@ class TypesTest {
|
|||
fun `should serialize and deserialize audio content correctly`() {
|
||||
val audioContent = AudioContent(
|
||||
data = "YXVkaW8=", // base64 encoded "audio"
|
||||
mimeType = "audio/wav"
|
||||
mimeType = "audio/wav",
|
||||
)
|
||||
|
||||
val json = McpJson.encodeToString<PromptMessageContent>(audioContent)
|
||||
|
|
@ -161,7 +161,7 @@ class TypesTest {
|
|||
val resource = TextResourceContents(
|
||||
text = "File contents",
|
||||
uri = "file:///path/to/file.txt",
|
||||
mimeType = "text/plain"
|
||||
mimeType = "text/plain",
|
||||
)
|
||||
val embeddedResource = EmbeddedResource(resource = resource)
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ class TypesTest {
|
|||
val resource = BlobResourceContents(
|
||||
blob = "YmluYXJ5ZGF0YQ==",
|
||||
uri = "file:///path/to/binary.dat",
|
||||
mimeType = "application/octet-stream"
|
||||
mimeType = "application/octet-stream",
|
||||
)
|
||||
val embeddedResource = EmbeddedResource(resource = resource)
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ class TypesTest {
|
|||
val textContent = TextContent(text = "Hello, assistant!")
|
||||
val promptMessage = PromptMessage(
|
||||
role = Role.user,
|
||||
content = textContent
|
||||
content = textContent,
|
||||
)
|
||||
|
||||
assertEquals(Role.user, promptMessage.role)
|
||||
|
|
@ -219,12 +219,12 @@ class TypesTest {
|
|||
val resource = TextResourceContents(
|
||||
text = "Primary application entry point",
|
||||
uri = "file:///project/src/main.rs",
|
||||
mimeType = "text/x-rust"
|
||||
mimeType = "text/x-rust",
|
||||
)
|
||||
val embeddedResource = EmbeddedResource(resource = resource)
|
||||
val promptMessage = PromptMessage(
|
||||
role = Role.assistant,
|
||||
content = embeddedResource
|
||||
content = embeddedResource,
|
||||
)
|
||||
|
||||
assertEquals(Role.assistant, promptMessage.role)
|
||||
|
|
@ -240,11 +240,11 @@ class TypesTest {
|
|||
fun `should serialize and deserialize prompt message correctly`() {
|
||||
val imageContent = ImageContent(
|
||||
data = "aW1hZ2VkYXRh", // base64 encoded "imagedata"
|
||||
mimeType = "image/png"
|
||||
mimeType = "image/png",
|
||||
)
|
||||
val promptMessage = PromptMessage(
|
||||
role = Role.assistant,
|
||||
content = imageContent
|
||||
content = imageContent,
|
||||
)
|
||||
|
||||
val json = McpJson.encodeToString(promptMessage)
|
||||
|
|
@ -267,17 +267,17 @@ class TypesTest {
|
|||
resource = TextResourceContents(
|
||||
text = "fn main() {}",
|
||||
uri = "file:///project/src/main.rs",
|
||||
mimeType = "text/x-rust"
|
||||
)
|
||||
mimeType = "text/x-rust",
|
||||
),
|
||||
),
|
||||
EmbeddedResource(
|
||||
resource = TextResourceContents(
|
||||
text = "pub mod lib;",
|
||||
uri = "file:///project/src/lib.rs",
|
||||
mimeType = "text/x-rust"
|
||||
)
|
||||
)
|
||||
)
|
||||
mimeType = "text/x-rust",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
assertEquals(3, toolResult.content.size)
|
||||
|
|
@ -300,9 +300,9 @@ class TypesTest {
|
|||
val toolResult = CallToolResult(
|
||||
content = listOf(
|
||||
TextContent(text = "Operation completed"),
|
||||
ImageContent(data = "aW1hZ2U=", mimeType = "image/png")
|
||||
ImageContent(data = "aW1hZ2U=", mimeType = "image/png"),
|
||||
),
|
||||
isError = false
|
||||
isError = false,
|
||||
)
|
||||
|
||||
val json = McpJson.encodeToString(toolResult)
|
||||
|
|
@ -319,7 +319,7 @@ class TypesTest {
|
|||
fun `should validate CompleteRequest with prompt reference`() {
|
||||
val request = CompleteRequest(
|
||||
ref = PromptReference(name = "greeting"),
|
||||
argument = CompleteRequest.Argument(name = "name", value = "A")
|
||||
argument = CompleteRequest.Argument(name = "name", value = "A"),
|
||||
)
|
||||
|
||||
assertEquals("completion/complete", request.method.value)
|
||||
|
|
@ -334,7 +334,7 @@ class TypesTest {
|
|||
fun `should validate CompleteRequest with resource reference`() {
|
||||
val request = CompleteRequest(
|
||||
ref = ResourceReference(uri = "github://repos/{owner}/{repo}"),
|
||||
argument = CompleteRequest.Argument(name = "repo", value = "t")
|
||||
argument = CompleteRequest.Argument(name = "repo", value = "t"),
|
||||
)
|
||||
|
||||
assertEquals("completion/complete", request.method.value)
|
||||
|
|
@ -349,7 +349,7 @@ class TypesTest {
|
|||
fun `should serialize and deserialize CompleteRequest correctly`() {
|
||||
val request = CompleteRequest(
|
||||
ref = PromptReference(name = "test"),
|
||||
argument = CompleteRequest.Argument(name = "arg", value = "")
|
||||
argument = CompleteRequest.Argument(name = "arg", value = ""),
|
||||
)
|
||||
|
||||
val json = McpJson.encodeToString(request)
|
||||
|
|
@ -367,7 +367,7 @@ class TypesTest {
|
|||
fun `should validate CompleteRequest with complex URIs`() {
|
||||
val request = CompleteRequest(
|
||||
ref = ResourceReference(uri = "api://v1/{tenant}/{resource}/{id}"),
|
||||
argument = CompleteRequest.Argument(name = "id", value = "123")
|
||||
argument = CompleteRequest.Argument(name = "id", value = "123"),
|
||||
)
|
||||
|
||||
val resourceRef = request.ref as ResourceReference
|
||||
|
|
@ -375,4 +375,4 @@ class TypesTest {
|
|||
assertEquals("id", request.argument.name)
|
||||
assertEquals("123", request.argument.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,4 +249,4 @@ class TypesUtilTest {
|
|||
assertEquals(false, result.isError)
|
||||
assertEquals(meta, result._meta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue