Merge pull request #204 from koic/make_tool_names_stricter
Make tool names stricter
This commit is contained in:
commit
4968d9cffc
2 changed files with 61 additions and 1 deletions
|
|
@ -4,6 +4,7 @@ module MCP
|
|||
class Tool
|
||||
class << self
|
||||
NOT_SET = Object.new
|
||||
MAX_LENGTH_OF_NAME = 128
|
||||
|
||||
attr_reader :title_value
|
||||
attr_reader :description_value
|
||||
|
|
@ -45,11 +46,13 @@ module MCP
|
|||
name_value
|
||||
else
|
||||
@name_value = value
|
||||
|
||||
validate!
|
||||
end
|
||||
end
|
||||
|
||||
def name_value
|
||||
@name_value || StringUtils.handle_from_class_name(name)
|
||||
@name_value || (name.nil? ? nil : StringUtils.handle_from_class_name(name))
|
||||
end
|
||||
|
||||
def input_schema_value
|
||||
|
|
@ -129,6 +132,22 @@ module MCP
|
|||
output_schema output_schema
|
||||
self.annotations(annotations) if annotations
|
||||
define_singleton_method(:call, &block) if block
|
||||
end.tap(&:validate!)
|
||||
end
|
||||
|
||||
# It complies with the following tool name specification:
|
||||
# https://modelcontextprotocol.io/specification/latest/server/tools#tool-names
|
||||
def validate!
|
||||
return true unless tool_name
|
||||
|
||||
if tool_name.empty? || tool_name.length > MAX_LENGTH_OF_NAME
|
||||
raise ArgumentError, "Tool names should be between 1 and 128 characters in length (inclusive)."
|
||||
end
|
||||
|
||||
unless tool_name.match?(/\A[A-Za-z\d_\-\.]+\z/)
|
||||
raise ArgumentError, <<~MESSAGE
|
||||
Tool names only allowed characters: uppercase and lowercase ASCII letters (A-Z, a-z), digits (0-9), underscore (_), hyphen (-), and dot (.).
|
||||
MESSAGE
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -447,5 +447,46 @@ module MCP
|
|||
expected_output = { type: "object", properties: { result: { type: "string" }, success: { type: "boolean" } }, required: ["result", "success"] }
|
||||
assert_equal expected_output, tool.output_schema.to_h
|
||||
end
|
||||
|
||||
test "accepts valid tool names" do
|
||||
assert Tool.define(name: "getUser")
|
||||
assert Tool.define(name: "DATA_EXPORT_v2")
|
||||
assert Tool.define(name: "admin.tools.list")
|
||||
assert Tool.define(name: "a" * 128)
|
||||
end
|
||||
|
||||
test "raises an error when tool name is empty in class definition" do
|
||||
error = assert_raises(ArgumentError) do
|
||||
class EmptyTitleNameTool < Tool
|
||||
tool_name ""
|
||||
end
|
||||
end
|
||||
assert_equal("Tool names should be between 1 and 128 characters in length (inclusive).", error.message)
|
||||
end
|
||||
|
||||
test "allows nil tool name in class definition" do
|
||||
assert_nothing_raised do
|
||||
class EmptyTitleNameTool < Tool
|
||||
tool_name nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "raises an error when tool name is empty" do
|
||||
error = assert_raises(ArgumentError) { Tool.define(name: "") }
|
||||
assert_equal("Tool names should be between 1 and 128 characters in length (inclusive).", error.message)
|
||||
end
|
||||
|
||||
test "raises an error when tool name exceeds 128 characters" do
|
||||
error = assert_raises(ArgumentError) { Tool.define(name: "a" * 129) }
|
||||
assert_equal("Tool names should be between 1 and 128 characters in length (inclusive).", error.message)
|
||||
end
|
||||
|
||||
test "raises an error when tool name includes invalid characters (e.g., spaces)" do
|
||||
error = assert_raises(ArgumentError) { Tool.define(name: "foo bar") }
|
||||
assert_equal(<<~MESSAGE, error.message)
|
||||
Tool names only allowed characters: uppercase and lowercase ASCII letters (A-Z, a-z), digits (0-9), underscore (_), hyphen (-), and dot (.).
|
||||
MESSAGE
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue