Support icons parameter
This PR adds support for the optional `icons` parameter in prompt, resource, resource template, and server info. The specifications for `icons` are as follows. https://modelcontextprotocol.io/specification/2025-11-25/schema#icon Resolves https://github.com/modelcontextprotocol/ruby-sdk/issues/127.
This commit is contained in:
parent
d745ccdedc
commit
028c5f3291
11 changed files with 139 additions and 15 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
require_relative "json_rpc_handler"
|
require_relative "json_rpc_handler"
|
||||||
require_relative "mcp/configuration"
|
require_relative "mcp/configuration"
|
||||||
require_relative "mcp/content"
|
require_relative "mcp/content"
|
||||||
|
require_relative "mcp/icon"
|
||||||
require_relative "mcp/instrumentation"
|
require_relative "mcp/instrumentation"
|
||||||
require_relative "mcp/methods"
|
require_relative "mcp/methods"
|
||||||
require_relative "mcp/prompt"
|
require_relative "mcp/prompt"
|
||||||
|
|
|
||||||
22
lib/mcp/icon.rb
Normal file
22
lib/mcp/icon.rb
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module MCP
|
||||||
|
class Icon
|
||||||
|
SUPPORTED_THEMES = ["light", "dark"]
|
||||||
|
|
||||||
|
attr_reader :mime_type, :sizes, :src, :theme
|
||||||
|
|
||||||
|
def initialize(mime_type: nil, sizes: nil, src: nil, theme: nil)
|
||||||
|
raise ArgumentError, 'The value of theme must specify "light" or "dark".' if theme && !SUPPORTED_THEMES.include?(theme)
|
||||||
|
|
||||||
|
@mime_type = mime_type
|
||||||
|
@sizes = sizes
|
||||||
|
@src = src
|
||||||
|
@theme = theme
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_h
|
||||||
|
{ mimeType: mime_type, sizes: sizes, src: src, theme: theme }.compact
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -7,6 +7,7 @@ module MCP
|
||||||
|
|
||||||
attr_reader :title_value
|
attr_reader :title_value
|
||||||
attr_reader :description_value
|
attr_reader :description_value
|
||||||
|
attr_reader :icons_value
|
||||||
attr_reader :arguments_value
|
attr_reader :arguments_value
|
||||||
attr_reader :meta_value
|
attr_reader :meta_value
|
||||||
|
|
||||||
|
|
@ -19,6 +20,7 @@ module MCP
|
||||||
name: name_value,
|
name: name_value,
|
||||||
title: title_value,
|
title: title_value,
|
||||||
description: description_value,
|
description: description_value,
|
||||||
|
icons: icons&.map(&:to_h),
|
||||||
arguments: arguments_value&.map(&:to_h),
|
arguments: arguments_value&.map(&:to_h),
|
||||||
_meta: meta_value,
|
_meta: meta_value,
|
||||||
}.compact
|
}.compact
|
||||||
|
|
@ -29,6 +31,7 @@ module MCP
|
||||||
subclass.instance_variable_set(:@name_value, nil)
|
subclass.instance_variable_set(:@name_value, nil)
|
||||||
subclass.instance_variable_set(:@title_value, nil)
|
subclass.instance_variable_set(:@title_value, nil)
|
||||||
subclass.instance_variable_set(:@description_value, nil)
|
subclass.instance_variable_set(:@description_value, nil)
|
||||||
|
subclass.instance_variable_set(:@icons_value, nil)
|
||||||
subclass.instance_variable_set(:@arguments_value, nil)
|
subclass.instance_variable_set(:@arguments_value, nil)
|
||||||
subclass.instance_variable_set(:@meta_value, nil)
|
subclass.instance_variable_set(:@meta_value, nil)
|
||||||
end
|
end
|
||||||
|
|
@ -61,6 +64,14 @@ module MCP
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def icons(value = NOT_SET)
|
||||||
|
if value == NOT_SET
|
||||||
|
@icons_value
|
||||||
|
else
|
||||||
|
@icons_value = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def arguments(value = NOT_SET)
|
def arguments(value = NOT_SET)
|
||||||
if value == NOT_SET
|
if value == NOT_SET
|
||||||
@arguments_value
|
@arguments_value
|
||||||
|
|
@ -77,11 +88,12 @@ module MCP
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def define(name: nil, title: nil, description: nil, arguments: [], meta: nil, &block)
|
def define(name: nil, title: nil, description: nil, icons: [], arguments: [], meta: nil, &block)
|
||||||
Class.new(self) do
|
Class.new(self) do
|
||||||
prompt_name name
|
prompt_name name
|
||||||
title title
|
title title
|
||||||
description description
|
description description
|
||||||
|
icons icons
|
||||||
arguments arguments
|
arguments arguments
|
||||||
define_singleton_method(:template) do |args, server_context: nil|
|
define_singleton_method(:template) do |args, server_context: nil|
|
||||||
instance_exec(args, server_context:, &block)
|
instance_exec(args, server_context:, &block)
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@
|
||||||
|
|
||||||
module MCP
|
module MCP
|
||||||
class Resource
|
class Resource
|
||||||
attr_reader :uri, :name, :title, :description, :mime_type
|
attr_reader :uri, :name, :title, :description, :icons, :mime_type
|
||||||
|
|
||||||
def initialize(uri:, name:, title: nil, description: nil, mime_type: nil)
|
def initialize(uri:, name:, title: nil, description: nil, icons: [], mime_type: nil)
|
||||||
@uri = uri
|
@uri = uri
|
||||||
@name = name
|
@name = name
|
||||||
@title = title
|
@title = title
|
||||||
@description = description
|
@description = description
|
||||||
|
@icons = icons
|
||||||
@mime_type = mime_type
|
@mime_type = mime_type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -18,6 +19,7 @@ module MCP
|
||||||
name: name,
|
name: name,
|
||||||
title: title,
|
title: title,
|
||||||
description: description,
|
description: description,
|
||||||
|
icons: icons.map(&:to_h),
|
||||||
mimeType: mime_type,
|
mimeType: mime_type,
|
||||||
}.compact
|
}.compact
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@
|
||||||
|
|
||||||
module MCP
|
module MCP
|
||||||
class ResourceTemplate
|
class ResourceTemplate
|
||||||
attr_reader :uri_template, :name, :title, :description, :mime_type
|
attr_reader :uri_template, :name, :title, :description, :icons, :mime_type
|
||||||
|
|
||||||
def initialize(uri_template:, name:, title: nil, description: nil, mime_type: nil)
|
def initialize(uri_template:, name:, title: nil, description: nil, icons: [], mime_type: nil)
|
||||||
@uri_template = uri_template
|
@uri_template = uri_template
|
||||||
@name = name
|
@name = name
|
||||||
@title = title
|
@title = title
|
||||||
@description = description
|
@description = description
|
||||||
|
@icons = icons
|
||||||
@mime_type = mime_type
|
@mime_type = mime_type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -18,6 +19,7 @@ module MCP
|
||||||
name: name,
|
name: name,
|
||||||
title: title,
|
title: title,
|
||||||
description: description,
|
description: description,
|
||||||
|
icons: icons.map(&:to_h),
|
||||||
mimeType: mime_type,
|
mimeType: mime_type,
|
||||||
}.compact
|
}.compact
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,11 @@ module MCP
|
||||||
|
|
||||||
include Instrumentation
|
include Instrumentation
|
||||||
|
|
||||||
attr_accessor :description, :name, :title, :version, :website_url, :instructions, :tools, :prompts, :resources, :server_context, :configuration, :capabilities, :transport
|
attr_accessor :description, :icons, :name, :title, :version, :website_url, :instructions, :tools, :prompts, :resources, :server_context, :configuration, :capabilities, :transport
|
||||||
|
|
||||||
def initialize(
|
def initialize(
|
||||||
description: nil,
|
description: nil,
|
||||||
|
icons: [],
|
||||||
name: "model_context_protocol",
|
name: "model_context_protocol",
|
||||||
title: nil,
|
title: nil,
|
||||||
version: DEFAULT_VERSION,
|
version: DEFAULT_VERSION,
|
||||||
|
|
@ -59,6 +60,7 @@ module MCP
|
||||||
transport: nil
|
transport: nil
|
||||||
)
|
)
|
||||||
@description = description
|
@description = description
|
||||||
|
@icons = icons
|
||||||
@name = name
|
@name = name
|
||||||
@title = title
|
@title = title
|
||||||
@version = version
|
@version = version
|
||||||
|
|
@ -288,6 +290,7 @@ module MCP
|
||||||
def server_info
|
def server_info
|
||||||
@server_info ||= {
|
@server_info ||= {
|
||||||
description:,
|
description:,
|
||||||
|
icons:,
|
||||||
name:,
|
name:,
|
||||||
title:,
|
title:,
|
||||||
version:,
|
version:,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ module MCP
|
||||||
|
|
||||||
attr_reader :title_value
|
attr_reader :title_value
|
||||||
attr_reader :description_value
|
attr_reader :description_value
|
||||||
|
attr_reader :icons_value
|
||||||
attr_reader :annotations_value
|
attr_reader :annotations_value
|
||||||
attr_reader :meta_value
|
attr_reader :meta_value
|
||||||
|
|
||||||
|
|
@ -19,6 +20,7 @@ module MCP
|
||||||
name: name_value,
|
name: name_value,
|
||||||
title: title_value,
|
title: title_value,
|
||||||
description: description_value,
|
description: description_value,
|
||||||
|
icons: icons&.map(&:to_h),
|
||||||
inputSchema: input_schema_value.to_h,
|
inputSchema: input_schema_value.to_h,
|
||||||
outputSchema: @output_schema_value&.to_h,
|
outputSchema: @output_schema_value&.to_h,
|
||||||
annotations: annotations_value&.to_h,
|
annotations: annotations_value&.to_h,
|
||||||
|
|
@ -31,6 +33,7 @@ module MCP
|
||||||
subclass.instance_variable_set(:@name_value, nil)
|
subclass.instance_variable_set(:@name_value, nil)
|
||||||
subclass.instance_variable_set(:@title_value, nil)
|
subclass.instance_variable_set(:@title_value, nil)
|
||||||
subclass.instance_variable_set(:@description_value, nil)
|
subclass.instance_variable_set(:@description_value, nil)
|
||||||
|
subclass.instance_variable_set(:@icons_value, nil)
|
||||||
subclass.instance_variable_set(:@input_schema_value, nil)
|
subclass.instance_variable_set(:@input_schema_value, nil)
|
||||||
subclass.instance_variable_set(:@output_schema_value, nil)
|
subclass.instance_variable_set(:@output_schema_value, nil)
|
||||||
subclass.instance_variable_set(:@annotations_value, nil)
|
subclass.instance_variable_set(:@annotations_value, nil)
|
||||||
|
|
@ -71,6 +74,14 @@ module MCP
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def icons(value = NOT_SET)
|
||||||
|
if value == NOT_SET
|
||||||
|
@icons_value
|
||||||
|
else
|
||||||
|
@icons_value = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def input_schema(value = NOT_SET)
|
def input_schema(value = NOT_SET)
|
||||||
if value == NOT_SET
|
if value == NOT_SET
|
||||||
input_schema_value
|
input_schema_value
|
||||||
|
|
@ -107,11 +118,12 @@ module MCP
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def define(name: nil, title: nil, description: nil, input_schema: nil, output_schema: nil, meta: nil, annotations: nil, &block)
|
def define(name: nil, title: nil, description: nil, icons: [], input_schema: nil, output_schema: nil, meta: nil, annotations: nil, &block)
|
||||||
Class.new(self) do
|
Class.new(self) do
|
||||||
tool_name name
|
tool_name name
|
||||||
title title
|
title title
|
||||||
description description
|
description description
|
||||||
|
icons icons
|
||||||
input_schema input_schema
|
input_schema input_schema
|
||||||
meta meta
|
meta meta
|
||||||
output_schema output_schema
|
output_schema output_schema
|
||||||
|
|
|
||||||
48
test/mcp/icon_test.rb
Normal file
48
test/mcp/icon_test.rb
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
module MCP
|
||||||
|
class IconTest < ActiveSupport::TestCase
|
||||||
|
def test_initialization
|
||||||
|
icon = Icon.new(mime_type: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light")
|
||||||
|
|
||||||
|
assert_equal("image/png", icon.mime_type)
|
||||||
|
assert_equal(["48x48", "96x96"], icon.sizes)
|
||||||
|
assert_equal("https://example.com", icon.src)
|
||||||
|
assert_equal("light", icon.theme)
|
||||||
|
|
||||||
|
assert_equal({ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }, icon.to_h)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_initialization_by_default
|
||||||
|
icon = Icon.new
|
||||||
|
|
||||||
|
assert_nil(icon.mime_type)
|
||||||
|
assert_nil(icon.sizes)
|
||||||
|
assert_nil(icon.src)
|
||||||
|
assert_nil(icon.theme)
|
||||||
|
|
||||||
|
assert_empty(icon.to_h)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_valid_theme_for_light
|
||||||
|
assert_nothing_raised do
|
||||||
|
Icon.new(theme: "light")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_valid_theme_for_dark
|
||||||
|
assert_nothing_raised do
|
||||||
|
Icon.new(theme: "dark")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_invalid_theme
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
Icon.new(theme: "unexpected")
|
||||||
|
end
|
||||||
|
assert_equal('The value of theme must specify "light" or "dark".', exception.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -6,6 +6,7 @@ module MCP
|
||||||
class PromptTest < ActiveSupport::TestCase
|
class PromptTest < ActiveSupport::TestCase
|
||||||
class TestPrompt < Prompt
|
class TestPrompt < Prompt
|
||||||
description "Test prompt"
|
description "Test prompt"
|
||||||
|
icons [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }]
|
||||||
arguments [
|
arguments [
|
||||||
Prompt::Argument.new(name: "test_argument", description: "Test argument", required: true),
|
Prompt::Argument.new(name: "test_argument", description: "Test argument", required: true),
|
||||||
]
|
]
|
||||||
|
|
@ -43,6 +44,7 @@ module MCP
|
||||||
class MockPrompt < Prompt
|
class MockPrompt < Prompt
|
||||||
prompt_name "my_mock_prompt"
|
prompt_name "my_mock_prompt"
|
||||||
description "a mock prompt for testing"
|
description "a mock prompt for testing"
|
||||||
|
icons [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }]
|
||||||
arguments [
|
arguments [
|
||||||
Prompt::Argument.new(name: "test_argument", description: "Test argument", required: true),
|
Prompt::Argument.new(name: "test_argument", description: "Test argument", required: true),
|
||||||
]
|
]
|
||||||
|
|
@ -64,6 +66,7 @@ module MCP
|
||||||
|
|
||||||
assert_equal "my_mock_prompt", prompt.name_value
|
assert_equal "my_mock_prompt", prompt.name_value
|
||||||
assert_equal "a mock prompt for testing", prompt.description
|
assert_equal "a mock prompt for testing", prompt.description
|
||||||
|
assert_equal([{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }], prompt.icons)
|
||||||
assert_equal "test_argument", prompt.arguments.first.name
|
assert_equal "test_argument", prompt.arguments.first.name
|
||||||
assert_equal "Test argument", prompt.arguments.first.description
|
assert_equal "Test argument", prompt.arguments.first.description
|
||||||
assert prompt.arguments.first.required
|
assert prompt.arguments.first.required
|
||||||
|
|
@ -112,6 +115,7 @@ module MCP
|
||||||
name: "mock_prompt",
|
name: "mock_prompt",
|
||||||
title: "Mock Prompt",
|
title: "Mock Prompt",
|
||||||
description: "a mock prompt for testing",
|
description: "a mock prompt for testing",
|
||||||
|
icons: [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }],
|
||||||
arguments: [
|
arguments: [
|
||||||
Prompt::Argument.new(
|
Prompt::Argument.new(
|
||||||
name: "test_argument",
|
name: "test_argument",
|
||||||
|
|
@ -135,6 +139,7 @@ module MCP
|
||||||
|
|
||||||
assert_equal "mock_prompt", prompt.name_value
|
assert_equal "mock_prompt", prompt.name_value
|
||||||
assert_equal "a mock prompt for testing", prompt.description
|
assert_equal "a mock prompt for testing", prompt.description
|
||||||
|
assert_equal([{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }], prompt.icons)
|
||||||
assert_equal "test_argument", prompt.arguments.first.name
|
assert_equal "test_argument", prompt.arguments.first.name
|
||||||
assert_equal "Test argument title", prompt.arguments.first.title
|
assert_equal "Test argument title", prompt.arguments.first.title
|
||||||
assert_equal "This is a test argument description", prompt.arguments.first.description
|
assert_equal "This is a test argument description", prompt.arguments.first.description
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ module MCP
|
||||||
name: "test-resource",
|
name: "test-resource",
|
||||||
title: "Test Resource",
|
title: "Test Resource",
|
||||||
description: "Test resource",
|
description: "Test resource",
|
||||||
|
icons: [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }],
|
||||||
mime_type: "text/plain",
|
mime_type: "text/plain",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -60,6 +61,7 @@ module MCP
|
||||||
name: "test-resource",
|
name: "test-resource",
|
||||||
title: "Test Resource",
|
title: "Test Resource",
|
||||||
description: "Test resource",
|
description: "Test resource",
|
||||||
|
icons: [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }],
|
||||||
mime_type: "text/plain",
|
mime_type: "text/plain",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -69,6 +71,7 @@ module MCP
|
||||||
|
|
||||||
@server = Server.new(
|
@server = Server.new(
|
||||||
description: "Test server",
|
description: "Test server",
|
||||||
|
icons: [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }],
|
||||||
name: @server_name,
|
name: @server_name,
|
||||||
title: "Example Server Display Name",
|
title: "Example Server Display Name",
|
||||||
version: "1.2.3",
|
version: "1.2.3",
|
||||||
|
|
@ -142,6 +145,7 @@ module MCP
|
||||||
},
|
},
|
||||||
serverInfo: {
|
serverInfo: {
|
||||||
description: "Test server",
|
description: "Test server",
|
||||||
|
icons: [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }],
|
||||||
name: @server_name,
|
name: @server_name,
|
||||||
title: "Example Server Display Name",
|
title: "Example Server Display Name",
|
||||||
version: "1.2.3",
|
version: "1.2.3",
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ module MCP
|
||||||
class TestTool < Tool
|
class TestTool < Tool
|
||||||
tool_name "test_tool"
|
tool_name "test_tool"
|
||||||
description "a test tool for testing"
|
description "a test tool for testing"
|
||||||
|
icons [Icon.new(mime_type: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light")]
|
||||||
input_schema({ properties: { message: { type: "string" } }, required: ["message"] })
|
input_schema({ properties: { message: { type: "string" } }, required: ["message"] })
|
||||||
annotations(
|
annotations(
|
||||||
destructive_hint: false,
|
destructive_hint: false,
|
||||||
|
|
@ -26,13 +27,22 @@ module MCP
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "#to_h returns a hash with name, description, and inputSchema" do
|
test "#to_h returns a hash including name, description, icons, and inputSchema" do
|
||||||
|
expected = {
|
||||||
|
name: "mock_tool",
|
||||||
|
title: "Mock Tool",
|
||||||
|
description: "a mock tool for testing",
|
||||||
|
icons: [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }],
|
||||||
|
inputSchema: { type: "object" },
|
||||||
|
}
|
||||||
tool = Tool.define(
|
tool = Tool.define(
|
||||||
name: "mock_tool",
|
name: "mock_tool",
|
||||||
title: "Mock Tool",
|
title: "Mock Tool",
|
||||||
description: "a mock tool for testing",
|
description: "a mock tool for testing",
|
||||||
|
icons: [Icon.new(mime_type: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light")],
|
||||||
)
|
)
|
||||||
assert_equal({ name: "mock_tool", title: "Mock Tool", description: "a mock tool for testing", inputSchema: { type: "object" } }, tool.to_h)
|
|
||||||
|
assert_equal(expected, tool.to_h)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "#to_h does not have `:title` key when title is omitted" do
|
test "#to_h does not have `:title` key when title is omitted" do
|
||||||
|
|
@ -308,19 +318,22 @@ module MCP
|
||||||
end
|
end
|
||||||
|
|
||||||
test "#to_h includes outputSchema when present" do
|
test "#to_h includes outputSchema when present" do
|
||||||
tool = Tool.define(
|
|
||||||
name: "mock_tool",
|
|
||||||
title: "Mock Tool",
|
|
||||||
description: "a mock tool for testing",
|
|
||||||
output_schema: { properties: { result: { type: "string" } }, required: ["result"] },
|
|
||||||
)
|
|
||||||
expected = {
|
expected = {
|
||||||
name: "mock_tool",
|
name: "mock_tool",
|
||||||
title: "Mock Tool",
|
title: "Mock Tool",
|
||||||
description: "a mock tool for testing",
|
description: "a mock tool for testing",
|
||||||
|
icons: [{ mimeType: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light" }],
|
||||||
inputSchema: { type: "object" },
|
inputSchema: { type: "object" },
|
||||||
outputSchema: { type: "object", properties: { result: { type: "string" } }, required: ["result"] },
|
outputSchema: { type: "object", properties: { result: { type: "string" } }, required: ["result"] },
|
||||||
}
|
}
|
||||||
|
tool = Tool.define(
|
||||||
|
name: "mock_tool",
|
||||||
|
title: "Mock Tool",
|
||||||
|
description: "a mock tool for testing",
|
||||||
|
icons: [Icon.new(mime_type: "image/png", sizes: ["48x48", "96x96"], src: "https://example.com", theme: "light")],
|
||||||
|
output_schema: { properties: { result: { type: "string" } }, required: ["result"] },
|
||||||
|
)
|
||||||
|
|
||||||
assert_equal expected, tool.to_h
|
assert_equal expected, tool.to_h
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue