Add ktlint (#213)

* Add ktlint

* Simplify `initClient` function and clean imports in SseIntegrationTest.
This commit is contained in:
Pavel Gorgulov 2025-08-05 15:10:44 +02:00 • committed by GitHub
commit 91cf1205af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 800 additions and 758 deletions

View file

@ -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)

View file

@ -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"

View file

@ -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.",
)
}

View file

@ -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"
}

View file

@ -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,
)

View file

@ -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)
}
}
}

View file

@ -61,4 +61,3 @@ class CallToolResultUtilsTest {
assertEquals(meta, result._meta)
}
}

View file

@ -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
}

View file

@ -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)
}
}
}

View file

@ -249,4 +249,4 @@ class TypesUtilTest {
assertEquals(false, result.isError)
assertEquals(meta, result._meta)
}
}
}