hatch-xclam 0.7.0.dev13__py3-none-any.whl → 0.7.1__py3-none-any.whl

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.
Files changed (26) hide show
  1. hatch/cli_hatch.py +120 -18
  2. hatch/mcp_host_config/__init__.py +4 -2
  3. hatch/mcp_host_config/backup.py +62 -31
  4. hatch/mcp_host_config/models.py +125 -1
  5. hatch/mcp_host_config/strategies.py +268 -1
  6. {hatch_xclam-0.7.0.dev13.dist-info → hatch_xclam-0.7.1.dist-info}/METADATA +6 -3
  7. {hatch_xclam-0.7.0.dev13.dist-info → hatch_xclam-0.7.1.dist-info}/RECORD +26 -14
  8. tests/integration/__init__.py +5 -0
  9. tests/integration/test_mcp_kiro_integration.py +153 -0
  10. tests/regression/__init__.py +5 -0
  11. tests/regression/test_mcp_codex_backup_integration.py +162 -0
  12. tests/regression/test_mcp_codex_host_strategy.py +163 -0
  13. tests/regression/test_mcp_codex_model_validation.py +117 -0
  14. tests/regression/test_mcp_kiro_backup_integration.py +241 -0
  15. tests/regression/test_mcp_kiro_cli_integration.py +141 -0
  16. tests/regression/test_mcp_kiro_decorator_registration.py +71 -0
  17. tests/regression/test_mcp_kiro_host_strategy.py +214 -0
  18. tests/regression/test_mcp_kiro_model_validation.py +116 -0
  19. tests/regression/test_mcp_kiro_omni_conversion.py +104 -0
  20. tests/test_data_utils.py +108 -0
  21. tests/test_mcp_cli_all_host_specific_args.py +194 -1
  22. tests/test_mcp_cli_direct_management.py +8 -5
  23. {hatch_xclam-0.7.0.dev13.dist-info → hatch_xclam-0.7.1.dist-info}/WHEEL +0 -0
  24. {hatch_xclam-0.7.0.dev13.dist-info → hatch_xclam-0.7.1.dist-info}/entry_points.txt +0 -0
  25. {hatch_xclam-0.7.0.dev13.dist-info → hatch_xclam-0.7.1.dist-info}/licenses/LICENSE +0 -0
  26. {hatch_xclam-0.7.0.dev13.dist-info → hatch_xclam-0.7.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,141 @@
1
+ """
2
+ Kiro MCP CLI Integration Tests
3
+
4
+ Tests for CLI argument parsing and integration with Kiro-specific arguments.
5
+ """
6
+
7
+ import unittest
8
+ from unittest.mock import patch, MagicMock
9
+
10
+ from wobble.decorators import regression_test
11
+
12
+ from hatch.cli_hatch import handle_mcp_configure
13
+
14
+
15
+ class TestKiroCLIIntegration(unittest.TestCase):
16
+ """Test suite for Kiro CLI argument integration."""
17
+
18
+ @patch('hatch.cli_hatch.MCPHostConfigurationManager')
19
+ @regression_test
20
+ def test_kiro_cli_with_disabled_flag(self, mock_manager_class):
21
+ """Test CLI with --disabled flag for Kiro."""
22
+ mock_manager = MagicMock()
23
+ mock_manager_class.return_value = mock_manager
24
+
25
+ mock_result = MagicMock()
26
+ mock_result.success = True
27
+ mock_result.backup_path = None
28
+ mock_manager.configure_server.return_value = mock_result
29
+
30
+ result = handle_mcp_configure(
31
+ host='kiro',
32
+ server_name='test-server',
33
+ command='auggie',
34
+ args=['--mcp'],
35
+ disabled=True, # Kiro-specific argument
36
+ auto_approve=True
37
+ )
38
+
39
+ self.assertEqual(result, 0)
40
+
41
+ # Verify configure_server was called with Kiro model
42
+ mock_manager.configure_server.assert_called_once()
43
+ call_args = mock_manager.configure_server.call_args
44
+ server_config = call_args.kwargs['server_config']
45
+
46
+ # Verify Kiro-specific field was set
47
+ self.assertTrue(server_config.disabled)
48
+
49
+ @patch('hatch.cli_hatch.MCPHostConfigurationManager')
50
+ @regression_test
51
+ def test_kiro_cli_with_auto_approve_tools(self, mock_manager_class):
52
+ """Test CLI with --auto-approve-tools for Kiro."""
53
+ mock_manager = MagicMock()
54
+ mock_manager_class.return_value = mock_manager
55
+
56
+ mock_result = MagicMock()
57
+ mock_result.success = True
58
+ mock_manager.configure_server.return_value = mock_result
59
+
60
+ result = handle_mcp_configure(
61
+ host='kiro',
62
+ server_name='test-server',
63
+ command='auggie',
64
+ args=['--mcp'], # Required parameter
65
+ auto_approve_tools=['codebase-retrieval', 'fetch'],
66
+ auto_approve=True
67
+ )
68
+
69
+ self.assertEqual(result, 0)
70
+
71
+ # Verify autoApprove field was set correctly
72
+ call_args = mock_manager.configure_server.call_args
73
+ server_config = call_args.kwargs['server_config']
74
+ self.assertEqual(len(server_config.autoApprove), 2)
75
+ self.assertIn('codebase-retrieval', server_config.autoApprove)
76
+
77
+ @patch('hatch.cli_hatch.MCPHostConfigurationManager')
78
+ @regression_test
79
+ def test_kiro_cli_with_disable_tools(self, mock_manager_class):
80
+ """Test CLI with --disable-tools for Kiro."""
81
+ mock_manager = MagicMock()
82
+ mock_manager_class.return_value = mock_manager
83
+
84
+ mock_result = MagicMock()
85
+ mock_result.success = True
86
+ mock_manager.configure_server.return_value = mock_result
87
+
88
+ result = handle_mcp_configure(
89
+ host='kiro',
90
+ server_name='test-server',
91
+ command='python',
92
+ args=['server.py'], # Required parameter
93
+ disable_tools=['dangerous-tool', 'risky-tool'],
94
+ auto_approve=True
95
+ )
96
+
97
+ self.assertEqual(result, 0)
98
+
99
+ # Verify disabledTools field was set correctly
100
+ call_args = mock_manager.configure_server.call_args
101
+ server_config = call_args.kwargs['server_config']
102
+ self.assertEqual(len(server_config.disabledTools), 2)
103
+ self.assertIn('dangerous-tool', server_config.disabledTools)
104
+
105
+ @patch('hatch.cli_hatch.MCPHostConfigurationManager')
106
+ @regression_test
107
+ def test_kiro_cli_combined_arguments(self, mock_manager_class):
108
+ """Test CLI with multiple Kiro-specific arguments combined."""
109
+ mock_manager = MagicMock()
110
+ mock_manager_class.return_value = mock_manager
111
+
112
+ mock_result = MagicMock()
113
+ mock_result.success = True
114
+ mock_manager.configure_server.return_value = mock_result
115
+
116
+ result = handle_mcp_configure(
117
+ host='kiro',
118
+ server_name='comprehensive-server',
119
+ command='auggie',
120
+ args=['--mcp', '-m', 'default'],
121
+ disabled=False,
122
+ auto_approve_tools=['codebase-retrieval'],
123
+ disable_tools=['dangerous-tool'],
124
+ auto_approve=True
125
+ )
126
+
127
+ self.assertEqual(result, 0)
128
+
129
+ # Verify all Kiro fields were set correctly
130
+ call_args = mock_manager.configure_server.call_args
131
+ server_config = call_args.kwargs['server_config']
132
+
133
+ self.assertFalse(server_config.disabled)
134
+ self.assertEqual(len(server_config.autoApprove), 1)
135
+ self.assertEqual(len(server_config.disabledTools), 1)
136
+ self.assertIn('codebase-retrieval', server_config.autoApprove)
137
+ self.assertIn('dangerous-tool', server_config.disabledTools)
138
+
139
+
140
+ if __name__ == '__main__':
141
+ unittest.main()
@@ -0,0 +1,71 @@
1
+ """
2
+ Kiro MCP Decorator Registration Tests
3
+
4
+ Tests for automatic strategy registration via @register_host_strategy decorator.
5
+ """
6
+
7
+ import unittest
8
+
9
+ from wobble.decorators import regression_test
10
+
11
+ from hatch.mcp_host_config.host_management import MCPHostRegistry
12
+ from hatch.mcp_host_config.models import MCPHostType
13
+
14
+
15
+ class TestKiroDecoratorRegistration(unittest.TestCase):
16
+ """Test suite for Kiro decorator registration."""
17
+
18
+ @regression_test
19
+ def test_kiro_strategy_registration(self):
20
+ """Test that KiroHostStrategy is properly registered."""
21
+ # Import strategies to trigger registration
22
+ import hatch.mcp_host_config.strategies
23
+
24
+ # Verify Kiro is registered
25
+ self.assertIn(MCPHostType.KIRO, MCPHostRegistry._strategies)
26
+
27
+ # Verify correct strategy class
28
+ strategy_class = MCPHostRegistry._strategies[MCPHostType.KIRO]
29
+ self.assertEqual(strategy_class.__name__, "KiroHostStrategy")
30
+
31
+ @regression_test
32
+ def test_kiro_strategy_instantiation(self):
33
+ """Test that Kiro strategy can be instantiated."""
34
+ # Import strategies to trigger registration
35
+ import hatch.mcp_host_config.strategies
36
+
37
+ strategy = MCPHostRegistry.get_strategy(MCPHostType.KIRO)
38
+
39
+ # Verify strategy instance
40
+ self.assertIsNotNone(strategy)
41
+ self.assertEqual(strategy.__class__.__name__, "KiroHostStrategy")
42
+
43
+ @regression_test
44
+ def test_kiro_in_host_detection(self):
45
+ """Test that Kiro appears in host detection."""
46
+ # Import strategies to trigger registration
47
+ import hatch.mcp_host_config.strategies
48
+
49
+ # Get all registered host types
50
+ registered_hosts = list(MCPHostRegistry._strategies.keys())
51
+
52
+ # Verify Kiro is included
53
+ self.assertIn(MCPHostType.KIRO, registered_hosts)
54
+
55
+ @regression_test
56
+ def test_kiro_registry_consistency(self):
57
+ """Test that Kiro registration is consistent across calls."""
58
+ # Import strategies to trigger registration
59
+ import hatch.mcp_host_config.strategies
60
+
61
+ # Get strategy multiple times
62
+ strategy1 = MCPHostRegistry.get_strategy(MCPHostType.KIRO)
63
+ strategy2 = MCPHostRegistry.get_strategy(MCPHostType.KIRO)
64
+
65
+ # Verify same class (not necessarily same instance)
66
+ self.assertEqual(strategy1.__class__, strategy2.__class__)
67
+ self.assertEqual(strategy1.__class__.__name__, "KiroHostStrategy")
68
+
69
+
70
+ if __name__ == '__main__':
71
+ unittest.main()
@@ -0,0 +1,214 @@
1
+ """
2
+ Kiro MCP Host Strategy Tests
3
+
4
+ Tests for KiroHostStrategy implementation including path resolution,
5
+ configuration read/write, and host detection.
6
+ """
7
+
8
+ import unittest
9
+ import json
10
+ from unittest.mock import patch, mock_open, MagicMock
11
+ from pathlib import Path
12
+
13
+ from wobble.decorators import regression_test
14
+
15
+ from hatch.mcp_host_config.strategies import KiroHostStrategy
16
+ from hatch.mcp_host_config.models import MCPServerConfig, HostConfiguration
17
+
18
+ # Import test data loader from local tests module
19
+ import sys
20
+ from pathlib import Path
21
+ sys.path.insert(0, str(Path(__file__).parent.parent))
22
+ from test_data_utils import MCPHostConfigTestDataLoader
23
+
24
+
25
+ class TestKiroHostStrategy(unittest.TestCase):
26
+ """Test suite for KiroHostStrategy implementation."""
27
+
28
+ def setUp(self):
29
+ """Set up test environment."""
30
+ self.strategy = KiroHostStrategy()
31
+ self.test_data_loader = MCPHostConfigTestDataLoader()
32
+
33
+ @regression_test
34
+ def test_kiro_config_path_resolution(self):
35
+ """Test Kiro configuration path resolution."""
36
+ config_path = self.strategy.get_config_path()
37
+
38
+ # Verify path structure (use normalized path for cross-platform compatibility)
39
+ self.assertIsNotNone(config_path)
40
+ normalized_path = str(config_path).replace('\\', '/')
41
+ self.assertTrue(normalized_path.endswith('.kiro/settings/mcp.json'))
42
+ self.assertEqual(config_path.name, 'mcp.json')
43
+
44
+ @regression_test
45
+ def test_kiro_config_key(self):
46
+ """Test Kiro configuration key."""
47
+ config_key = self.strategy.get_config_key()
48
+ self.assertEqual(config_key, "mcpServers")
49
+
50
+ @regression_test
51
+ def test_kiro_server_config_validation(self):
52
+ """Test Kiro server configuration validation."""
53
+ # Test local server validation
54
+ local_config = MCPServerConfig(
55
+ command="auggie",
56
+ args=["--mcp"]
57
+ )
58
+ self.assertTrue(self.strategy.validate_server_config(local_config))
59
+
60
+ # Test remote server validation
61
+ remote_config = MCPServerConfig(
62
+ url="https://api.example.com/mcp"
63
+ )
64
+ self.assertTrue(self.strategy.validate_server_config(remote_config))
65
+
66
+ # Test invalid configuration (should raise ValidationError during creation)
67
+ with self.assertRaises(Exception): # Pydantic ValidationError
68
+ invalid_config = MCPServerConfig()
69
+ self.strategy.validate_server_config(invalid_config)
70
+
71
+ @patch('pathlib.Path.exists')
72
+ @regression_test
73
+ def test_kiro_host_availability_detection(self, mock_exists):
74
+ """Test Kiro host availability detection."""
75
+ # Test when Kiro directory exists
76
+ mock_exists.return_value = True
77
+ self.assertTrue(self.strategy.is_host_available())
78
+
79
+ # Test when Kiro directory doesn't exist
80
+ mock_exists.return_value = False
81
+ self.assertFalse(self.strategy.is_host_available())
82
+
83
+ @patch('builtins.open', new_callable=mock_open)
84
+ @patch('pathlib.Path.exists')
85
+ @patch('json.load')
86
+ @regression_test
87
+ def test_kiro_read_configuration_success(self, mock_json_load, mock_exists, mock_file):
88
+ """Test successful Kiro configuration reading."""
89
+ # Mock file exists and JSON content
90
+ mock_exists.return_value = True
91
+ mock_json_load.return_value = {
92
+ "mcpServers": {
93
+ "augment": {
94
+ "command": "auggie",
95
+ "args": ["--mcp", "-m", "default"],
96
+ "autoApprove": ["codebase-retrieval"]
97
+ }
98
+ }
99
+ }
100
+
101
+ config = self.strategy.read_configuration()
102
+
103
+ # Verify configuration structure
104
+ self.assertIsInstance(config, HostConfiguration)
105
+ self.assertIn("augment", config.servers)
106
+
107
+ server = config.servers["augment"]
108
+ self.assertEqual(server.command, "auggie")
109
+ self.assertEqual(len(server.args), 3)
110
+
111
+ @patch('pathlib.Path.exists')
112
+ @regression_test
113
+ def test_kiro_read_configuration_file_not_exists(self, mock_exists):
114
+ """Test Kiro configuration reading when file doesn't exist."""
115
+ mock_exists.return_value = False
116
+
117
+ config = self.strategy.read_configuration()
118
+
119
+ # Should return empty configuration
120
+ self.assertIsInstance(config, HostConfiguration)
121
+ self.assertEqual(len(config.servers), 0)
122
+
123
+ @patch('hatch.mcp_host_config.strategies.MCPHostConfigBackupManager')
124
+ @patch('hatch.mcp_host_config.strategies.AtomicFileOperations')
125
+ @patch('builtins.open', new_callable=mock_open)
126
+ @patch('pathlib.Path.exists')
127
+ @patch('pathlib.Path.mkdir')
128
+ @patch('json.load')
129
+ @regression_test
130
+ def test_kiro_write_configuration_success(self, mock_json_load, mock_mkdir,
131
+ mock_exists, mock_file, mock_atomic_ops_class, mock_backup_manager_class):
132
+ """Test successful Kiro configuration writing."""
133
+ # Mock existing file with other settings
134
+ mock_exists.return_value = True
135
+ mock_json_load.return_value = {
136
+ "otherSettings": {"theme": "dark"},
137
+ "mcpServers": {}
138
+ }
139
+
140
+ # Mock backup and atomic operations
141
+ mock_backup_manager = MagicMock()
142
+ mock_backup_manager_class.return_value = mock_backup_manager
143
+
144
+ mock_atomic_ops = MagicMock()
145
+ mock_atomic_ops_class.return_value = mock_atomic_ops
146
+
147
+ # Create test configuration
148
+ server_config = MCPServerConfig(
149
+ command="auggie",
150
+ args=["--mcp"]
151
+ )
152
+ config = HostConfiguration(servers={"test-server": server_config})
153
+
154
+ result = self.strategy.write_configuration(config)
155
+
156
+ # Verify success
157
+ self.assertTrue(result)
158
+
159
+ # Verify atomic write was called
160
+ mock_atomic_ops.atomic_write_with_backup.assert_called_once()
161
+
162
+ # Verify configuration structure in the call
163
+ call_args = mock_atomic_ops.atomic_write_with_backup.call_args
164
+ written_data = call_args[1]['data'] # keyword argument 'data'
165
+ self.assertIn("otherSettings", written_data) # Preserved
166
+ self.assertIn("mcpServers", written_data) # Updated
167
+ self.assertIn("test-server", written_data["mcpServers"])
168
+
169
+ @patch('hatch.mcp_host_config.strategies.MCPHostConfigBackupManager')
170
+ @patch('hatch.mcp_host_config.strategies.AtomicFileOperations')
171
+ @patch('builtins.open', new_callable=mock_open)
172
+ @patch('pathlib.Path.exists')
173
+ @patch('pathlib.Path.mkdir')
174
+ @regression_test
175
+ def test_kiro_write_configuration_new_file(self, mock_mkdir, mock_exists,
176
+ mock_file, mock_atomic_ops_class, mock_backup_manager_class):
177
+ """Test Kiro configuration writing when file doesn't exist."""
178
+ # Mock file doesn't exist
179
+ mock_exists.return_value = False
180
+
181
+ # Mock backup and atomic operations
182
+ mock_backup_manager = MagicMock()
183
+ mock_backup_manager_class.return_value = mock_backup_manager
184
+
185
+ mock_atomic_ops = MagicMock()
186
+ mock_atomic_ops_class.return_value = mock_atomic_ops
187
+
188
+ # Create test configuration
189
+ server_config = MCPServerConfig(
190
+ command="auggie",
191
+ args=["--mcp"]
192
+ )
193
+ config = HostConfiguration(servers={"new-server": server_config})
194
+
195
+ result = self.strategy.write_configuration(config)
196
+
197
+ # Verify success
198
+ self.assertTrue(result)
199
+
200
+ # Verify directory creation was attempted
201
+ mock_mkdir.assert_called_once()
202
+
203
+ # Verify atomic write was called
204
+ mock_atomic_ops.atomic_write_with_backup.assert_called_once()
205
+
206
+ # Verify configuration structure
207
+ call_args = mock_atomic_ops.atomic_write_with_backup.call_args
208
+ written_data = call_args[1]['data'] # keyword argument 'data'
209
+ self.assertIn("mcpServers", written_data)
210
+ self.assertIn("new-server", written_data["mcpServers"])
211
+
212
+
213
+ if __name__ == '__main__':
214
+ unittest.main()
@@ -0,0 +1,116 @@
1
+ """
2
+ Kiro MCP Model Validation Tests
3
+
4
+ Tests for MCPServerConfigKiro Pydantic model behavior, field validation,
5
+ and Kiro-specific field combinations.
6
+ """
7
+
8
+ import unittest
9
+ from typing import Optional, List
10
+
11
+ from wobble.decorators import regression_test
12
+
13
+ from hatch.mcp_host_config.models import (
14
+ MCPServerConfigKiro,
15
+ MCPServerConfigOmni,
16
+ MCPHostType
17
+ )
18
+
19
+
20
+ class TestMCPServerConfigKiro(unittest.TestCase):
21
+ """Test suite for MCPServerConfigKiro model validation."""
22
+
23
+ @regression_test
24
+ def test_kiro_model_with_disabled_field(self):
25
+ """Test Kiro model with disabled field."""
26
+ config = MCPServerConfigKiro(
27
+ name="kiro-server",
28
+ command="auggie",
29
+ args=["--mcp", "-m", "default"],
30
+ disabled=True
31
+ )
32
+
33
+ self.assertEqual(config.command, "auggie")
34
+ self.assertTrue(config.disabled)
35
+ self.assertEqual(config.type, "stdio") # Inferred
36
+
37
+ @regression_test
38
+ def test_kiro_model_with_auto_approve_tools(self):
39
+ """Test Kiro model with autoApprove field."""
40
+ config = MCPServerConfigKiro(
41
+ name="kiro-server",
42
+ command="auggie",
43
+ autoApprove=["codebase-retrieval", "fetch"]
44
+ )
45
+
46
+ self.assertEqual(config.command, "auggie")
47
+ self.assertEqual(len(config.autoApprove), 2)
48
+ self.assertIn("codebase-retrieval", config.autoApprove)
49
+ self.assertIn("fetch", config.autoApprove)
50
+
51
+ @regression_test
52
+ def test_kiro_model_with_disabled_tools(self):
53
+ """Test Kiro model with disabledTools field."""
54
+ config = MCPServerConfigKiro(
55
+ name="kiro-server",
56
+ command="python",
57
+ disabledTools=["dangerous-tool", "risky-tool"]
58
+ )
59
+
60
+ self.assertEqual(config.command, "python")
61
+ self.assertEqual(len(config.disabledTools), 2)
62
+ self.assertIn("dangerous-tool", config.disabledTools)
63
+
64
+ @regression_test
65
+ def test_kiro_model_all_fields_combined(self):
66
+ """Test Kiro model with all Kiro-specific fields."""
67
+ config = MCPServerConfigKiro(
68
+ name="kiro-server",
69
+ command="auggie",
70
+ args=["--mcp"],
71
+ env={"DEBUG": "true"},
72
+ disabled=False,
73
+ autoApprove=["codebase-retrieval"],
74
+ disabledTools=["dangerous-tool"]
75
+ )
76
+
77
+ # Verify all fields
78
+ self.assertEqual(config.command, "auggie")
79
+ self.assertFalse(config.disabled)
80
+ self.assertEqual(len(config.autoApprove), 1)
81
+ self.assertEqual(len(config.disabledTools), 1)
82
+ self.assertEqual(config.env["DEBUG"], "true")
83
+
84
+ @regression_test
85
+ def test_kiro_model_minimal_configuration(self):
86
+ """Test Kiro model with minimal configuration."""
87
+ config = MCPServerConfigKiro(
88
+ name="kiro-server",
89
+ command="auggie"
90
+ )
91
+
92
+ self.assertEqual(config.command, "auggie")
93
+ self.assertEqual(config.type, "stdio") # Inferred
94
+ self.assertIsNone(config.disabled)
95
+ self.assertIsNone(config.autoApprove)
96
+ self.assertIsNone(config.disabledTools)
97
+
98
+ @regression_test
99
+ def test_kiro_model_remote_server_with_kiro_fields(self):
100
+ """Test Kiro model with remote server and Kiro-specific fields."""
101
+ config = MCPServerConfigKiro(
102
+ name="kiro-remote",
103
+ url="https://api.example.com/mcp",
104
+ headers={"Authorization": "Bearer token"},
105
+ disabled=True,
106
+ autoApprove=["safe-tool"]
107
+ )
108
+
109
+ self.assertEqual(config.url, "https://api.example.com/mcp")
110
+ self.assertTrue(config.disabled)
111
+ self.assertEqual(len(config.autoApprove), 1)
112
+ self.assertEqual(config.type, "sse") # Inferred for remote
113
+
114
+
115
+ if __name__ == '__main__':
116
+ unittest.main()
@@ -0,0 +1,104 @@
1
+ """
2
+ Kiro MCP Omni Conversion Tests
3
+
4
+ Tests for conversion from MCPServerConfigOmni to MCPServerConfigKiro
5
+ using the from_omni() method.
6
+ """
7
+
8
+ import unittest
9
+
10
+ from wobble.decorators import regression_test
11
+
12
+ from hatch.mcp_host_config.models import (
13
+ MCPServerConfigKiro,
14
+ MCPServerConfigOmni
15
+ )
16
+
17
+
18
+ class TestKiroFromOmniConversion(unittest.TestCase):
19
+ """Test suite for Kiro from_omni() conversion method."""
20
+
21
+ @regression_test
22
+ def test_kiro_from_omni_with_supported_fields(self):
23
+ """Test Kiro from_omni with supported fields."""
24
+ omni = MCPServerConfigOmni(
25
+ name="kiro-server",
26
+ command="auggie",
27
+ args=["--mcp", "-m", "default"],
28
+ disabled=True,
29
+ autoApprove=["codebase-retrieval", "fetch"],
30
+ disabledTools=["dangerous-tool"]
31
+ )
32
+
33
+ # Convert to Kiro model
34
+ kiro = MCPServerConfigKiro.from_omni(omni)
35
+
36
+ # Verify all supported fields transferred
37
+ self.assertEqual(kiro.name, "kiro-server")
38
+ self.assertEqual(kiro.command, "auggie")
39
+ self.assertEqual(len(kiro.args), 3)
40
+ self.assertTrue(kiro.disabled)
41
+ self.assertEqual(len(kiro.autoApprove), 2)
42
+ self.assertEqual(len(kiro.disabledTools), 1)
43
+
44
+ @regression_test
45
+ def test_kiro_from_omni_with_unsupported_fields(self):
46
+ """Test Kiro from_omni excludes unsupported fields."""
47
+ omni = MCPServerConfigOmni(
48
+ name="kiro-server",
49
+ command="python",
50
+ disabled=True, # Kiro field
51
+ envFile=".env", # VS Code field (unsupported by Kiro)
52
+ timeout=30000 # Gemini field (unsupported by Kiro)
53
+ )
54
+
55
+ # Convert to Kiro model
56
+ kiro = MCPServerConfigKiro.from_omni(omni)
57
+
58
+ # Verify Kiro fields transferred
59
+ self.assertEqual(kiro.command, "python")
60
+ self.assertTrue(kiro.disabled)
61
+
62
+ # Verify unsupported fields NOT transferred
63
+ self.assertFalse(hasattr(kiro, 'envFile') and kiro.envFile is not None)
64
+ self.assertFalse(hasattr(kiro, 'timeout') and kiro.timeout is not None)
65
+
66
+ @regression_test
67
+ def test_kiro_from_omni_exclude_unset_behavior(self):
68
+ """Test that from_omni respects exclude_unset=True."""
69
+ omni = MCPServerConfigOmni(
70
+ name="kiro-server",
71
+ command="auggie"
72
+ # disabled, autoApprove, disabledTools not set
73
+ )
74
+
75
+ kiro = MCPServerConfigKiro.from_omni(omni)
76
+
77
+ # Verify unset fields remain None
78
+ self.assertIsNone(kiro.disabled)
79
+ self.assertIsNone(kiro.autoApprove)
80
+ self.assertIsNone(kiro.disabledTools)
81
+
82
+ @regression_test
83
+ def test_kiro_from_omni_remote_server_conversion(self):
84
+ """Test Kiro from_omni with remote server configuration."""
85
+ omni = MCPServerConfigOmni(
86
+ name="kiro-remote",
87
+ url="https://api.example.com/mcp",
88
+ headers={"Authorization": "Bearer token"},
89
+ disabled=False,
90
+ autoApprove=["safe-tool"]
91
+ )
92
+
93
+ kiro = MCPServerConfigKiro.from_omni(omni)
94
+
95
+ # Verify remote server fields
96
+ self.assertEqual(kiro.url, "https://api.example.com/mcp")
97
+ self.assertEqual(kiro.headers["Authorization"], "Bearer token")
98
+ self.assertFalse(kiro.disabled)
99
+ self.assertEqual(len(kiro.autoApprove), 1)
100
+ self.assertEqual(kiro.type, "sse") # Inferred for remote
101
+
102
+
103
+ if __name__ == '__main__':
104
+ unittest.main()