agent-harness 0.11.1 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf9a5083c42a6675255f4c0ea0516ab99473813020e3a875b02eeda98b937db8
4
- data.tar.gz: e070d74c397e02260d2994783c42124f45ac41b15a7c070834dd43c9c59e712a
3
+ metadata.gz: 50b5bc213cf4a1b6f9441a06a82c38210c7e6907eb085e6cadf71e305e4b7897
4
+ data.tar.gz: 9785ea0b1b35f5aa52528741ce070287f2d433235ffeaf3d6df0ab7337f486b0
5
5
  SHA512:
6
- metadata.gz: 7bce4c50dc634010ce8d7ac38c4adc661fdff51e2b055d9a585c0a7ef745f4a365a7aa9c68fedac63cfcbce7d7bea18f74a69b1622f2cde8fc5a6d38312ce2df
7
- data.tar.gz: cd9adee894f938a0bb104cd4648766f2b6b6f89e1080874436dd774f8313213bdea4d63d3fed0a81b7bddeca319c8e54a39588726fb40f724bb8d858a85314fc
6
+ metadata.gz: 2343d812d85375faad3a55e0462eb228003ff5eddc1920fd1edb75aedf381e5b86e3062c191ee64d24c39f245c1f27ded7d0e74247526727901b6b5391c2518a
7
+ data.tar.gz: cfe73ff0ffce00f5e0be1726b3dc28d0cdb73aab6546988c19b79846c1d16014476302f2d258d13bb703124edbf86066a96cd43044047ebacc81ad0cf5c853e5
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.11.1"
2
+ ".": "0.11.2"
3
3
  }
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.11.2](https://github.com/viamin/agent-harness/compare/agent-harness/v0.11.1...agent-harness/v0.11.2) (2026-04-27)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * 162: Support provider-agnostic MCP configuration ([#165](https://github.com/viamin/agent-harness/issues/165)) ([27f4814](https://github.com/viamin/agent-harness/commit/27f48146e99d8fdba0346235a3e5f19138266652))
9
+
3
10
  ## [0.11.1](https://github.com/viamin/agent-harness/compare/agent-harness/v0.11.0...agent-harness/v0.11.1) (2026-04-26)
4
11
 
5
12
 
@@ -78,6 +78,22 @@ module AgentHarness
78
78
  @custom_provider_classes[name.to_sym] = klass
79
79
  end
80
80
 
81
+ # Set MCP servers from an array of server definitions.
82
+ #
83
+ # @param servers [Array<Hash, McpServer>] server definitions
84
+ def mcp_servers=(servers)
85
+ normalized = McpConfigTranslator.normalize_servers(servers)
86
+ @mcp_servers = normalized.each_with_object({}) { |s, h| h[s.name.to_sym] = s }
87
+ end
88
+
89
+ # Load MCP server definitions from a configuration file.
90
+ #
91
+ # @param path [String] file path
92
+ def load_mcp_servers_file(path)
93
+ loaded = McpConfigLoader.load_file(path)
94
+ @mcp_servers = loaded.each_with_object({}) { |s, h| h[s.name.to_sym] = s }
95
+ end
96
+
81
97
  # Configure a provider-agnostic sub-agent definition.
82
98
  #
83
99
  # @param name [Symbol, String] sub-agent name
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "yaml"
5
+
6
+ module AgentHarness
7
+ class McpConfigLoader
8
+ ENV_VAR_PATTERN = /\$\{([A-Z0-9_]+)\}/
9
+
10
+ class << self
11
+ def load_file(path)
12
+ parsed = parse_file(path)
13
+ servers = parsed.is_a?(Hash) ? (parsed["servers"] || parsed[:servers] || parsed) : parsed
14
+
15
+ unless servers.is_a?(Array)
16
+ raise McpConfigurationError,
17
+ "MCP config file must contain a top-level servers array"
18
+ end
19
+
20
+ servers.map do |server|
21
+ McpServer.from_hash(interpolate_env(server))
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def parse_file(path)
28
+ ext = File.extname(path).downcase
29
+ content = File.read(path)
30
+
31
+ case ext
32
+ when ".json"
33
+ JSON.parse(content)
34
+ when ".yml", ".yaml"
35
+ YAML.safe_load(content, aliases: false) || {}
36
+ else
37
+ raise McpConfigurationError,
38
+ "Unsupported MCP config file format '#{ext}'. Use .json, .yml, or .yaml"
39
+ end
40
+ rescue Errno::ENOENT => e
41
+ raise McpConfigurationError, "MCP config file not found: #{e.message}"
42
+ rescue JSON::ParserError, Psych::SyntaxError => e
43
+ raise McpConfigurationError, "Failed to parse MCP config file: #{e.message}"
44
+ end
45
+
46
+ def interpolate_env(value)
47
+ case value
48
+ when Array
49
+ value.map { |entry| interpolate_env(entry) }
50
+ when Hash
51
+ value.each_with_object({}) do |(key, entry), memo|
52
+ memo[key] = interpolate_env(entry)
53
+ end
54
+ when String
55
+ value.gsub(ENV_VAR_PATTERN) { ENV.fetch(Regexp.last_match(1), "") }
56
+ else
57
+ value
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AgentHarness
4
+ module McpConfigTranslator
5
+ module_function
6
+
7
+ def for_provider(provider, mcp_servers)
8
+ servers = normalize_servers(mcp_servers)
9
+
10
+ case provider.to_sym
11
+ when :anthropic, :claude, :claude_code
12
+ translate_for_claude(servers)
13
+ when :codex
14
+ translate_for_codex(servers)
15
+ when :openai
16
+ translate_for_openai(servers)
17
+ else
18
+ servers.map(&:to_h)
19
+ end
20
+ end
21
+
22
+ def normalize_servers(mcp_servers)
23
+ Array(mcp_servers).map do |server|
24
+ case server
25
+ when McpServer
26
+ server
27
+ when Hash
28
+ McpServer.from_hash(server)
29
+ else
30
+ raise McpConfigurationError, "MCP server must be a Hash or McpServer, got #{server.class}"
31
+ end
32
+ end
33
+ end
34
+
35
+ def translate_for_claude(mcp_servers)
36
+ {
37
+ mcpServers: mcp_servers.each_with_object({}) do |server, memo|
38
+ entry = server.stdio? ? {command: server.command} : {url: server.url}
39
+ entry[:args] = server.args if server.stdio? && !server.args.empty?
40
+ entry[:env] = server.env unless server.env.empty?
41
+ entry[:headers] = server.headers if server.http? && !server.headers.empty?
42
+ memo[server.name] = entry
43
+ end
44
+ }
45
+ end
46
+
47
+ def translate_for_codex(mcp_servers)
48
+ {
49
+ mcp_servers: mcp_servers.each_with_object({}) do |server, memo|
50
+ entry = server.stdio? ? {command: server.command, transport: server.transport} : {url: server.url, transport: server.transport}
51
+ entry[:args] = server.args if server.stdio? && !server.args.empty?
52
+ entry[:env] = server.env unless server.env.empty?
53
+ entry[:headers] = server.headers if server.http? && !server.headers.empty?
54
+ memo[server.name] = entry
55
+ end
56
+ }
57
+ end
58
+
59
+ def translate_for_openai(mcp_servers)
60
+ mcp_servers.map do |server|
61
+ unless server.http?
62
+ raise McpTransportUnsupportedError.new(
63
+ "Provider 'openai' only supports remote MCP servers over HTTP/SSE (server: '#{server.name}')",
64
+ provider: :openai
65
+ )
66
+ end
67
+
68
+ unsupported_headers = server.headers.keys - ["Authorization"]
69
+ unless unsupported_headers.empty?
70
+ raise McpConfigurationError,
71
+ "OpenAI MCP translation only supports the Authorization header (server: '#{server.name}')"
72
+ end
73
+
74
+ tool = {
75
+ type: "mcp",
76
+ server_label: server.name,
77
+ server_url: server.url,
78
+ require_approval: "never"
79
+ }
80
+ tool[:authorization] = server.headers["Authorization"] if server.headers.key?("Authorization")
81
+ tool
82
+ end
83
+ end
84
+ end
85
+ end
@@ -10,7 +10,8 @@ module AgentHarness
10
10
  # McpServer.new(
11
11
  # name: "filesystem",
12
12
  # transport: "stdio",
13
- # command: ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
13
+ # command: "npx",
14
+ # args: ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
14
15
  # env: { "DEBUG" => "0" }
15
16
  # )
16
17
  #
@@ -23,21 +24,24 @@ module AgentHarness
23
24
  class McpServer
24
25
  VALID_TRANSPORTS = %w[stdio http sse].freeze
25
26
 
26
- attr_reader :name, :transport, :command, :args, :env, :url
27
+ attr_reader :name, :transport, :command, :args, :env, :url, :headers
27
28
 
28
29
  # @param name [String] unique name for this MCP server
29
30
  # @param transport [String] one of "stdio", "http", "sse"
30
- # @param command [Array<String>, nil] command to launch (stdio only)
31
+ # @param command [String, Array<String>, nil] executable to launch (stdio only).
32
+ # Arrays are accepted for backwards compatibility and normalized into
33
+ # +command+ plus +args+.
31
34
  # @param args [Array<String>, nil] additional args for the command
32
35
  # @param env [Hash<String,String>, nil] environment variables for the server process
33
36
  # @param url [String, nil] URL for HTTP/SSE transport
34
- def initialize(name:, transport:, command: nil, args: nil, env: nil, url: nil)
37
+ # @param headers [Hash<String,String>, nil] HTTP headers for remote MCP servers
38
+ def initialize(name:, transport:, command: nil, args: nil, env: nil, url: nil, headers: nil)
35
39
  @name = name
36
40
  @transport = transport.to_s
37
- @command = command
38
- @args = args || []
41
+ @command, @args = normalize_command_and_args(command, args)
39
42
  @env = env || {}
40
43
  @url = url
44
+ @headers = headers || {}
41
45
 
42
46
  validate!
43
47
  end
@@ -63,7 +67,8 @@ module AgentHarness
63
67
  command: hash[:command],
64
68
  args: hash[:args],
65
69
  env: hash[:env],
66
- url: hash[:url]
70
+ url: hash[:url],
71
+ headers: hash[:headers]
67
72
  )
68
73
  end
69
74
 
@@ -75,6 +80,12 @@ module AgentHarness
75
80
  %w[http sse].include?(@transport)
76
81
  end
77
82
 
83
+ def command_argv
84
+ return [] unless stdio?
85
+
86
+ [@command, *@args]
87
+ end
88
+
78
89
  # Check if the MCP server is reachable based on its transport type.
79
90
  #
80
91
  # For stdio servers, checks that a command is present.
@@ -101,6 +112,7 @@ module AgentHarness
101
112
  h[:args] = @args unless @args.empty?
102
113
  else
103
114
  h[:url] = @url
115
+ h[:headers] = @headers unless @headers.empty?
104
116
  end
105
117
  h[:env] = @env unless @env.empty?
106
118
  h
@@ -118,6 +130,7 @@ module AgentHarness
118
130
 
119
131
  validate_args!
120
132
  validate_env!
133
+ validate_headers!
121
134
  validate_stdio! if stdio?
122
135
  validate_http! if http?
123
136
  validate_no_stdio_only_fields_on_http! if http?
@@ -137,15 +150,17 @@ module AgentHarness
137
150
  "MCP server '#{@name}' env must be a Hash with String keys and values"
138
151
  end
139
152
 
140
- def validate_stdio!
141
- if @command.nil? || !@command.is_a?(Array) || @command.empty?
142
- raise McpConfigurationError,
143
- "MCP server '#{@name}' with stdio transport requires a non-empty command array"
144
- end
153
+ def validate_headers!
154
+ return if @headers.is_a?(Hash) && @headers.keys.all? { |k| k.is_a?(String) } && @headers.values.all? { |v| v.is_a?(String) }
145
155
 
146
- unless @command.all? { |c| c.is_a?(String) }
156
+ raise McpConfigurationError,
157
+ "MCP server '#{@name}' headers must be a Hash with String keys and values"
158
+ end
159
+
160
+ def validate_stdio!
161
+ if @command.nil? || !@command.is_a?(String) || @command.strip.empty?
147
162
  raise McpConfigurationError,
148
- "MCP server '#{@name}' command must contain only strings"
163
+ "MCP server '#{@name}' with stdio transport requires a non-empty command string"
149
164
  end
150
165
 
151
166
  return if @url.nil?
@@ -173,6 +188,17 @@ module AgentHarness
173
188
  "MCP server '#{@name}' with #{@transport} transport should not have args (args are only valid for stdio)"
174
189
  end
175
190
 
191
+ def normalize_command_and_args(command, args)
192
+ normalized_args = args || []
193
+ return [command, normalized_args] unless command.is_a?(Array)
194
+
195
+ unless normalized_args.is_a?(Array)
196
+ return [command.first, normalized_args]
197
+ end
198
+
199
+ [command.first, command[1..] + normalized_args]
200
+ end
201
+
176
202
  def http_ping_ok?(timeout: 5)
177
203
  require "net/http"
178
204
  uri = URI.parse(@url)
@@ -15,6 +15,7 @@ module AgentHarness
15
15
  # response = provider.send_message(prompt: "Hello!")
16
16
  class Anthropic < Base
17
17
  include RateLimitResetParsing
18
+ include McpConfigFileSupport
18
19
 
19
20
  # Model name pattern for Anthropic Claude models
20
21
  MODEL_PATTERN = /^claude-[\d.-]+-(?:opus|sonnet|haiku)(?:-\d{8})?$/i
@@ -756,85 +757,8 @@ module AgentHarness
756
757
  servers
757
758
  end
758
759
 
759
- def write_mcp_config_file(mcp_servers, working_dir: nil)
760
- require "tempfile"
761
- require "tmpdir"
762
- require "securerandom"
763
-
764
- config = build_claude_mcp_config(mcp_servers)
765
- config_json = JSON.generate(config)
766
-
767
- if @executor.is_a?(DockerCommandExecutor)
768
- # When running inside a Docker container, write the config file
769
- # inside the container so the CLI process can read it.
770
- # Track the path so cleanup_mcp_tempfiles! can remove it after execution.
771
- container_path = "/tmp/agent_harness_mcp_#{SecureRandom.hex(8)}.json"
772
- result = @executor.execute(
773
- ["sh", "-c", "cat > #{container_path}"],
774
- stdin_data: config_json,
775
- timeout: 5
776
- )
777
- unless result.success?
778
- raise McpConfigurationError,
779
- "Failed to write MCP config inside container: #{result.stderr}"
780
- end
781
-
782
- @mcp_docker_config_paths ||= []
783
- @mcp_docker_config_paths << container_path
784
-
785
- container_path
786
- else
787
- dir = working_dir || Dir.tmpdir
788
- file = Tempfile.new(["agent_harness_mcp_", ".json"], dir)
789
- file.write(config_json)
790
- file.close
791
-
792
- # Hold a reference so the Tempfile is not garbage-collected (and
793
- # therefore deleted) before the CLI process reads it.
794
- # Cleaned up by cleanup_mcp_tempfiles! after execution.
795
- @mcp_config_tempfiles ||= []
796
- @mcp_config_tempfiles << file
797
-
798
- file.path
799
- end
800
- end
801
-
802
- def build_claude_mcp_config(mcp_servers)
803
- servers = {}
804
- mcp_servers.each do |server|
805
- h = if server.stdio?
806
- entry = {command: server.command.first}
807
- remaining_args = server.command[1..] + server.args
808
- entry[:args] = remaining_args unless remaining_args.empty?
809
- entry
810
- else
811
- {url: server.url}
812
- end
813
- h[:env] = server.env unless server.env.empty?
814
- servers[server.name] = h
815
- end
816
- {mcpServers: servers}
817
- end
818
-
819
- def cleanup_mcp_tempfiles!
820
- if @mcp_config_tempfiles
821
- @mcp_config_tempfiles.each do |file|
822
- file.close unless file.closed?
823
- file.unlink
824
- rescue
825
- nil
826
- end
827
- @mcp_config_tempfiles = nil
828
- end
829
-
830
- if @mcp_docker_config_paths
831
- @mcp_docker_config_paths.each do |path|
832
- @executor.execute(["rm", "-f", path], timeout: 5)
833
- rescue
834
- nil
835
- end
836
- @mcp_docker_config_paths = nil
837
- end
760
+ def mcp_provider_key
761
+ :anthropic
838
762
  end
839
763
 
840
764
  def build_tool_control_flags(tools_option, skip_permission_mode: false)
@@ -419,7 +419,13 @@ module AgentHarness
419
419
  end
420
420
 
421
421
  def normalize_mcp_servers(options)
422
- servers = options[:mcp_servers]
422
+ if options.key?(:mcp_servers)
423
+ servers = options[:mcp_servers]
424
+ else
425
+ # Configuration stores mcp_servers as a Hash keyed by name; extract values.
426
+ config_servers = AgentHarness.configuration.mcp_servers
427
+ servers = config_servers.is_a?(Hash) ? config_servers.values : config_servers
428
+ end
423
429
  return options if servers.nil?
424
430
 
425
431
  unless servers.is_a?(Array)
@@ -9,6 +9,7 @@ module AgentHarness
9
9
  # Provides integration with the OpenAI Codex CLI tool.
10
10
  class Codex < Base
11
11
  include RateLimitResetParsing
12
+ include McpConfigFileSupport
12
13
 
13
14
  SUPPORTED_CLI_VERSION = "0.116.0"
14
15
  SUPPORTED_CLI_REQUIREMENT = Gem::Requirement.new(">= #{SUPPORTED_CLI_VERSION}", "< 0.117.0").freeze
@@ -186,7 +187,7 @@ module AgentHarness
186
187
  vision: false,
187
188
  tool_use: true,
188
189
  json_mode: false,
189
- mcp: false,
190
+ mcp: true,
190
191
  dangerous_mode: true
191
192
  }
192
193
  end
@@ -199,6 +200,27 @@ module AgentHarness
199
200
 
200
201
  def cli_env_overrides = {"PAID_CODEX_SUBSCRIPTION_AUTH" => "1"}
201
202
 
203
+ def send_message(prompt:, **options)
204
+ super
205
+ ensure
206
+ cleanup_mcp_tempfiles!
207
+ end
208
+
209
+ def supports_mcp?
210
+ true
211
+ end
212
+
213
+ def supported_mcp_transports
214
+ %w[stdio http sse]
215
+ end
216
+
217
+ def build_mcp_flags(mcp_servers, working_dir: nil)
218
+ return [] if mcp_servers.empty?
219
+
220
+ config_path = write_mcp_config_file(mcp_servers, working_dir: working_dir)
221
+ ["--mcp-config", config_path]
222
+ end
223
+
202
224
  def test_command_overrides
203
225
  ["--skip-git-repo-check", "--output-last-message"]
204
226
  end
@@ -449,6 +471,11 @@ module AgentHarness
449
471
  cmd += sandbox_bypass_flags
450
472
  end
451
473
 
474
+ # Add MCP server flags (validated/normalized by Base#send_message)
475
+ if options[:mcp_servers]&.any?
476
+ cmd += build_mcp_flags(options[:mcp_servers])
477
+ end
478
+
452
479
  if options[:session]
453
480
  cmd += session_flags(options[:session])
454
481
  end
@@ -1259,6 +1286,10 @@ module AgentHarness
1259
1286
  config_dir = ENV["CODEX_CONFIG_DIR"] || File.expand_path("~/.codex")
1260
1287
  File.join(config_dir, "config.json")
1261
1288
  end
1289
+
1290
+ def mcp_provider_key
1291
+ :codex
1292
+ end
1262
1293
  end
1263
1294
  end
1264
1295
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AgentHarness
4
+ module Providers
5
+ # Shared concern for writing and cleaning up MCP configuration tempfiles.
6
+ #
7
+ # Include this module in any provider that needs to write MCP config files
8
+ # for CLI processes. The including class must define an +mcp_provider_key+
9
+ # method that returns the symbol passed to +McpConfigTranslator.for_provider+.
10
+ module McpConfigFileSupport
11
+ def write_mcp_config_file(mcp_servers, working_dir: nil)
12
+ require "tempfile"
13
+ require "tmpdir"
14
+ require "securerandom"
15
+
16
+ config = McpConfigTranslator.for_provider(mcp_provider_key, mcp_servers)
17
+ config_json = JSON.generate(config)
18
+
19
+ if @executor.is_a?(DockerCommandExecutor)
20
+ # When running inside a Docker container, write the config file
21
+ # inside the container so the CLI process can read it.
22
+ # Track the path so cleanup_mcp_tempfiles! can remove it after execution.
23
+ container_path = "/tmp/agent_harness_mcp_#{SecureRandom.hex(8)}.json"
24
+ result = @executor.execute(
25
+ ["sh", "-c", "cat > #{container_path}"],
26
+ stdin_data: config_json,
27
+ timeout: 5
28
+ )
29
+ unless result.success?
30
+ raise McpConfigurationError,
31
+ "Failed to write MCP config inside container: #{result.stderr}"
32
+ end
33
+
34
+ @mcp_docker_config_paths ||= []
35
+ @mcp_docker_config_paths << container_path
36
+
37
+ container_path
38
+ else
39
+ dir = working_dir || Dir.tmpdir
40
+ file = Tempfile.new(["agent_harness_mcp_", ".json"], dir)
41
+ file.write(config_json)
42
+ file.close
43
+
44
+ # Hold a reference so the Tempfile is not garbage-collected (and
45
+ # therefore deleted) before the CLI process reads it.
46
+ # Cleaned up by cleanup_mcp_tempfiles! after execution.
47
+ @mcp_config_tempfiles ||= []
48
+ @mcp_config_tempfiles << file
49
+
50
+ file.path
51
+ end
52
+ end
53
+
54
+ def cleanup_mcp_tempfiles!
55
+ if @mcp_config_tempfiles
56
+ @mcp_config_tempfiles.each do |file|
57
+ file.close unless file.closed?
58
+ file.unlink
59
+ rescue
60
+ nil
61
+ end
62
+ @mcp_config_tempfiles = nil
63
+ end
64
+
65
+ if @mcp_docker_config_paths
66
+ @mcp_docker_config_paths.each do |path|
67
+ @executor.execute(["rm", "-f", path], timeout: 5)
68
+ rescue
69
+ nil
70
+ end
71
+ @mcp_docker_config_paths = nil
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AgentHarness
4
- VERSION = "0.11.1"
4
+ VERSION = "0.11.2"
5
5
  end
data/lib/agent_harness.rb CHANGED
@@ -278,6 +278,8 @@ end
278
278
  # Core components
279
279
  require_relative "agent_harness/errors"
280
280
  require_relative "agent_harness/mcp_server"
281
+ require_relative "agent_harness/mcp_config_loader"
282
+ require_relative "agent_harness/mcp_config_translator"
281
283
  require_relative "agent_harness/sub_agent_config"
282
284
  require_relative "agent_harness/sub_agent_file_loader"
283
285
  require_relative "agent_harness/sub_agent_translator"
@@ -301,6 +303,7 @@ require_relative "agent_harness/providers/adapter"
301
303
  require_relative "agent_harness/providers/base"
302
304
  require_relative "agent_harness/providers/token_usage_parsing"
303
305
  require_relative "agent_harness/providers/rate_limit_reset_parsing"
306
+ require_relative "agent_harness/providers/mcp_config_file_support"
304
307
  require_relative "agent_harness/providers/anthropic"
305
308
  require_relative "agent_harness/providers/aider"
306
309
  require_relative "agent_harness/providers/codex"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: agent-harness
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.1
4
+ version: 0.11.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bart Agapinan
@@ -107,6 +107,8 @@ files:
107
107
  - lib/agent_harness/error_taxonomy.rb
108
108
  - lib/agent_harness/errors.rb
109
109
  - lib/agent_harness/execution_preparation.rb
110
+ - lib/agent_harness/mcp_config_loader.rb
111
+ - lib/agent_harness/mcp_config_translator.rb
110
112
  - lib/agent_harness/mcp_server.rb
111
113
  - lib/agent_harness/openai_compatible_transport.rb
112
114
  - lib/agent_harness/orchestration/circuit_breaker.rb
@@ -126,6 +128,7 @@ files:
126
128
  - lib/agent_harness/providers/gemini.rb
127
129
  - lib/agent_harness/providers/github_copilot.rb
128
130
  - lib/agent_harness/providers/kilocode.rb
131
+ - lib/agent_harness/providers/mcp_config_file_support.rb
129
132
  - lib/agent_harness/providers/mistral_vibe.rb
130
133
  - lib/agent_harness/providers/opencode.rb
131
134
  - lib/agent_harness/providers/rate_limit_reset_parsing.rb