feat: add tool execution properties to Tool (#567)

closes #543 

## How Has This Been Tested?
unit

## Breaking Changes
binary compatibility in the Tool class

## Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

---------

Co-authored-by: Konstantin Pavlov <1517853+kpavlov@users.noreply.github.com>
This commit is contained in:
Pavel Gorgulov 2026-03-10 20:05:44 +01:00 • committed by GitHub
commit 338f94804f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 188 additions and 8 deletions

View file

@ -1618,7 +1618,7 @@ public fun Tool(
title,
annotations,
icons,
_meta,
meta = _meta,
)
/**

View file

@ -55,6 +55,8 @@ public fun CallToolResult.Companion.error(content: String, meta: JsonObject? = n
* @property icons Optional set of sized icons that clients can display in their user interface.
* Clients MUST support at least PNG and JPEG formats.
* Clients SHOULD also support SVG and WebP formats.
* @property execution Optional execution-related properties for this tool,
* such as task-augmented execution support.
* @property meta Optional metadata for this tool.
*/
@Serializable
@ -66,6 +68,7 @@ public data class Tool(
val title: String? = null,
val annotations: ToolAnnotations? = null,
val icons: List<Icon>? = null,
val execution: ToolExecution? = null,
@SerialName("_meta")
override val meta: JsonObject? = null,
) : WithMeta
@ -92,6 +95,38 @@ public data class ToolSchema(
val type: String = "object"
}
/**
* Execution-related properties for a tool.
*
* @property taskSupport Indicates whether this tool supports task-augmented execution.
* This allows clients to handle long-running operations through polling the task system.
* If omitted (`null`), consumers should treat it as [TaskSupport.Forbidden] per the spec.
*/
@Serializable
public data class ToolExecution(val taskSupport: TaskSupport? = null)
/**
* Indicates whether a tool supports task-augmented execution.
*
* - [Forbidden]: Tool does not support task-augmented execution (default when absent).
* - [Optional]: Tool may support task-augmented execution.
* - [Required]: Tool requires task-augmented execution.
*/
@Serializable
public enum class TaskSupport {
/** Tool does not support task-augmented execution. */
@SerialName("forbidden")
Forbidden,
/** Tool may support task-augmented execution. */
@SerialName("optional")
Optional,
/** Tool requires task-augmented execution. */
@SerialName("required")
Required,
}
/**
* Additional properties describing a Tool to clients.
*

View file

@ -475,6 +475,102 @@ class ToolsTest {
assertEquals(null, result.structuredContent)
}
@Test
fun `should serialize ToolExecution with taskSupport`() {
val execution = ToolExecution(taskSupport = TaskSupport.Required)
verifySerialization(
execution,
McpJson,
"""
{
"taskSupport": "required"
}
""".trimIndent(),
)
}
@Test
fun `should serialize ToolExecution without taskSupport`() {
val execution = ToolExecution()
verifySerialization(
execution,
McpJson,
"{}",
)
}
@Test
fun `should deserialize ToolExecution with taskSupport`() {
val json = """
{
"taskSupport": "optional"
}
""".trimIndent()
val execution = verifyDeserialization<ToolExecution>(McpJson, json)
assertEquals(TaskSupport.Optional, execution.taskSupport)
}
@Test
fun `should deserialize ToolExecution without taskSupport`() {
val json = "{}"
val execution = verifyDeserialization<ToolExecution>(McpJson, json)
assertEquals(null, execution.taskSupport)
}
@Test
fun `should serialize Tool with execution`() {
val tool = Tool(
name = "long-running-task",
inputSchema = ToolSchema(),
description = "A tool that supports task-augmented execution",
execution = ToolExecution(taskSupport = TaskSupport.Required),
)
verifySerialization(
tool,
McpJson,
"""
{
"name": "long-running-task",
"inputSchema": {
"type": "object"
},
"description": "A tool that supports task-augmented execution",
"execution": {
"taskSupport": "required"
}
}
""".trimIndent(),
)
}
@Test
fun `should deserialize Tool with execution`() {
val json = """
{
"name": "long-running-task",
"inputSchema": {
"type": "object"
},
"execution": {
"taskSupport": "forbidden"
}
}
""".trimIndent()
val tool = verifyDeserialization<Tool>(McpJson, json)
assertEquals("long-running-task", tool.name)
assertNotNull(tool.execution)
assertEquals(TaskSupport.Forbidden, tool.execution.taskSupport)
}
@Test
fun `should serialize tool schema type even when defaults disabled`() {
val tool = weatherTool()