Module: Legion::MCP::DynamicInjector

Extended by:
Logging::Helper
Defined in:
lib/legion/mcp/dynamic_injector.rb

Constant Summary collapse

MAX_INJECTED =
10

Class Method Summary collapse

Class Method Details

.active_tool_set(intent_string) ⇒ Object



36
37
38
39
40
# File 'lib/legion/mcp/dynamic_injector.rb', line 36

def active_tool_set(intent_string)
  always = always_loaded_classes
  injected = context_tools(intent_string)
  (always + injected).uniq(&:tool_name)
end

.always_loaded_classesObject



42
43
44
45
# File 'lib/legion/mcp/dynamic_injector.rb', line 42

def always_loaded_classes
  names = DeferredRegistry.always_loaded_tools
  Server.tool_registry.select { |tc| names.include?(tc.tool_name) }
end

.context_tools(intent_string) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/legion/mcp/dynamic_injector.rb', line 20

def context_tools(intent_string)
  return [] unless enabled?
  return [] if intent_string.nil? || intent_string.strip.empty?

  matches = ContextCompiler.match_tools(intent_string, limit: max_injected)
  return [] if matches.empty?

  always = DeferredRegistry.always_loaded_tools
  matches.filter_map do |match|
    next if always.include?(match[:name])
    next if match[:score] <= 0

    Server.tool_registry.find { |tc| tc.tool_name == match[:name] }
  end
end

.enabled?Boolean

Returns:

  • (Boolean)


12
13
14
# File 'lib/legion/mcp/dynamic_injector.rb', line 12

def enabled?
  Legion::Settings.dig(:mcp, :dynamic_tools, :enabled) == true
end

.inject_for_context(server, intent_string, previous_names: []) ⇒ Object



61
62
63
64
65
66
67
68
69
# File 'lib/legion/mcp/dynamic_injector.rb', line 61

def inject_for_context(server, intent_string, previous_names: [])
  return previous_names unless enabled?

  tools = active_tool_set(intent_string)
  current_names = tools.map(&:tool_name)

  notify_if_changed(server, previous_names, current_names)
  current_names
end

.max_injectedObject



16
17
18
# File 'lib/legion/mcp/dynamic_injector.rb', line 16

def max_injected
  Legion::Settings.dig(:mcp, :dynamic_tools, :max_injected) || MAX_INJECTED
end

.notify_if_changed(server, previous_names, current_names) ⇒ Object



51
52
53
54
55
56
57
58
59
# File 'lib/legion/mcp/dynamic_injector.rb', line 51

def notify_if_changed(server, previous_names, current_names)
  return unless tools_changed?(previous_names, current_names)
  return unless server.respond_to?(:notify_tools_list_changed)

  server.notify_tools_list_changed
rescue StandardError => e
  handle_exception(e, level: :debug, operation: 'legion.mcp.dynamic_injector.notify_if_changed')
  log.debug("DynamicInjector: notify failed: #{e.message}")
end

.tools_changed?(previous_names, current_names) ⇒ Boolean

Returns:

  • (Boolean)


47
48
49
# File 'lib/legion/mcp/dynamic_injector.rb', line 47

def tools_changed?(previous_names, current_names)
  previous_names.sort != current_names.sort
end