Class: VectorMCP::Tool
- Inherits:
-
Object
- Object
- VectorMCP::Tool
- Defined in:
- lib/vector_mcp/tool.rb
Overview
Abstract base class for declarative tool definitions.
Subclass this to define tools using a class-level DSL instead of the block-based register_tool API. The two styles are fully interchangeable – both produce the same VectorMCP::Definitions::Tool struct that the rest of the system consumes.
Direct Known Subclasses
Constant Summary collapse
- TYPE_MAP =
Maps Ruby symbol types to JSON Schema property fragments. Each value is merged into the generated property hash, so it may carry both
typeandformat(or any other JSON Schema keyword). { string: { "type" => "string" }, integer: { "type" => "integer" }, number: { "type" => "number" }, boolean: { "type" => "boolean" }, array: { "type" => "array" }, object: { "type" => "object" }, date: { "type" => "string", "format" => "date" }, datetime: { "type" => "string", "format" => "date-time" } }.freeze
- COERCERS =
Maps Ruby symbol types to a coercer lambda. Types not listed here pass their values through unchanged. Coercers receive the raw value (or nil) and return the coerced value. They must be total over the values JSON Schema validation would accept.
{ date: ->(v) { v.nil? || v.is_a?(Date) ? v : Date.parse(v.to_s) }, datetime: ->(v) { v.nil? || v.is_a?(Time) ? v : Time.parse(v.to_s) } }.freeze
Class Method Summary collapse
-
.coerce_args(args, params) ⇒ Object
Applies coercers to the raw argument hash.
-
.description(text = nil) ⇒ String?
Sets or retrieves the tool description.
-
.inherited(subclass) ⇒ Object
Ensures each subclass gets its own @params array so sibling classes do not share mutable state.
-
.param(name, type: :string, desc: nil, required: false, **options) ⇒ Object
Declares a parameter for the tool’s input schema.
-
.to_definition ⇒ VectorMCP::Definitions::Tool
Builds a
VectorMCP::Definitions::Toolstruct from the DSL metadata. -
.tool_name(name = nil) ⇒ String
Sets or retrieves the tool name.
Instance Method Summary collapse
-
#call(_args, _session) ⇒ Object
The handler method that subclasses must implement.
Class Method Details
.coerce_args(args, params) ⇒ Object
Applies coercers to the raw argument hash. Returns a new hash; does not mutate the original. Keys without a coercible type pass through. Keys that are absent from args stay absent — coercion only fires for keys actually present.
A parse failure on a client-supplied value is translated into VectorMCP::InvalidParamsError (JSON-RPC -32602) so the client sees a “bad request” response instead of a generic internal error. This is needed because the json-schema gem does not enforce format: date upstream (it does enforce format: date-time), so malformed :date values would otherwise crash inside Date.parse.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/vector_mcp/tool.rb', line 168 def self.coerce_args(args, params) coerced = args.dup params.each do |param| name = param[:name] next unless coerced.key?(name) coercer = COERCERS[param[:type]] next unless coercer begin coerced[name] = coercer.call(coerced[name]) rescue ArgumentError, TypeError => e # Date::Error < ArgumentError in Ruby 3.2+, so ArgumentError alone covers Date.parse failures. raise VectorMCP::InvalidParamsError.new( "Invalid #{param[:type]} value for param '#{name}': #{e.}", details: { param: name, type: param[:type], message: e. } ) end end coerced end |
.description(text = nil) ⇒ String?
Sets or retrieves the tool description.
80 81 82 83 84 85 86 |
# File 'lib/vector_mcp/tool.rb', line 80 def self.description(text = nil) if text @description = text else @description end end |
.inherited(subclass) ⇒ Object
Ensures each subclass gets its own @params array so sibling classes do not share mutable state.
56 57 58 59 |
# File 'lib/vector_mcp/tool.rb', line 56 def self.inherited(subclass) super subclass.instance_variable_set(:@params, []) end |
.param(name, type: :string, desc: nil, required: false, **options) ⇒ Object
Declares a parameter for the tool’s input schema.
95 96 97 98 99 100 101 102 103 |
# File 'lib/vector_mcp/tool.rb', line 95 def self.param(name, type: :string, desc: nil, required: false, **) @params << { name: name.to_s, type: type, desc: desc, required: required, options: } end |
.to_definition ⇒ VectorMCP::Definitions::Tool
Builds a VectorMCP::Definitions::Tool struct from the DSL metadata.
109 110 111 112 113 114 115 116 117 118 |
# File 'lib/vector_mcp/tool.rb', line 109 def self.to_definition validate_tool_class! VectorMCP::Definitions::Tool.new( tool_name, description, build_input_schema, build_handler ) end |
.tool_name(name = nil) ⇒ String
Sets or retrieves the tool name.
When called with an argument, stores the name. When called without, returns the stored name or derives one from the class name.
68 69 70 71 72 73 74 |
# File 'lib/vector_mcp/tool.rb', line 68 def self.tool_name(name = nil) if name @tool_name = name.to_s else @tool_name || derive_tool_name end end |
Instance Method Details
#call(_args, _session) ⇒ Object
The handler method that subclasses must implement.
125 126 127 |
# File 'lib/vector_mcp/tool.rb', line 125 def call(_args, _session) raise NotImplementedError, "#{self.class.name} must implement #call(args, session)" end |