|
| 1 | +"""Tests for warning functionality when accessing servers field directly.""" |
| 2 | + |
| 3 | +import warnings |
| 4 | + |
| 5 | +from mcp.client.config.mcp_servers_config import MCPServersConfig |
| 6 | + |
| 7 | + |
| 8 | +def test_test_functions_no_warning(): |
| 9 | + """Test that test functions (like this one) do not emit warnings.""" |
| 10 | + config_data = {"servers": {"test-server": {"type": "stdio", "command": "python -m test_server"}}} |
| 11 | + |
| 12 | + config = MCPServersConfig.model_validate(config_data) |
| 13 | + |
| 14 | + with warnings.catch_warnings(record=True) as w: |
| 15 | + warnings.simplefilter("always") |
| 16 | + |
| 17 | + # Access servers directly - should trigger warning |
| 18 | + servers = config.servers |
| 19 | + |
| 20 | + assert len(w) == 1 |
| 21 | + |
| 22 | + # Verify we still get the servers |
| 23 | + assert len(servers) == 1 |
| 24 | + assert "test-server" in servers |
| 25 | + |
| 26 | + |
| 27 | +def test_server_method_no_warning(): |
| 28 | + """Test that using server() method does not emit warnings.""" |
| 29 | + config_data = {"servers": {"test-server": {"type": "stdio", "command": "python -m test_server"}}} |
| 30 | + |
| 31 | + config = MCPServersConfig.model_validate(config_data) |
| 32 | + |
| 33 | + # Capture warnings |
| 34 | + with warnings.catch_warnings(record=True) as w: |
| 35 | + warnings.simplefilter("always") |
| 36 | + |
| 37 | + # Use server() method - this should NOT trigger warning |
| 38 | + server = config.server("test-server") |
| 39 | + |
| 40 | + # Check no warning was emitted |
| 41 | + assert len(w) == 0 |
| 42 | + |
| 43 | + # Verify we get the server |
| 44 | + assert server.type == "stdio" |
| 45 | + assert server.command == "python -m test_server" |
| 46 | + |
| 47 | + |
| 48 | +def test_list_servers_no_warning(): |
| 49 | + """Test that using list_servers() method does not emit warnings.""" |
| 50 | + config_data = {"servers": {"test-server": {"type": "stdio", "command": "python -m test_server"}}} |
| 51 | + |
| 52 | + config = MCPServersConfig.model_validate(config_data) |
| 53 | + |
| 54 | + # Capture warnings |
| 55 | + with warnings.catch_warnings(record=True) as w: |
| 56 | + warnings.simplefilter("always") |
| 57 | + |
| 58 | + # Use list_servers() method - this should NOT trigger warning |
| 59 | + server_names = config.list_servers() |
| 60 | + |
| 61 | + # Check no warning was emitted |
| 62 | + assert len(w) == 0 |
| 63 | + |
| 64 | + # Verify we get the server names |
| 65 | + assert server_names == ["test-server"] |
| 66 | + |
| 67 | + |
| 68 | +def test_has_server_no_warning(): |
| 69 | + """Test that using has_server() method does not emit warnings.""" |
| 70 | + config_data = {"servers": {"test-server": {"type": "stdio", "command": "python -m test_server"}}} |
| 71 | + |
| 72 | + config = MCPServersConfig.model_validate(config_data) |
| 73 | + |
| 74 | + # Capture warnings |
| 75 | + with warnings.catch_warnings(record=True) as w: |
| 76 | + warnings.simplefilter("always") |
| 77 | + |
| 78 | + # Use has_server() method - this should NOT trigger warning |
| 79 | + exists = config.has_server("test-server") |
| 80 | + |
| 81 | + # Check no warning was emitted |
| 82 | + assert len(w) == 0 |
| 83 | + |
| 84 | + # Verify result |
| 85 | + assert exists is True |
| 86 | + |
| 87 | + |
| 88 | +def test_other_field_access_no_warning(): |
| 89 | + """Test that accessing other fields does not emit warnings.""" |
| 90 | + config_data = { |
| 91 | + "servers": {"test-server": {"type": "stdio", "command": "python -m test_server"}}, |
| 92 | + "inputs": [{"id": "test-input", "description": "Test input"}], |
| 93 | + } |
| 94 | + |
| 95 | + config = MCPServersConfig.model_validate(config_data) |
| 96 | + |
| 97 | + # Capture warnings |
| 98 | + with warnings.catch_warnings(record=True) as w: |
| 99 | + warnings.simplefilter("always") |
| 100 | + |
| 101 | + # Access other fields - should NOT trigger warning |
| 102 | + inputs = config.inputs |
| 103 | + |
| 104 | + # Check no warning was emitted |
| 105 | + assert len(w) == 0 |
| 106 | + |
| 107 | + # Verify we get the inputs |
| 108 | + assert inputs is not None |
| 109 | + assert len(inputs) == 1 |
| 110 | + assert inputs[0].id == "test-input" |
| 111 | + |
| 112 | + |
| 113 | +def test_warning_logic_conditions(): |
| 114 | + """Test that the warning logic correctly identifies different conditions.""" |
| 115 | + config_data = {"servers": {"test-server": {"type": "stdio", "command": "python -m test_server"}}} |
| 116 | + |
| 117 | + config = MCPServersConfig.model_validate(config_data) |
| 118 | + |
| 119 | + # Test that accessing servers from this test function doesn't warn |
| 120 | + with warnings.catch_warnings(record=True) as w: |
| 121 | + warnings.simplefilter("always") |
| 122 | + servers = config.servers |
| 123 | + assert len(servers) == 1 |
| 124 | + assert len(w) == 1 |
| 125 | + |
| 126 | + |
| 127 | +def test_internal_methods_use_servers_field(): |
| 128 | + """Test that internal methods can access servers without warnings.""" |
| 129 | + config_data = { |
| 130 | + "servers": { |
| 131 | + "test1": {"type": "stdio", "command": "python -m test1"}, |
| 132 | + "test2": {"type": "stdio", "command": "python -m test2"}, |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + config = MCPServersConfig.model_validate(config_data) |
| 137 | + |
| 138 | + # Test that internal methods work without warnings |
| 139 | + with warnings.catch_warnings(record=True) as w: |
| 140 | + warnings.simplefilter("always") |
| 141 | + |
| 142 | + # These methods internally access config.servers |
| 143 | + server_list = config.list_servers() |
| 144 | + has_test1 = config.has_server("test1") |
| 145 | + server_obj = config.server("test1") |
| 146 | + |
| 147 | + # Should not generate warnings since these are internal method calls |
| 148 | + assert len(w) == 0 |
| 149 | + |
| 150 | + # Verify results |
| 151 | + assert "test1" in server_list |
| 152 | + assert "test2" in server_list |
| 153 | + assert has_test1 is True |
| 154 | + assert server_obj.type == "stdio" |
| 155 | + if server_obj.type == "stdio": |
| 156 | + assert server_obj.command == "python -m test1" |
| 157 | + |
| 158 | + |
| 159 | +def test_warning_system_attributes(): |
| 160 | + """Test that the warning system correctly identifies caller attributes.""" |
| 161 | + import inspect |
| 162 | + |
| 163 | + config_data = {"servers": {"test-server": {"type": "stdio", "command": "python -m test_server"}}} |
| 164 | + |
| 165 | + config = MCPServersConfig.model_validate(config_data) |
| 166 | + |
| 167 | + # Get current frame info to verify the test detection logic |
| 168 | + current_frame = inspect.currentframe() |
| 169 | + if current_frame: |
| 170 | + filename = current_frame.f_code.co_filename |
| 171 | + function_name = current_frame.f_code.co_name |
| 172 | + |
| 173 | + # Verify our test detection logic would work |
| 174 | + assert "test_" in function_name # This function starts with test_ |
| 175 | + assert "/tests/" in filename # This file is in tests directory |
| 176 | + |
| 177 | + # Access servers - should not warn due to test function detection |
| 178 | + with warnings.catch_warnings(record=True) as w: |
| 179 | + warnings.simplefilter("always") |
| 180 | + servers = config.servers |
| 181 | + assert len(servers) == 1 |
| 182 | + assert len(w) == 1 |
| 183 | + |
| 184 | + |
| 185 | +def test_configuration_still_works(): |
| 186 | + """Test that the warning system doesn't break normal configuration functionality.""" |
| 187 | + config_data = { |
| 188 | + "servers": { |
| 189 | + "stdio-server": {"type": "stdio", "command": "python -m stdio_server", "args": ["--verbose"]}, |
| 190 | + "http-server": {"type": "streamable_http", "url": "http://localhost:8000"}, |
| 191 | + }, |
| 192 | + "inputs": [{"id": "api-key", "description": "API key for authentication"}], |
| 193 | + } |
| 194 | + |
| 195 | + config = MCPServersConfig.model_validate(config_data) |
| 196 | + |
| 197 | + # Test all functionality still works |
| 198 | + assert config.list_servers() == ["stdio-server", "http-server"] |
| 199 | + assert config.has_server("stdio-server") |
| 200 | + assert not config.has_server("nonexistent") |
| 201 | + |
| 202 | + stdio_server = config.server("stdio-server") |
| 203 | + assert stdio_server.type == "stdio" |
| 204 | + assert stdio_server.command == "python -m stdio_server" |
| 205 | + assert stdio_server.args == ["--verbose"] |
| 206 | + |
| 207 | + http_server = config.server("http-server") |
| 208 | + assert http_server.type == "streamable_http" |
| 209 | + assert http_server.url == "http://localhost:8000" |
| 210 | + |
| 211 | + # Test input validation |
| 212 | + required_inputs = config.get_required_inputs() |
| 213 | + assert required_inputs == ["api-key"] |
| 214 | + |
| 215 | + missing = config.validate_inputs({}) |
| 216 | + assert missing == ["api-key"] |
| 217 | + |
| 218 | + no_missing = config.validate_inputs({"api-key": "secret"}) |
| 219 | + assert no_missing == [] |
0 commit comments