# frozen_string_literal: true require "test_helper" module MCP class ConfigurationTest < ActiveSupport::TestCase test "initializes with a default no-op exception reporter" do config = Configuration.new assert_respond_to config, :exception_reporter # The default reporter should be callable but do nothing exception = StandardError.new("test error") server_context = { test: "context" } assert_nothing_raised do config.exception_reporter.call(exception, server_context) end end test "allows setting a custom exception reporter" do config = Configuration.new reported_exception = nil reported_context = nil config.exception_reporter = ->(exception, server_context) do reported_exception = exception reported_context = server_context end test_exception = StandardError.new("test error") test_context = { foo: "bar" } config.exception_reporter.call(test_exception, test_context) assert_equal test_exception, reported_exception assert_equal test_context, reported_context end # https://github.com/modelcontextprotocol/modelcontextprotocol/blob/14ec41c/schema/draft/schema.ts#L15 test "initializes with default protocol version" do config = Configuration.new assert_equal Configuration::LATEST_STABLE_PROTOCOL_VERSION, config.protocol_version end test "uses the draft protocol version when protocol_version is set to nil" do config = Configuration.new(protocol_version: nil) assert_equal Configuration::LATEST_STABLE_PROTOCOL_VERSION, config.protocol_version end test "raises ArgumentError when setting the draft protocol version" do exception = assert_raises(ArgumentError) do # DRAFT-2025-v3 is the latest draft protocol version: # https://github.com/modelcontextprotocol/modelcontextprotocol/blob/14ec41c/schema/draft/schema.ts#L15 Configuration.new(protocol_version: "DRAFT-2025-v3") end assert_equal("protocol_version must be 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26, or 2024-11-05", exception.message) end test "raises ArgumentError when protocol_version is not a supported protocol version" do config = Configuration.new exception = assert_raises(ArgumentError) do custom_version = "2025-03-27" config.protocol_version = custom_version end assert_equal("protocol_version must be 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26, or 2024-11-05", exception.message) end test "exposes the SEP-2575 modern protocol versions" do assert_equal "2026-07-28", Configuration::LATEST_MODERN_PROTOCOL_VERSION assert_equal ["2026-07-28"], Configuration::SUPPORTED_MODERN_PROTOCOL_VERSIONS assert Configuration.modern_protocol_version?("2026-07-28") refute Configuration.modern_protocol_version?("2025-11-25") end test "accepts 2026-07-28 as the protocol version" do # 2026-07-28 serves both lifecycles of the dual-era model (SEP-2575), so it is negotiable through # the legacy `initialize` handshake and settable as the fallback version. config = Configuration.new(protocol_version: Configuration::LATEST_MODERN_PROTOCOL_VERSION) assert_equal "2026-07-28", config.protocol_version end test "raises ArgumentError when protocol_version is not a boolean value" do config = Configuration.new exception = assert_raises(ArgumentError) do config.validate_tool_call_arguments = "true" end assert_equal("validate_tool_call_arguments must be a boolean", exception.message) end test "raises ArgumentError when validate_tool_call_results is not a boolean value" do config = Configuration.new exception = assert_raises(ArgumentError) do config.validate_tool_call_results = "true" end assert_equal("validate_tool_call_results must be a boolean", exception.message) end test "merges protocol version from other configuration" do config1 = Configuration.new(protocol_version: "2025-03-26") config2 = Configuration.new(protocol_version: "2025-06-18") config3 = Configuration.new merged = config1.merge(config2) assert_equal "2025-06-18", merged.protocol_version merged = config1.merge(config3) assert_equal "2025-03-26", merged.protocol_version merged = config3.merge(config1) assert_equal "2025-03-26", merged.protocol_version end test "defaults validate_tool_call_arguments to true" do config = Configuration.new assert config.validate_tool_call_arguments end test "can set validate_tool_call_arguments to false" do config = Configuration.new(validate_tool_call_arguments: false) refute config.validate_tool_call_arguments end test "validate_tool_call_arguments? returns false when set" do config = Configuration.new(validate_tool_call_arguments: false) refute config.validate_tool_call_arguments? end test "validate_tool_call_arguments? returns true when not set" do config = Configuration.new assert config.validate_tool_call_arguments? end test "merge preserves validate_tool_call_arguments from other config" do config1 = Configuration.new(validate_tool_call_arguments: false) config2 = Configuration.new merged = config1.merge(config2) assert merged.validate_tool_call_arguments? end test "merge preserves validate_tool_call_arguments from self when other not set" do config1 = Configuration.new(validate_tool_call_arguments: false) config2 = Configuration.new merged = config2.merge(config1) refute merged.validate_tool_call_arguments end test "defaults validate_tool_call_results to false" do config = Configuration.new refute config.validate_tool_call_results end test "can set validate_tool_call_results to true" do config = Configuration.new(validate_tool_call_results: true) assert config.validate_tool_call_results end test "validate_tool_call_results? returns false when not set" do config = Configuration.new refute config.validate_tool_call_results? end test "validate_tool_call_results? returns true when set" do config = Configuration.new(validate_tool_call_results: true) assert config.validate_tool_call_results? end test "merge preserves validate_tool_call_results from other config" do config1 = Configuration.new(validate_tool_call_results: true) config2 = Configuration.new merged = config1.merge(config2) refute merged.validate_tool_call_results? end test "merge preserves validate_tool_call_results from self when other set" do config1 = Configuration.new(validate_tool_call_results: true) config2 = Configuration.new merged = config2.merge(config1) assert merged.validate_tool_call_results end test "initializes with a default pass-through around_request" do config = Configuration.new called = false config.around_request.call({}) { called = true } assert called end test "allows setting a custom around_request" do config = Configuration.new call_log = [] config.around_request = ->(_data, &request_handler) { call_log << :before request_handler.call call_log << :after } config.around_request.call({}) { call_log << :execute } assert_equal([:before, :execute, :after], call_log) end test "around_request? returns false by default" do config = Configuration.new refute config.around_request? end test "around_request? returns true when set" do config = Configuration.new config.around_request = ->(_data, &request_handler) { request_handler.call } assert config.around_request? end test "merge preserves around_request from other config" do custom = ->(_data, &request_handler) { request_handler.call } config1 = Configuration.new config2 = Configuration.new(around_request: custom) merged = config1.merge(config2) assert_equal custom, merged.around_request end test "merge preserves around_request from self when other not set" do custom = ->(_data, &request_handler) { request_handler.call } config1 = Configuration.new(around_request: custom) config2 = Configuration.new merged = config1.merge(config2) assert_equal custom, merged.around_request end test "raises ArgumentError when protocol_version is not a supported value" do exception = assert_raises(ArgumentError) do Configuration.new(protocol_version: "1999-12-31") end assert_match(/\Aprotocol_version must be/, exception.message) end test "raises ArgumentError when validate_tool_call_arguments is not a boolean" do exception = assert_raises(ArgumentError) do Configuration.new(validate_tool_call_arguments: "true") end assert_equal("validate_tool_call_arguments must be a boolean", exception.message) end test "raises ArgumentError when validate_tool_call_results is not a boolean" do exception = assert_raises(ArgumentError) do Configuration.new(validate_tool_call_results: "true") end assert_equal("validate_tool_call_results must be a boolean", exception.message) end end end