Skip to content

Commit 6910120

Browse files
test(mcp-host-config): add integration tests for adapter serialization
Add 7 integration tests (AS-01 to AS-07) covering full serialization flow for each adapter with realistic configurations: - AS-01: Claude stdio serialization (command, args, env, type) - AS-02: Claude SSE serialization (url, headers, type) - AS-03: Gemini stdio serialization (cwd, timeout, no type) - AS-04: Gemini HTTP serialization (httpUrl, trust) - AS-05: VSCode with envFile support - AS-06: Codex with field mapping (args -> arguments) - AS-07: Kiro stdio serialization Tests verify complete serialization including host-specific behaviors like Codex field name mapping and type field exclusion for Gemini/Kiro. All 7 tests pass.
1 parent c1a0fa4 commit 6910120

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
"""Integration tests for adapter serialization.
2+
3+
Test IDs: AS-01 to AS-10 (per 02-test_architecture_rebuild_v0.md)
4+
Scope: Full serialization flow for each adapter with realistic configs.
5+
"""
6+
7+
import unittest
8+
9+
from hatch.mcp_host_config.models import MCPServerConfig
10+
from hatch.mcp_host_config.adapters import (
11+
ClaudeAdapter,
12+
CodexAdapter,
13+
CursorAdapter,
14+
GeminiAdapter,
15+
KiroAdapter,
16+
LMStudioAdapter,
17+
VSCodeAdapter,
18+
)
19+
20+
21+
class TestClaudeAdapterSerialization(unittest.TestCase):
22+
"""Integration tests for Claude adapter serialization."""
23+
24+
def test_AS01_claude_stdio_serialization(self):
25+
"""AS-01: Claude stdio config serializes correctly."""
26+
config = MCPServerConfig(
27+
name="my-server",
28+
command="python",
29+
args=["-m", "mcp_server"],
30+
env={"API_KEY": "secret"},
31+
type="stdio",
32+
)
33+
34+
adapter = ClaudeAdapter()
35+
result = adapter.serialize(config)
36+
37+
self.assertEqual(result["command"], "python")
38+
self.assertEqual(result["args"], ["-m", "mcp_server"])
39+
self.assertEqual(result["env"], {"API_KEY": "secret"})
40+
self.assertEqual(result["type"], "stdio")
41+
self.assertNotIn("name", result)
42+
43+
def test_AS02_claude_sse_serialization(self):
44+
"""AS-02: Claude SSE config serializes correctly."""
45+
config = MCPServerConfig(
46+
name="remote-server",
47+
url="https://api.example.com/mcp",
48+
headers={"Authorization": "Bearer token"},
49+
type="sse",
50+
)
51+
52+
adapter = ClaudeAdapter()
53+
result = adapter.serialize(config)
54+
55+
self.assertEqual(result["url"], "https://api.example.com/mcp")
56+
self.assertEqual(result["headers"], {"Authorization": "Bearer token"})
57+
self.assertEqual(result["type"], "sse")
58+
self.assertNotIn("name", result)
59+
self.assertNotIn("command", result)
60+
61+
62+
class TestGeminiAdapterSerialization(unittest.TestCase):
63+
"""Integration tests for Gemini adapter serialization."""
64+
65+
def test_AS03_gemini_stdio_serialization(self):
66+
"""AS-03: Gemini stdio config serializes correctly."""
67+
config = MCPServerConfig(
68+
name="gemini-server",
69+
command="npx",
70+
args=["mcp-server"],
71+
cwd="/workspace",
72+
timeout=30000,
73+
)
74+
75+
adapter = GeminiAdapter()
76+
result = adapter.serialize(config)
77+
78+
self.assertEqual(result["command"], "npx")
79+
self.assertEqual(result["args"], ["mcp-server"])
80+
self.assertEqual(result["cwd"], "/workspace")
81+
self.assertEqual(result["timeout"], 30000)
82+
self.assertNotIn("name", result)
83+
self.assertNotIn("type", result)
84+
85+
def test_AS04_gemini_http_serialization(self):
86+
"""AS-04: Gemini HTTP config serializes correctly."""
87+
config = MCPServerConfig(
88+
name="gemini-http",
89+
httpUrl="https://api.example.com/http",
90+
trust=True,
91+
)
92+
93+
adapter = GeminiAdapter()
94+
result = adapter.serialize(config)
95+
96+
self.assertEqual(result["httpUrl"], "https://api.example.com/http")
97+
self.assertEqual(result["trust"], True)
98+
self.assertNotIn("name", result)
99+
self.assertNotIn("type", result)
100+
101+
102+
class TestVSCodeAdapterSerialization(unittest.TestCase):
103+
"""Integration tests for VS Code adapter serialization."""
104+
105+
def test_AS05_vscode_with_envfile(self):
106+
"""AS-05: VS Code config with envFile serializes correctly."""
107+
config = MCPServerConfig(
108+
name="vscode-server",
109+
command="node",
110+
args=["server.js"],
111+
envFile=".env",
112+
type="stdio",
113+
)
114+
115+
adapter = VSCodeAdapter()
116+
result = adapter.serialize(config)
117+
118+
self.assertEqual(result["command"], "node")
119+
self.assertEqual(result["envFile"], ".env")
120+
self.assertEqual(result["type"], "stdio")
121+
self.assertNotIn("name", result)
122+
123+
124+
class TestCodexAdapterSerialization(unittest.TestCase):
125+
"""Integration tests for Codex adapter serialization."""
126+
127+
def test_AS06_codex_stdio_serialization(self):
128+
"""AS-06: Codex stdio config serializes correctly (no type field).
129+
130+
Note: Codex maps 'args' to 'arguments' and 'headers' to 'http_headers'.
131+
"""
132+
config = MCPServerConfig(
133+
name="codex-server",
134+
command="python",
135+
args=["server.py"],
136+
env={"DEBUG": "true"},
137+
)
138+
139+
adapter = CodexAdapter()
140+
result = adapter.serialize(config)
141+
142+
self.assertEqual(result["command"], "python")
143+
# Codex uses 'arguments' instead of 'args'
144+
self.assertEqual(result["arguments"], ["server.py"])
145+
self.assertNotIn("args", result) # Original name should not be present
146+
self.assertEqual(result["env"], {"DEBUG": "true"})
147+
self.assertNotIn("name", result)
148+
self.assertNotIn("type", result)
149+
150+
151+
class TestKiroAdapterSerialization(unittest.TestCase):
152+
"""Integration tests for Kiro adapter serialization."""
153+
154+
def test_AS07_kiro_stdio_serialization(self):
155+
"""AS-07: Kiro stdio config serializes correctly."""
156+
config = MCPServerConfig(
157+
name="kiro-server",
158+
command="npx",
159+
args=["@modelcontextprotocol/server"],
160+
)
161+
162+
adapter = KiroAdapter()
163+
result = adapter.serialize(config)
164+
165+
self.assertEqual(result["command"], "npx")
166+
self.assertEqual(result["args"], ["@modelcontextprotocol/server"])
167+
self.assertNotIn("name", result)
168+
self.assertNotIn("type", result)
169+
170+
171+
if __name__ == "__main__":
172+
unittest.main()
173+

0 commit comments

Comments
 (0)