Set default values for ToolAnnotations hints

According to the specification, `destructive_hint`, `idempotent_hint`, `open_world_hint`,
and `read_only_hint` of `ToolAnnotations` are optional with default values:
https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations

This PR sets their default values in accordance with the specification.

Additionally, for readability, the hints have been reordered to follow the specification.
This commit is contained in:
Koichi ITO 2025-08-28 00:19:50 +09:00
commit cae30547d2
4 changed files with 33 additions and 30 deletions

View file

@ -420,10 +420,10 @@ e.g. around authentication state.
Tools can include annotations that provide additional metadata about their behavior. The following annotations are supported: Tools can include annotations that provide additional metadata about their behavior. The following annotations are supported:
- `destructive_hint`: Indicates if the tool performs destructive operations - `destructive_hint`: Indicates if the tool performs destructive operations. Defaults to true
- `idempotent_hint`: Indicates if the tool's operations are idempotent - `idempotent_hint`: Indicates if the tool's operations are idempotent. Defaults to false
- `open_world_hint`: Indicates if the tool operates in an open world context - `open_world_hint`: Indicates if the tool operates in an open world context. Defaults to true
- `read_only_hint`: Indicates if the tool only reads data (doesn't modify state) - `read_only_hint`: Indicates if the tool only reads data (doesn't modify state). Defaults to false
- `title`: A human-readable title for the tool - `title`: A human-readable title for the tool
Annotations can be set either through the class definition using the `annotations` class method or when defining a tool using the `define` method. Annotations can be set either through the class definition using the `annotations` class method or when defining a tool using the `define` method.

View file

@ -3,9 +3,9 @@
module MCP module MCP
class Tool class Tool
class Annotations class Annotations
attr_reader :title, :read_only_hint, :destructive_hint, :idempotent_hint, :open_world_hint attr_reader :destructive_hint, :idempotent_hint, :open_world_hint, :read_only_hint, :title
def initialize(title: nil, read_only_hint: nil, destructive_hint: nil, idempotent_hint: nil, open_world_hint: nil) def initialize(destructive_hint: true, idempotent_hint: false, open_world_hint: true, read_only_hint: false, title: nil)
@title = title @title = title
@read_only_hint = read_only_hint @read_only_hint = read_only_hint
@destructive_hint = destructive_hint @destructive_hint = destructive_hint
@ -15,11 +15,11 @@ module MCP
def to_h def to_h
{ {
title:,
readOnlyHint: read_only_hint,
destructiveHint: destructive_hint, destructiveHint: destructive_hint,
idempotentHint: idempotent_hint, idempotentHint: idempotent_hint,
openWorldHint: open_world_hint, openWorldHint: open_world_hint,
readOnlyHint: read_only_hint,
title:,
}.compact }.compact
end end
end end

View file

@ -7,31 +7,31 @@ module MCP
class AnnotationsTest < ActiveSupport::TestCase class AnnotationsTest < ActiveSupport::TestCase
test "Tool::Annotations initializes with all properties" do test "Tool::Annotations initializes with all properties" do
annotations = Tool::Annotations.new( annotations = Tool::Annotations.new(
title: "Test Tool",
read_only_hint: true,
destructive_hint: false, destructive_hint: false,
idempotent_hint: true, idempotent_hint: true,
open_world_hint: false, open_world_hint: false,
read_only_hint: true,
title: "Test Tool",
) )
assert_equal "Test Tool", annotations.title
assert annotations.read_only_hint
refute annotations.destructive_hint refute annotations.destructive_hint
assert annotations.idempotent_hint assert annotations.idempotent_hint
refute annotations.open_world_hint refute annotations.open_world_hint
assert annotations.read_only_hint
assert_equal "Test Tool", annotations.title
end end
test "Tool::Annotations initializes with partial properties" do test "Tool::Annotations initializes with partial properties" do
annotations = Tool::Annotations.new( annotations = Tool::Annotations.new(
title: "Test Tool",
read_only_hint: true, read_only_hint: true,
title: "Test Tool",
) )
assert_equal "Test Tool", annotations.title assert annotations.destructive_hint
refute annotations.idempotent_hint
assert annotations.open_world_hint
assert annotations.read_only_hint assert annotations.read_only_hint
assert_nil annotations.destructive_hint assert_equal "Test Tool", annotations.title
assert_nil annotations.idempotent_hint
assert_nil annotations.open_world_hint
end end
test "Tool::Annotations#to_h omits nil values" do test "Tool::Annotations#to_h omits nil values" do
@ -41,34 +41,37 @@ module MCP
) )
expected = { expected = {
title: "Test Tool", destructiveHint: true,
idempotentHint: false,
openWorldHint: true,
readOnlyHint: true, readOnlyHint: true,
title: "Test Tool",
} }
assert_equal expected, annotations.to_h assert_equal expected, annotations.to_h
end end
test "Tool::Annotations#to_h handles all properties" do test "Tool::Annotations#to_h handles all properties" do
annotations = Tool::Annotations.new( annotations = Tool::Annotations.new(
title: "Test Tool",
read_only_hint: true,
destructive_hint: false, destructive_hint: false,
idempotent_hint: true, idempotent_hint: true,
open_world_hint: false, open_world_hint: false,
read_only_hint: true,
title: "Test Tool",
) )
expected = { expected = {
title: "Test Tool",
readOnlyHint: true,
destructiveHint: false, destructiveHint: false,
idempotentHint: true, idempotentHint: true,
openWorldHint: false, openWorldHint: false,
readOnlyHint: true,
title: "Test Tool",
} }
assert_equal expected, annotations.to_h assert_equal expected, annotations.to_h
end end
test "Tool::Annotations#to_h returns empty hash when all values are nil" do test "Tool::Annotations#to_h returns hash with default hint values" do
annotations = Tool::Annotations.new annotations = Tool::Annotations.new
assert_empty annotations.to_h assert_equal({ destructiveHint: true, idempotentHint: false, openWorldHint: true, readOnlyHint: false }, annotations.to_h)
end end
end end
end end

View file

@ -10,11 +10,11 @@ module MCP
description "a test tool for testing" description "a test tool for testing"
input_schema({ properties: { message: { type: "string" } }, required: ["message"] }) input_schema({ properties: { message: { type: "string" } }, required: ["message"] })
annotations( annotations(
title: "Test Tool",
read_only_hint: true,
destructive_hint: false, destructive_hint: false,
idempotent_hint: true, idempotent_hint: true,
open_world_hint: false, open_world_hint: false,
read_only_hint: true,
title: "Test Tool",
) )
class << self class << self
@ -36,11 +36,11 @@ module MCP
test "#to_h includes annotations when present" do test "#to_h includes annotations when present" do
tool = TestTool tool = TestTool
expected_annotations = { expected_annotations = {
title: "Test Tool",
readOnlyHint: true,
destructiveHint: false, destructiveHint: false,
idempotentHint: true, idempotentHint: true,
openWorldHint: false, openWorldHint: false,
readOnlyHint: true,
title: "Test Tool",
} }
assert_equal expected_annotations, tool.to_h[:annotations] assert_equal expected_annotations, tool.to_h[:annotations]
end end
@ -142,15 +142,15 @@ module MCP
assert_equal "Mock Tool", tool.title assert_equal "Mock Tool", tool.title
assert_equal "a mock tool for testing", tool.description assert_equal "a mock tool for testing", tool.description
assert_equal tool.input_schema, Tool::InputSchema.new assert_equal tool.input_schema, Tool::InputSchema.new
assert_equal({ readOnlyHint: true, title: "Mock Tool" }, tool.annotations_value.to_h) assert_equal({ destructiveHint: true, idempotentHint: false, openWorldHint: true, readOnlyHint: true, title: "Mock Tool" }, tool.annotations_value.to_h)
end end
test "Tool class method annotations can be set and retrieved" do test "Tool class method annotations can be set and retrieved" do
class AnnotationsTestTool < Tool class AnnotationsTestTool < Tool
tool_name "annotations_test" tool_name "annotations_test"
annotations( annotations(
title: "Annotations Test",
read_only_hint: true, read_only_hint: true,
title: "Annotations Test",
) )
end end