Add missing title, size and annotation attributes on Resource/ResourceTemplate and other types (#219)

* Add missing resource and resource template title and size

* Add missing annotations

* Add serialization test for Annotations

* Dump APIs
This commit is contained in:
Didier Villevalois 2025-08-19 13:45:17 +02:00 • committed by GitHub
commit ad8205297e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 168 additions and 20 deletions

View file

@ -17,6 +17,8 @@ import kotlin.concurrent.atomics.AtomicLong
import kotlin.concurrent.atomics.ExperimentalAtomicApi
import kotlin.concurrent.atomics.incrementAndFetch
import kotlin.jvm.JvmInline
import kotlin.time.ExperimentalTime
import kotlin.time.Instant
public const val LATEST_PROTOCOL_VERSION: String = "2025-03-26"
@ -710,6 +712,18 @@ public data class Resource(
* The MIME type of this resource, if known.
*/
val mimeType: String?,
/**
* The optional human-readable name of this resource for display purposes.
*/
val title: String? = null,
/**
* The optional size of this resource in bytes, if known.
*/
val size: Long? = null,
/**
* Optional annotations for the client.
*/
val annotations: Annotations? = null,
)
/**
@ -738,6 +752,14 @@ public data class ResourceTemplate(
* The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type.
*/
val mimeType: String?,
/**
* The optional human-readable name of this resource for display purposes.
*/
val title: String? = null,
/**
* Optional annotations for the client.
*/
val annotations: Annotations? = null,
)
/**
@ -971,6 +993,11 @@ public data class TextContent(
* The text content of the message.
*/
val text: String? = null,
/**
* Optional annotations for the client.
*/
val annotations: Annotations? = null,
) : PromptMessageContentMultimodal {
override val type: String = TYPE
@ -993,6 +1020,11 @@ public data class ImageContent(
* The MIME type of the image. Different providers may support different image types.
*/
val mimeType: String,
/**
* Optional annotations for the client.
*/
val annotations: Annotations? = null,
) : PromptMessageContentMultimodal {
override val type: String = TYPE
@ -1015,6 +1047,11 @@ public data class AudioContent(
* The MIME type of the audio. Different providers may support different audio types.
*/
val mimeType: String,
/**
* Optional annotations for the client.
*/
val annotations: Annotations? = null,
) : PromptMessageContentMultimodal {
override val type: String = TYPE
@ -1033,7 +1070,17 @@ public data class UnknownContent(override val type: String) : PromptMessageConte
* 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(
/**
* The contents of the embedded resource.
*/
val resource: ResourceContents,
/**
* Optional annotations for the client.
*/
val annotations: Annotations? = null,
) : PromptMessageContent {
override val type: String = TYPE
public companion object {
@ -1051,6 +1098,34 @@ public enum class Role {
assistant,
}
/**
* Optional annotations for the client.
* The client can use annotations to inform how objects are used or displayed.
*/
@Serializable
public data class Annotations(
/**
* Describes who the intended customer of this object or data is.
*/
val audience: List<Role>?,
/**
* The moment the resource was last modified.
*/
@OptIn(ExperimentalTime::class)
val lastModified: Instant?,
/**
* Describes how important this data is for operating the server.
*
* A value of 1.0 means "most important", and indicates that the data is effectively required,
* while 0.0 means "less important", and indicates that the data is entirely optional.
*/
val priority: Double?,
) {
init {
require(priority == null || priority in 0.0..1.0) { "Priority must be between 0.0 and 1.0" }
}
}
/**
* Describes a message returned as part of a prompt.
*/

View file

@ -6,6 +6,8 @@ import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
import kotlin.time.ExperimentalTime
import kotlin.time.Instant
class TypesTest {
@ -236,6 +238,23 @@ class TypesTest {
assertEquals("text/x-rust", textResource.mimeType)
}
@OptIn(ExperimentalTime::class)
@Test
fun `should serialize and deserialize annotations correctly`() {
val annotations = Annotations(
audience = listOf(Role.assistant),
lastModified = Instant.parse("2025-06-18T00:00:00Z"),
priority = 0.5,
)
val json = McpJson.encodeToString(annotations)
val decoded = McpJson.decodeFromString<Annotations>(json)
assertEquals(listOf(Role.assistant), decoded.audience)
assertEquals(Instant.parse("2025-06-18T00:00:00Z"), decoded.lastModified)
assertEquals(0.5, decoded.priority)
}
@Test
fun `should serialize and deserialize prompt message correctly`() {
val imageContent = ImageContent(