diff --git a/README.md b/README.md index f1726ad7..582477b1 100644 --- a/README.md +++ b/README.md @@ -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: -- `destructive_hint`: Indicates if the tool performs destructive operations -- `idempotent_hint`: Indicates if the tool's operations are idempotent -- `open_world_hint`: Indicates if the tool operates in an open world context -- `read_only_hint`: Indicates if the tool only reads data (doesn't modify state) +- `destructive_hint`: Indicates if the tool performs destructive operations. Defaults to true +- `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. Defaults to true +- `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 Annotations can be set either through the class definition using the `annotations` class method or when defining a tool using the `define` method. diff --git a/lib/mcp/tool/annotations.rb b/lib/mcp/tool/annotations.rb index 6344334d..328a24cd 100644 --- a/lib/mcp/tool/annotations.rb +++ b/lib/mcp/tool/annotations.rb @@ -3,9 +3,9 @@ module MCP class Tool 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 @read_only_hint = read_only_hint @destructive_hint = destructive_hint @@ -15,11 +15,11 @@ def initialize(title: nil, read_only_hint: nil, destructive_hint: nil, idempoten def to_h { - title:, - readOnlyHint: read_only_hint, destructiveHint: destructive_hint, idempotentHint: idempotent_hint, openWorldHint: open_world_hint, + readOnlyHint: read_only_hint, + title:, }.compact end end diff --git a/test/mcp/tool/annotations_test.rb b/test/mcp/tool/annotations_test.rb index 7615ea82..b379db70 100644 --- a/test/mcp/tool/annotations_test.rb +++ b/test/mcp/tool/annotations_test.rb @@ -7,31 +7,31 @@ class Tool class AnnotationsTest < ActiveSupport::TestCase test "Tool::Annotations initializes with all properties" do annotations = Tool::Annotations.new( - title: "Test Tool", - read_only_hint: true, destructive_hint: false, idempotent_hint: true, 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 assert annotations.idempotent_hint refute annotations.open_world_hint + assert annotations.read_only_hint + assert_equal "Test Tool", annotations.title end test "Tool::Annotations initializes with partial properties" do annotations = Tool::Annotations.new( - title: "Test Tool", 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_nil annotations.destructive_hint - assert_nil annotations.idempotent_hint - assert_nil annotations.open_world_hint + assert_equal "Test Tool", annotations.title end test "Tool::Annotations#to_h omits nil values" do @@ -41,34 +41,37 @@ class AnnotationsTest < ActiveSupport::TestCase ) expected = { - title: "Test Tool", + destructiveHint: true, + idempotentHint: false, + openWorldHint: true, readOnlyHint: true, + title: "Test Tool", } assert_equal expected, annotations.to_h end test "Tool::Annotations#to_h handles all properties" do annotations = Tool::Annotations.new( - title: "Test Tool", - read_only_hint: true, destructive_hint: false, idempotent_hint: true, open_world_hint: false, + read_only_hint: true, + title: "Test Tool", ) expected = { - title: "Test Tool", - readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, + readOnlyHint: true, + title: "Test Tool", } assert_equal expected, annotations.to_h 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 - assert_empty annotations.to_h + assert_equal({ destructiveHint: true, idempotentHint: false, openWorldHint: true, readOnlyHint: false }, annotations.to_h) end end end diff --git a/test/mcp/tool_test.rb b/test/mcp/tool_test.rb index f2e3838a..a8dafcaa 100644 --- a/test/mcp/tool_test.rb +++ b/test/mcp/tool_test.rb @@ -10,11 +10,11 @@ class TestTool < Tool description "a test tool for testing" input_schema({ properties: { message: { type: "string" } }, required: ["message"] }) annotations( - title: "Test Tool", - read_only_hint: true, destructive_hint: false, idempotent_hint: true, open_world_hint: false, + read_only_hint: true, + title: "Test Tool", ) class << self @@ -36,11 +36,11 @@ def call(message:, server_context: nil) test "#to_h includes annotations when present" do tool = TestTool expected_annotations = { - title: "Test Tool", - readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false, + readOnlyHint: true, + title: "Test Tool", } assert_equal expected_annotations, tool.to_h[:annotations] end @@ -142,15 +142,15 @@ class InputSchemaTool < Tool assert_equal "Mock Tool", tool.title assert_equal "a mock tool for testing", tool.description 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 test "Tool class method annotations can be set and retrieved" do class AnnotationsTestTool < Tool tool_name "annotations_test" annotations( - title: "Annotations Test", read_only_hint: true, + title: "Annotations Test", ) end