Class: SwarmSDK::Swarm::McpConfigurator

Inherits:
Object
  • Object
show all
Defined in:
lib/swarm_sdk/swarm/mcp_configurator.rb

Overview

Handles MCP (Model Context Protocol) server configuration and client management

Responsibilities:

  • Register MCP servers for agents
  • Initialize MCP clients (stdio, SSE, streamable transports)
  • Build transport-specific configurations
  • Track clients for cleanup

This encapsulates all MCP-related logic that was previously in Swarm.

Instance Method Summary collapse

Constructor Details

#initialize(swarm) ⇒ McpConfigurator

Returns a new instance of McpConfigurator.



15
16
17
18
# File 'lib/swarm_sdk/swarm/mcp_configurator.rb', line 15

def initialize(swarm)
  @swarm = swarm
  @mcp_clients = swarm.mcp_clients
end

Instance Method Details

#build_transport_config(transport_type, config) ⇒ Hash

Build transport-specific configuration for MCP client

This method is public for testing delegation from Swarm.

Parameters:

  • transport_type (Symbol)

    Transport type (:stdio, :sse, :streamable)

  • config (Hash)

    MCP server configuration

Returns:

  • (Hash)

    Transport-specific configuration



112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/swarm_sdk/swarm/mcp_configurator.rb', line 112

def build_transport_config(transport_type, config)
  case transport_type
  when :stdio
    build_stdio_config(config)
  when :sse
    build_sse_config(config)
  when :streamable
    build_streamable_config(config)
  else
    raise ArgumentError, "Unsupported transport type: #{transport_type}"
  end
end

#register_mcp_servers(chat, mcp_server_configs, agent_name:) ⇒ Object

Register MCP servers for an agent

Connects to MCP servers and registers their tools with the agent's chat instance. Supports stdio, SSE, and HTTP (streamable) transports.

Boot Optimization (Plan 025)

  • If tools specified: Create stubs without tools/list RPC (fast boot, lazy schema)
  • If tools omitted: Call tools/list to discover all tools (discovery mode)

Examples:

Fast boot mode

mcp_server :codebase, type: :stdio, command: "mcp-server", tools: [:search, :list]
# Creates tool stubs instantly, no tools/list RPC

Discovery mode

mcp_server :codebase, type: :stdio, command: "mcp-server"
# Calls tools/list to discover all available tools

Parameters:

  • chat (AgentChat)

    The agent's chat instance

  • mcp_server_configs (Array<Hash>)

    MCP server configurations

  • agent_name (Symbol)

    Agent name for tracking clients



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/swarm_sdk/swarm/mcp_configurator.rb', line 41

def register_mcp_servers(chat, mcp_server_configs, agent_name:)
  return if mcp_server_configs.nil? || mcp_server_configs.empty?

  # Ensure MCP logging is configured before creating clients
  Swarm.apply_mcp_logging_configuration

  mcp_server_configs.each do |server_config|
    tools_config = server_config[:tools]
    mode = tools_config.nil? ? :discovery : :optimized

    # Emit event before initialization
    emit_mcp_init_start(agent_name, server_config, mode)

    client = initialize_mcp_client(server_config)

    # Store client for cleanup
    @mcp_clients[agent_name] << client

    if tools_config.nil?
      # Discovery mode: Fetch all tools from server (calls tools/list)
      # client.tools returns RubyLLM::Tool instances (already wrapped by internal Coordinator)
      all_tools = client.tools
      tool_names = all_tools.map { |t| t.respond_to?(:name) ? t.name : t.to_s }

      all_tools.each do |tool|
        chat.tool_registry.register(
          tool,
          source: :mcp,
          metadata: { server_name: server_config[:name] },
        )
      end

      # Emit completion event for discovery mode
      emit_mcp_init_complete(agent_name, server_config, mode, all_tools.size, tool_names)
      RubyLLM.logger.debug("SwarmSDK: Discovered and registered #{all_tools.size} tools from MCP server '#{server_config[:name]}'")
    else
      # Optimized mode: Create tool stubs without tools/list RPC (Plan 025)
      # Use client directly (it has internal coordinator)
      tool_names = tools_config.map(&:to_s)

      tools_config.each do |tool_name|
        stub = Tools::McpToolStub.new(
          client: client,
          name: tool_name.to_s,
          server_name: server_config[:name],
        )
        chat.tool_registry.register(
          stub,
          source: :mcp,
          metadata: { server_name: server_config[:name] },
        )
      end

      # Emit completion event for optimized mode
      emit_mcp_init_complete(agent_name, server_config, mode, tools_config.size, tool_names)
      RubyLLM.logger.debug("SwarmSDK: Registered #{tools_config.size} tool stubs from MCP server '#{server_config[:name]}' (lazy schema)")
    end
  rescue StandardError => e
    RubyLLM.logger.error("SwarmSDK: Failed to initialize MCP server '#{server_config[:name]}' for agent #{agent_name}: #{e.class.name}: #{e.message}")
    RubyLLM.logger.error("SwarmSDK: Backtrace: #{e.backtrace.first(5).join("\n  ")}")
    raise ConfigurationError, "Failed to initialize MCP server '#{server_config[:name]}': #{e.message}"
  end
end