Skip to content

feat: add tool annotations according to 2025-03-26 spec #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,15 @@ public open class Server(
name: String,
description: String,
inputSchema: Tool.Input = Tool.Input(),
toolAnnotations: ToolAnnotations? = null,
handler: suspend (CallToolRequest) -> CallToolResult
) {
if (capabilities.tools == null) {
logger.error { "Failed to add tool '$name': Server does not support tools capability" }
throw IllegalStateException("Server does not support tools capability. Enable it in ServerOptions.")
}
logger.info { "Registering tool: $name" }
tools[name] = RegisteredTool(Tool(name, description, inputSchema), handler)
tools[name] = RegisteredTool(Tool(name, description, inputSchema, toolAnnotations), handler)
}

/**
Expand Down
57 changes: 57 additions & 0 deletions src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,58 @@ public class PromptListChangedNotification : ServerNotification {
}

/* Tools */
/**
* Additional properties describing a Tool to clients.
*
* NOTE: all properties in ToolAnnotations are **hints**.
* They are not guaranteed to provide a faithful description of
* tool behavior (including descriptive properties like `title`).
*
* Clients should never make tool use decisions based on ToolAnnotations
* received from untrusted servers.
*/
@Serializable
public data class ToolAnnotations(
/**
* A human-readable title for the tool.
*/
val title: String?,
/**
* If true, the tool does not modify its environment.
*
* Default: false
*/
val readOnlyHint: Boolean? = false,
/**
* If true, the tool may perform destructive updates to its environment.
* If false, the tool performs only additive updates.
*
* (This property is meaningful only when `readOnlyHint == false`)
*
* Default: true
*/
val destructiveHint: Boolean? = true,
/**
* If true, calling the tool repeatedly with the same arguments
* will have no additional effect on the its environment.
*
* (This property is meaningful only when `readOnlyHint == false`)
*
* Default: false
*/
val idempotentHint: Boolean? = false,
/**
* If true, this tool may interact with an "open world" of external
* entities. If false, the tool's domain of interaction is closed.
* For example, the world of a web search tool is open, whereas that
* of a memory tool is not.
*
* Default: true
*/
val openWorldHint: Boolean? = true,
)


/**
* Definition for a tool the client can call.
*/
Expand All @@ -1008,6 +1060,11 @@ public data class Tool(
* A JSON object defining the expected parameters for the tool.
*/
val inputSchema: Input,

/**
* Optional additional tool information.
*/
val annotations: ToolAnnotations?,
) {
@Serializable
public data class Input(
Expand Down
2 changes: 2 additions & 0 deletions src/commonTest/kotlin/ToolSerializationTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.modelcontextprotocol.kotlin.sdk

import io.kotest.assertions.json.shouldEqualJson
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
import kotlinx.atomicfu.atomicArrayOfNulls
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.buildJsonObject
Expand Down Expand Up @@ -32,6 +33,7 @@ class ToolSerializationTest {
val getWeatherTool = Tool(
name = "get_weather",
description = "Get the current weather in a given location",
annotations = null,
inputSchema = Tool.Input(
properties = buildJsonObject {
put("location", buildJsonObject {
Expand Down
1 change: 1 addition & 0 deletions src/jvmTest/kotlin/client/ClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ class ClientTest {
Tool(
name = "testTool",
description = "testTool description",
annotations = null,
inputSchema = Tool.Input()
)
), nextCursor = null
Expand Down
Loading