67 lines
1.8 KiB
Ruby
67 lines
1.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "json-schema"
|
|
|
|
module MCP
|
|
class Tool
|
|
class InputSchema
|
|
class ValidationError < StandardError; end
|
|
|
|
attr_reader :properties, :required
|
|
|
|
def initialize(properties: {}, required: [])
|
|
@properties = properties
|
|
@required = required.map(&:to_sym)
|
|
validate_schema!
|
|
end
|
|
|
|
def to_h
|
|
{ type: "object", properties:, required: }
|
|
end
|
|
|
|
def missing_required_arguments?(arguments)
|
|
missing_required_arguments(arguments).any?
|
|
end
|
|
|
|
def missing_required_arguments(arguments)
|
|
(required - arguments.keys.map(&:to_sym))
|
|
end
|
|
|
|
def validate_arguments(arguments)
|
|
errors = JSON::Validator.fully_validate(to_h, arguments)
|
|
if errors.any?
|
|
raise ValidationError, "Invalid arguments: #{errors.join(", ")}"
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def validate_schema!
|
|
check_for_refs!
|
|
schema = to_h
|
|
schema_reader = JSON::Schema::Reader.new(
|
|
accept_uri: false,
|
|
accept_file: ->(path) { path.to_s.start_with?(Gem.loaded_specs["json-schema"].full_gem_path) },
|
|
)
|
|
metaschema = JSON::Validator.validator_for_name("draft4").metaschema
|
|
errors = JSON::Validator.fully_validate(metaschema, schema, schema_reader: schema_reader)
|
|
if errors.any?
|
|
raise ArgumentError, "Invalid JSON Schema: #{errors.join(", ")}"
|
|
end
|
|
end
|
|
|
|
def check_for_refs!(obj = properties)
|
|
case obj
|
|
when Hash
|
|
if obj.key?("$ref") || obj.key?(:$ref)
|
|
raise ArgumentError, "Invalid JSON Schema: $ref is not allowed in tool input schemas"
|
|
end
|
|
|
|
obj.each_value { |value| check_for_refs!(value) }
|
|
when Array
|
|
obj.each { |item| check_for_refs!(item) }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|