Class: RailsAiContext::CLI::ToolRunner

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_ai_context/cli/tool_runner.rb

Overview

Runs MCP tools from the command line without requiring an MCP client. Reads tool schemas at runtime — no hardcoded parameter lists.

Usage:

runner = ToolRunner.new("schema", ["--table", "users", "--detail", "full"])
puts runner.run

runner = ToolRunner.new("schema", { table: "users", detail: "full" })
puts runner.run

Defined Under Namespace

Classes: InvalidArgumentError, ToolNotFoundError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tool_name, raw_args, json_mode: false) ⇒ ToolRunner

Returns a new instance of ToolRunner.



20
21
22
23
24
# File 'lib/rails_ai_context/cli/tool_runner.rb', line 20

def initialize(tool_name, raw_args, json_mode: false)
  @tool_class = resolve_tool(tool_name)
  @raw_args = raw_args
  @json_mode = json_mode
end

Instance Attribute Details

#json_modeObject (readonly)

Returns the value of attribute json_mode.



18
19
20
# File 'lib/rails_ai_context/cli/tool_runner.rb', line 18

def json_mode
  @json_mode
end

#raw_argsObject (readonly)

Returns the value of attribute raw_args.



18
19
20
# File 'lib/rails_ai_context/cli/tool_runner.rb', line 18

def raw_args
  @raw_args
end

#tool_classObject (readonly)

Returns the value of attribute tool_class.



18
19
20
# File 'lib/rails_ai_context/cli/tool_runner.rb', line 18

def tool_class
  @tool_class
end

Class Method Details

.available_toolsObject

Filtered tool list respecting skip_tools config.



49
50
51
52
53
54
55
# File 'lib/rails_ai_context/cli/tool_runner.rb', line 49

def self.available_tools
  skip = RailsAiContext.configuration.skip_tools
  tools = Server.builtin_tools
  tools += RailsAiContext.configuration.custom_tools
  return tools if skip.empty?
  tools.reject { |t| skip.include?(t.tool_name) }
end

.short_name(tool_name) ⇒ Object

Derive short name: rails_get_schema → schema, rails_analyze_feature → analyze_feature



90
91
92
# File 'lib/rails_ai_context/cli/tool_runner.rb', line 90

def self.short_name(tool_name)
  tool_name.sub(/\Arails_get_/, "").sub(/\Arails_/, "")
end

.tool_help(tool_class) ⇒ Object

Generate help for a specific tool from its input_schema.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/rails_ai_context/cli/tool_runner.rb', line 58

def self.tool_help(tool_class)
  schema = tool_class.input_schema_value&.schema || {}
  properties = schema[:properties] || {}
  required = schema[:required] || []

  lines = [
    "#{tool_class.tool_name}#{tool_class.description_value}",
    "",
    "Usage:",
    "  rails 'ai:tool[#{short_name(tool_class.tool_name)}]' #{properties.keys.map { |k| "#{k}=VALUE" }.join(' ')}",
    "  rails-ai-context tool #{short_name(tool_class.tool_name)} #{properties.keys.map { |k| "--#{k.to_s.tr('_', '-')} VALUE" }.join(' ')}",
    ""
  ]

  if properties.any?
    lines << "Options:"
    properties.each do |name, prop|
      flag = "--#{name.to_s.tr('_', '-')}"
      type_hint = prop[:type] || "string"
      type_hint = "#{type_hint} (#{prop[:enum].join('/')})" if prop[:enum]
      req = required.include?(name.to_s) ? " [required]" : ""
      desc = prop[:description] || ""
      lines << "  #{flag.ljust(24)} #{desc} (#{type_hint})#{req}"
    end
  else
    lines << "  No parameters."
  end

  lines.join("\n")
end

.tool_listObject

List all available tools with short names and descriptions.



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/rails_ai_context/cli/tool_runner.rb', line 35

def self.tool_list
  lines = [ "Available tools:", "" ]
  available_tools.each do |tool|
    short = short_name(tool.tool_name)
    desc = tool.description_value.to_s[0..79]
    lines << "  #{short.ljust(24)} #{desc}"
  end
  lines << ""
  lines << "Usage: rails 'ai:tool[NAME]' param=value"
  lines << "       rails-ai-context tool NAME --param value"
  lines.join("\n")
end

Instance Method Details

#runObject



26
27
28
29
30
31
32
# File 'lib/rails_ai_context/cli/tool_runner.rb', line 26

def run
  kwargs = build_kwargs
  schema = tool_schema
  validate_kwargs!(kwargs, schema)
  response = tool_class.call(**kwargs)
  extract_output(response)
end