Class: Legate::Mcp::ConnectionManager

Inherits:
Object
  • Object
show all
Defined in:
lib/legate/mcp/connection_manager.rb

Overview

Owns an agent’s MCP client connections: connecting to configured servers, discovering and registering their tools into the agent’s tool registry, and disconnecting. Extracted from Legate::Agent to keep MCP lifecycle out of the agent’s core responsibilities.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tool_registry:, selected_tool_names:, agent_name:) ⇒ ConnectionManager

Returns a new instance of ConnectionManager.

Parameters:

  • tool_registry (Legate::ToolRegistry)

    the agent’s registry that MCP tools register into

  • selected_tool_names (Array<Symbol>)

    tool names the agent selected (others are skipped)

  • agent_name (Symbol, String)

    for log context



19
20
21
22
23
24
# File 'lib/legate/mcp/connection_manager.rb', line 19

def initialize(tool_registry:, selected_tool_names:, agent_name:)
  @tool_registry = tool_registry
  @selected_tool_names = selected_tool_names
  @agent_name = agent_name
  @clients = []
end

Instance Attribute Details

#clientsObject (readonly)

Returns the value of attribute clients.



14
15
16
# File 'lib/legate/mcp/connection_manager.rb', line 14

def clients
  @clients
end

Instance Method Details

#connect(servers_config) ⇒ Object

Connects to each configured MCP server and registers its selected tools.

Parameters:

  • servers_config (Array<Hash>, nil)

    server configs from the definition



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/legate/mcp/connection_manager.rb', line 28

def connect(servers_config)
  return if servers_config.nil? || servers_config.empty?

  servers_config.each do |config|
    # Transform keys to symbols for the client
    symbolized_config = config.transform_keys(&:to_sym)
    Legate.logger.info("Attempting to connect to MCP server: #{symbolized_config.inspect}")
    begin
      unless %w[stdio sse].include?(symbolized_config[:type])
        Legate.logger.error("Unsupported MCP server type specified: #{symbolized_config[:type].inspect}. Skipping configuration: #{symbolized_config.inspect}")
        next # Skip to the next server config
      end

      # Explicitly convert known string type values to symbols
      if symbolized_config[:type] == 'stdio'
        symbolized_config[:type] = :stdio
      elsif symbolized_config[:type] == 'sse'
        symbolized_config[:type] = :sse
      end
      # Pass the modified hash
      client = Legate::Mcp::Client.new(symbolized_config)
      client.connect # This performs handshake and gets capabilities
      @clients << client
      discover_and_register_tools(client)
    rescue Legate::Mcp::ConnectionError, Legate::Mcp::ProtocolError => e # More specific MCP errors
      Legate.logger.error("Failed to connect or handshake with MCP server #{config.inspect}: #{e.message}")
    rescue Legate::Mcp::Error => e
      Legate.logger.error("MCP-related error connecting to server #{config.inspect}: #{e.message}")
    rescue StandardError => e
      Legate.logger.error("Unexpected error connecting to MCP server #{config.inspect}: #{e.class} - #{e.message}")
    end
  end
end

#disconnectObject

Disconnects all active MCP clients.



63
64
65
66
67
68
69
70
71
72
73
# File 'lib/legate/mcp/connection_manager.rb', line 63

def disconnect
  return if @clients.nil? || @clients.empty?

  @clients.each do |client|
    Legate.logger.info('Disconnecting MCP client...')
    client.disconnect
  rescue StandardError => e
    Legate.logger.error("Error disconnecting MCP client: #{e.message}")
  end
  @clients.clear
end