Class: AgentHarness::McpServer

Inherits:
Object
  • Object
show all
Defined in:
lib/agent_harness/mcp_server.rb

Overview

Canonical representation of an MCP server for request-time execution.

Provider-agnostic value object that can be translated by each provider adapter into its CLI-specific configuration.

Examples:

stdio server

McpServer.new(
  name: "filesystem",
  transport: "stdio",
  command: "npx",
  args: ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
  env: { "DEBUG" => "0" }
)

HTTP/URL server

McpServer.new(
  name: "playwright",
  transport: "http",
  url: "http://mcp-playwright:3000/mcp"
)

Constant Summary collapse

VALID_TRANSPORTS =
%w[stdio http sse].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name:, transport:, command: nil, args: nil, env: nil, url: nil, headers: nil) ⇒ McpServer

Returns a new instance of McpServer.

Parameters:

  • name (String)

    unique name for this MCP server

  • transport (String)

    one of “stdio”, “http”, “sse”

  • command (String, Array<String>, nil) (defaults to: nil)

    executable to launch (stdio only). Arrays are accepted for backwards compatibility and normalized into command plus args.

  • args (Array<String>, nil) (defaults to: nil)

    additional args for the command

  • env (Hash<String,String>, nil) (defaults to: nil)

    environment variables for the server process

  • url (String, nil) (defaults to: nil)

    URL for HTTP/SSE transport

  • headers (Hash<String,String>, nil) (defaults to: nil)

    HTTP headers for remote MCP servers



38
39
40
41
42
43
44
45
46
47
# File 'lib/agent_harness/mcp_server.rb', line 38

def initialize(name:, transport:, command: nil, args: nil, env: nil, url: nil, headers: nil)
  @name = name
  @transport = transport.to_s
  @command, @args = normalize_command_and_args(command, args)
  @env = env || {}
  @url = url
  @headers = headers || {}

  validate!
end

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args.



27
28
29
# File 'lib/agent_harness/mcp_server.rb', line 27

def args
  @args
end

#commandObject (readonly)

Returns the value of attribute command.



27
28
29
# File 'lib/agent_harness/mcp_server.rb', line 27

def command
  @command
end

#envObject (readonly)

Returns the value of attribute env.



27
28
29
# File 'lib/agent_harness/mcp_server.rb', line 27

def env
  @env
end

#headersObject (readonly)

Returns the value of attribute headers.



27
28
29
# File 'lib/agent_harness/mcp_server.rb', line 27

def headers
  @headers
end

#nameObject (readonly)

Returns the value of attribute name.



27
28
29
# File 'lib/agent_harness/mcp_server.rb', line 27

def name
  @name
end

#transportObject (readonly)

Returns the value of attribute transport.



27
28
29
# File 'lib/agent_harness/mcp_server.rb', line 27

def transport
  @transport
end

#urlObject (readonly)

Returns the value of attribute url.



27
28
29
# File 'lib/agent_harness/mcp_server.rb', line 27

def url
  @url
end

Class Method Details

.from_hash(hash) ⇒ McpServer

Build from a plain Hash (e.g. from user input or serialized config)

Parameters:

  • hash (Hash)

    server definition

Returns:



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/agent_harness/mcp_server.rb', line 53

def self.from_hash(hash)
  unless hash.is_a?(Hash)
    raise McpConfigurationError, "MCP server definition must be a Hash, got #{hash.class}"
  end

  begin
    hash = hash.transform_keys(&:to_sym)
  rescue NoMethodError, TypeError => e
    raise McpConfigurationError, "MCP server hash contains invalid keys: #{e.message}"
  end

  new(
    name: hash[:name],
    transport: hash[:transport],
    command: hash[:command],
    args: hash[:args],
    env: hash[:env],
    url: hash[:url],
    headers: hash[:headers]
  )
end

Instance Method Details

#command_argvObject



83
84
85
86
87
# File 'lib/agent_harness/mcp_server.rb', line 83

def command_argv
  return [] unless stdio?

  [@command, *@args]
end

#http?Boolean

Returns:

  • (Boolean)


79
80
81
# File 'lib/agent_harness/mcp_server.rb', line 79

def http?
  %w[http sse].include?(@transport)
end

#reachable?(timeout: 5) ⇒ Boolean

Check if the MCP server is reachable based on its transport type.

For stdio servers, checks that a command is present. For HTTP/SSE servers, checks that a URL is present and the server responds to an HTTP HEAD request.

Parameters:

  • timeout (Integer) (defaults to: 5)

    HTTP request timeout in seconds (default: 5)

Returns:

  • (Boolean)


97
98
99
100
101
102
103
104
105
106
# File 'lib/agent_harness/mcp_server.rb', line 97

def reachable?(timeout: 5)
  case transport
  when "stdio"
    !command.nil? && !command.empty?
  when "http", "sse"
    !url.nil? && !url.to_s.strip.empty? && http_ping_ok?(timeout: timeout)
  else
    false
  end
end

#stdio?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/agent_harness/mcp_server.rb', line 75

def stdio?
  @transport == "stdio"
end

#to_hObject



108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/agent_harness/mcp_server.rb', line 108

def to_h
  h = {name: @name, transport: @transport}
  if stdio?
    h[:command] = @command
    h[:args] = @args unless @args.empty?
  else
    h[:url] = @url
    h[:headers] = @headers unless @headers.empty?
  end
  h[:env] = @env unless @env.empty?
  h
end