Skip to content

Commit 2bb1d3c

Browse files
author
LittleCoinCoin
committed
docs(reports): dev specs for Codex MCP config support via Hatch!
1 parent 402eded commit 2bb1d3c

File tree

5 files changed

+1976
-0
lines changed

5 files changed

+1976
-0
lines changed
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
# Codex MCP Host Support Feasibility Analysis
2+
3+
## Executive Summary
4+
5+
**FEASIBILITY: ✅ HIGHLY FEASIBLE**
6+
7+
Adding Codex MCP host support to Hatch is highly feasible within the current architecture. The existing strategy pattern with decorator-based registration is excellently designed for format diversity, requiring only moderate enhancements to support TOML configuration files. No extensive refactoring is needed.
8+
9+
## Current Architecture Analysis
10+
11+
### Strategy Pattern Excellence
12+
13+
The MCP host configuration system uses a well-designed strategy pattern that perfectly accommodates format diversity:
14+
15+
```python
16+
# hatch/mcp_host_config/strategies.py
17+
@register_host_strategy(MCPHostType.CLAUDE_DESKTOP)
18+
class ClaudeDesktopStrategy(ClaudeHostStrategy):
19+
def read_configuration(self) -> HostConfiguration: # Format-specific
20+
def write_configuration(self, config: HostConfiguration) -> bool: # Format-specific
21+
```
22+
23+
**Key Architectural Strengths:**
24+
- **Format Encapsulation**: Each strategy completely encapsulates its file format handling
25+
- **Interface Consistency**: All strategies work with format-agnostic `HostConfiguration` objects
26+
- **Automatic Registration**: Decorator system automatically discovers new host types
27+
- **Family Inheritance**: Base classes (`ClaudeHostStrategy`, `CursorBasedHostStrategy`) enable code reuse
28+
29+
### Data Model Flexibility
30+
31+
The Pydantic model system is already designed for host-specific extensions:
32+
33+
```python
34+
# hatch/mcp_host_config/models.py
35+
class MCPServerConfigBase(BaseModel):
36+
# Universal fields: command, args, env, url, headers, type
37+
38+
class MCPServerConfigGemini(MCPServerConfigBase):
39+
# Gemini-specific: cwd, timeout, trust, oauth_* fields
40+
41+
class MCPServerConfigVSCode(MCPServerConfigBase):
42+
# VS Code-specific: envFile, inputs fields
43+
```
44+
45+
**Pattern Compatibility:**
46+
- `MCPServerConfigCodex` can extend `MCPServerConfigBase` following established patterns
47+
- `HOST_MODEL_REGISTRY` already supports host-specific model mapping
48+
- Pydantic validation works regardless of serialization format
49+
50+
### File Operations Infrastructure
51+
52+
Current file operations are JSON-focused but architecturally sound:
53+
54+
```python
55+
# hatch/mcp_host_config/backup.py
56+
class AtomicFileOperations:
57+
def atomic_write_with_backup(self, file_path: Path, data: Dict[str, Any], ...):
58+
# Currently hardcoded to json.dump()
59+
```
60+
61+
**Infrastructure Assessment:**
62+
-**Backup Creation**: Uses `shutil.copy2()` - format independent
63+
-**Atomic Operations**: Core logic is format-agnostic
64+
-**Serialization**: Hardcoded to JSON format
65+
-**File Extensions**: Assumes `.json` in backup naming
66+
67+
## Codex Configuration Requirements
68+
69+
### TOML Structure Analysis
70+
71+
Codex uses TOML configuration at `~/.codex/config.toml`:
72+
73+
```toml
74+
[features]
75+
rmcp_client = true
76+
77+
[mcp_servers.context7]
78+
command = "npx"
79+
args = ["-y", "@upstash/context7-mcp"]
80+
startup_timeout_sec = 10
81+
tool_timeout_sec = 60
82+
enabled = true
83+
enabled_tools = ["tool1", "tool2"]
84+
85+
[mcp_servers.context7.env]
86+
MY_VAR = "value"
87+
88+
[mcp_servers.figma]
89+
url = "https://mcp.figma.com/mcp"
90+
bearer_token_env_var = "FIGMA_OAUTH_TOKEN"
91+
http_headers = { "X-Figma-Region" = "us-east-1" }
92+
```
93+
94+
### Codex-Specific Fields
95+
96+
**Standard Fields** (already supported):
97+
- `command`, `args`, `env` - Local server configuration
98+
- `url` - Remote server configuration
99+
100+
**Codex-Specific Fields** (require new model):
101+
- `env_vars: List[str]` - Environment variables to forward
102+
- `cwd: str` - Working directory for server
103+
- `startup_timeout_sec: int` - Server startup timeout
104+
- `tool_timeout_sec: int` - Tool execution timeout
105+
- `enabled: bool` - Enable/disable server
106+
- `enabled_tools: List[str]` - Tool allowlist
107+
- `disabled_tools: List[str]` - Tool denylist
108+
- `bearer_token_env_var: str` - Bearer token environment variable
109+
- `http_headers: Dict[str, str]` - Static HTTP headers
110+
- `env_http_headers: Dict[str, str]` - HTTP headers from environment
111+
112+
**Global Configuration:**
113+
- `[features].rmcp_client: bool` - Enable Rust MCP client
114+
115+
## Implementation Architecture
116+
117+
### Phase 1: Data Model Extension
118+
119+
```python
120+
# hatch/mcp_host_config/models.py
121+
class MCPHostType(str, Enum):
122+
# ... existing hosts ...
123+
CODEX = "codex"
124+
125+
class MCPServerConfigCodex(MCPServerConfigBase):
126+
"""Codex-specific MCP server configuration."""
127+
128+
# Codex-specific fields
129+
env_vars: Optional[List[str]] = Field(None, description="Environment variables to forward")
130+
cwd: Optional[str] = Field(None, description="Working directory")
131+
startup_timeout_sec: Optional[int] = Field(None, description="Server startup timeout")
132+
tool_timeout_sec: Optional[int] = Field(None, description="Tool execution timeout")
133+
enabled: Optional[bool] = Field(None, description="Enable/disable server")
134+
enabled_tools: Optional[List[str]] = Field(None, description="Tool allowlist")
135+
disabled_tools: Optional[List[str]] = Field(None, description="Tool denylist")
136+
137+
# HTTP-specific fields
138+
bearer_token_env_var: Optional[str] = Field(None, description="Bearer token env var")
139+
http_headers: Optional[Dict[str, str]] = Field(None, description="Static HTTP headers")
140+
env_http_headers: Optional[Dict[str, str]] = Field(None, description="HTTP headers from env")
141+
142+
# Update registry
143+
HOST_MODEL_REGISTRY[MCPHostType.CODEX] = MCPServerConfigCodex
144+
```
145+
146+
### Phase 2: Strategy Implementation
147+
148+
```python
149+
# hatch/mcp_host_config/strategies.py
150+
@register_host_strategy(MCPHostType.CODEX)
151+
class CodexHostStrategy(MCPHostStrategy):
152+
"""Configuration strategy for Codex IDE with TOML support."""
153+
154+
def get_config_path(self) -> Optional[Path]:
155+
return Path.home() / ".codex" / "config.toml"
156+
157+
def read_configuration(self) -> HostConfiguration:
158+
# TOML parsing logic
159+
# Handle [mcp_servers.*] sections
160+
# Convert to HostConfiguration
161+
162+
def write_configuration(self, config: HostConfiguration, no_backup: bool = False) -> bool:
163+
# Preserve [features] section
164+
# Convert HostConfiguration to TOML structure
165+
# Atomic TOML write operation
166+
```
167+
168+
### Phase 3: Backup System Enhancement
169+
170+
```python
171+
# hatch/mcp_host_config/backup.py
172+
class AtomicFileOperations:
173+
def atomic_write_with_serializer(self, file_path: Path, data: Any,
174+
serializer: Callable[[Any, TextIO], None],
175+
backup_manager: "MCPHostConfigBackupManager",
176+
hostname: str, skip_backup: bool = False) -> bool:
177+
# Generalized atomic write with custom serializer
178+
179+
def atomic_write_with_backup(self, file_path: Path, data: Dict[str, Any], ...):
180+
# Backward compatibility wrapper using JSON serializer
181+
```
182+
183+
## Technical Implementation Details
184+
185+
### TOML Serialization Strategy
186+
187+
```python
188+
def _convert_to_toml_structure(self, config: HostConfiguration) -> Dict[str, Any]:
189+
"""Convert HostConfiguration to Codex TOML structure."""
190+
toml_data = {}
191+
192+
# Preserve existing [features] section
193+
if self._existing_features:
194+
toml_data["features"] = self._existing_features
195+
196+
# Convert servers to [mcp_servers.*] sections
197+
toml_data["mcp_servers"] = {}
198+
for name, server_config in config.servers.items():
199+
server_dict = server_config.model_dump(exclude_none=True)
200+
201+
# Handle nested env section
202+
if "env" in server_dict:
203+
env_data = server_dict.pop("env")
204+
toml_data["mcp_servers"][name] = server_dict
205+
toml_data["mcp_servers"][name]["env"] = env_data
206+
else:
207+
toml_data["mcp_servers"][name] = server_dict
208+
209+
return toml_data
210+
```
211+
212+
### Dependency Requirements
213+
214+
```python
215+
# pyproject.toml
216+
[project]
217+
dependencies = [
218+
# ... existing dependencies ...
219+
"tomli-w>=1.0.0", # TOML writing
220+
"tomli>=1.2.0; python_version<'3.11'", # TOML reading for Python <3.11
221+
]
222+
```
223+
224+
## Risk Assessment
225+
226+
### Low Risk Components
227+
- **Strategy Registration**: Existing decorator system handles new hosts automatically
228+
- **Data Validation**: Pydantic models provide robust validation regardless of format
229+
- **Interface Compatibility**: No changes to core interfaces required
230+
231+
### Medium Risk Components
232+
- **TOML Serialization**: Need to handle nested structures and preserve global sections
233+
- **Backup System**: Requires refactoring to support multiple formats
234+
- **File Extension Handling**: Update backup naming for `.toml` files
235+
236+
### Mitigation Strategies
237+
- **Comprehensive Testing**: Unit tests for TOML serialization/deserialization
238+
- **Backward Compatibility**: Ensure existing JSON-based hosts remain unaffected
239+
- **Incremental Implementation**: Phase-based approach allows validation at each step
240+
241+
## Architectural Workflow Diagram
242+
243+
```mermaid
244+
sequenceDiagram
245+
participant Client as Hatch CLI
246+
participant Manager as MCPHostConfigurationManager
247+
participant Registry as MCPHostRegistry
248+
participant Strategy as CodexHostStrategy
249+
participant FileOps as AtomicFileOperations
250+
participant TOML as TOML Parser
251+
252+
Client->>Manager: configure_server(codex_config)
253+
Manager->>Registry: get_strategy(MCPHostType.CODEX)
254+
Registry->>Strategy: return CodexHostStrategy instance
255+
Manager->>Strategy: validate_server_config()
256+
Strategy->>Manager: validation result
257+
Manager->>Strategy: read_configuration()
258+
Strategy->>TOML: parse ~/.codex/config.toml
259+
TOML->>Strategy: parsed TOML data
260+
Strategy->>Manager: HostConfiguration object
261+
Manager->>FileOps: atomic_write_with_serializer()
262+
FileOps->>Strategy: TOML serialization callback
263+
Strategy->>TOML: serialize to TOML format
264+
TOML->>FileOps: TOML string
265+
FileOps->>Manager: write success
266+
Manager->>Client: ConfigurationResult
267+
```
268+
269+
## Class Relationship Diagram
270+
271+
```mermaid
272+
classDiagram
273+
class MCPHostStrategy {
274+
<<abstract>>
275+
+get_config_path() Path
276+
+read_configuration() HostConfiguration
277+
+write_configuration() bool
278+
+validate_server_config() bool
279+
}
280+
281+
class CodexHostStrategy {
282+
+get_config_path() Path
283+
+read_configuration() HostConfiguration
284+
+write_configuration() bool
285+
+validate_server_config() bool
286+
-_parse_toml() Dict
287+
-_serialize_toml() str
288+
-_preserve_features() Dict
289+
}
290+
291+
class MCPServerConfigBase {
292+
+command: Optional[str]
293+
+args: Optional[List[str]]
294+
+env: Optional[Dict]
295+
+url: Optional[str]
296+
+type: Optional[str]
297+
}
298+
299+
class MCPServerConfigCodex {
300+
+env_vars: Optional[List[str]]
301+
+cwd: Optional[str]
302+
+startup_timeout_sec: Optional[int]
303+
+tool_timeout_sec: Optional[int]
304+
+enabled: Optional[bool]
305+
+enabled_tools: Optional[List[str]]
306+
+disabled_tools: Optional[List[str]]
307+
+bearer_token_env_var: Optional[str]
308+
+http_headers: Optional[Dict]
309+
+env_http_headers: Optional[Dict]
310+
}
311+
312+
class AtomicFileOperations {
313+
+atomic_write_with_backup() bool
314+
+atomic_write_with_serializer() bool
315+
+atomic_copy() bool
316+
}
317+
318+
MCPHostStrategy <|-- CodexHostStrategy
319+
MCPServerConfigBase <|-- MCPServerConfigCodex
320+
CodexHostStrategy --> AtomicFileOperations
321+
CodexHostStrategy --> MCPServerConfigCodex
322+
```
323+
324+
## Conclusion
325+
326+
The current MCP host configuration architecture is excellently designed for extensibility. Adding Codex support with TOML configuration files requires:
327+
328+
1. **Minimal Changes**: Add enum value, create Codex-specific model, implement strategy
329+
2. **Moderate Enhancements**: Generalize backup system for multi-format support
330+
3. **No Refactoring**: Core interfaces and existing strategies remain unchanged
331+
332+
The strategy pattern's encapsulation of format-specific logic makes this extension natural and low-risk. The implementation follows established patterns and maintains architectural consistency.
333+
334+
**Recommendation**: Proceed with implementation using the phased approach outlined above.
335+
336+
---
337+
338+
**Analysis Date**: December 14, 2025
339+
**Architecture Version**: Current state as of analysis
340+
**Risk Level**: Low to Medium
341+
**Implementation Effort**: Moderate (estimated 2-3 development cycles)

0 commit comments

Comments
 (0)