hatch-xclam 0.7.1__py3-none-any.whl → 0.7.1.dev1__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.
- hatch/cli_hatch.py +21 -92
- hatch/mcp_host_config/__init__.py +2 -4
- hatch/mcp_host_config/backup.py +31 -62
- hatch/mcp_host_config/models.py +5 -98
- hatch/mcp_host_config/strategies.py +1 -172
- {hatch_xclam-0.7.1.dist-info → hatch_xclam-0.7.1.dev1.dist-info}/METADATA +3 -5
- {hatch_xclam-0.7.1.dist-info → hatch_xclam-0.7.1.dev1.dist-info}/RECORD +13 -16
- tests/test_mcp_cli_all_host_specific_args.py +1 -194
- tests/test_mcp_cli_direct_management.py +5 -8
- tests/regression/test_mcp_codex_backup_integration.py +0 -162
- tests/regression/test_mcp_codex_host_strategy.py +0 -163
- tests/regression/test_mcp_codex_model_validation.py +0 -117
- {hatch_xclam-0.7.1.dist-info → hatch_xclam-0.7.1.dev1.dist-info}/WHEEL +0 -0
- {hatch_xclam-0.7.1.dist-info → hatch_xclam-0.7.1.dev1.dist-info}/entry_points.txt +0 -0
- {hatch_xclam-0.7.1.dist-info → hatch_xclam-0.7.1.dev1.dist-info}/licenses/LICENSE +0 -0
- {hatch_xclam-0.7.1.dist-info → hatch_xclam-0.7.1.dev1.dist-info}/top_level.txt +0 -0
hatch/cli_hatch.py
CHANGED
|
@@ -716,12 +716,6 @@ def handle_mcp_configure(
|
|
|
716
716
|
disabled: Optional[bool] = None,
|
|
717
717
|
auto_approve_tools: Optional[list] = None,
|
|
718
718
|
disable_tools: Optional[list] = None,
|
|
719
|
-
env_vars: Optional[list] = None,
|
|
720
|
-
startup_timeout: Optional[int] = None,
|
|
721
|
-
tool_timeout: Optional[int] = None,
|
|
722
|
-
enabled: Optional[bool] = None,
|
|
723
|
-
bearer_token_env_var: Optional[str] = None,
|
|
724
|
-
env_header: Optional[list] = None,
|
|
725
719
|
no_backup: bool = False,
|
|
726
720
|
dry_run: bool = False,
|
|
727
721
|
auto_approve: bool = False,
|
|
@@ -843,27 +837,6 @@ def handle_mcp_configure(
|
|
|
843
837
|
if disable_tools is not None:
|
|
844
838
|
omni_config_data["disabledTools"] = disable_tools
|
|
845
839
|
|
|
846
|
-
# Host-specific fields (Codex)
|
|
847
|
-
if env_vars is not None:
|
|
848
|
-
omni_config_data["env_vars"] = env_vars
|
|
849
|
-
if startup_timeout is not None:
|
|
850
|
-
omni_config_data["startup_timeout_sec"] = startup_timeout
|
|
851
|
-
if tool_timeout is not None:
|
|
852
|
-
omni_config_data["tool_timeout_sec"] = tool_timeout
|
|
853
|
-
if enabled is not None:
|
|
854
|
-
omni_config_data["enabled"] = enabled
|
|
855
|
-
if bearer_token_env_var is not None:
|
|
856
|
-
omni_config_data["bearer_token_env_var"] = bearer_token_env_var
|
|
857
|
-
if env_header is not None:
|
|
858
|
-
# Parse KEY=ENV_VAR_NAME format into dict
|
|
859
|
-
env_http_headers = {}
|
|
860
|
-
for header_spec in env_header:
|
|
861
|
-
if '=' in header_spec:
|
|
862
|
-
key, env_var_name = header_spec.split('=', 1)
|
|
863
|
-
env_http_headers[key] = env_var_name
|
|
864
|
-
if env_http_headers:
|
|
865
|
-
omni_config_data["env_http_headers"] = env_http_headers
|
|
866
|
-
|
|
867
840
|
# Partial update merge logic
|
|
868
841
|
if is_update:
|
|
869
842
|
# Merge with existing configuration
|
|
@@ -1595,13 +1568,11 @@ def main():
|
|
|
1595
1568
|
mcp_configure_parser = mcp_subparsers.add_parser(
|
|
1596
1569
|
"configure", help="Configure MCP server directly on host"
|
|
1597
1570
|
)
|
|
1598
|
-
mcp_configure_parser.add_argument(
|
|
1599
|
-
"server_name", help="Name for the MCP server [hosts: all]"
|
|
1600
|
-
)
|
|
1571
|
+
mcp_configure_parser.add_argument("server_name", help="Name for the MCP server")
|
|
1601
1572
|
mcp_configure_parser.add_argument(
|
|
1602
1573
|
"--host",
|
|
1603
1574
|
required=True,
|
|
1604
|
-
help="Host platform to configure (e.g., claude-desktop, cursor)
|
|
1575
|
+
help="Host platform to configure (e.g., claude-desktop, cursor)",
|
|
1605
1576
|
)
|
|
1606
1577
|
|
|
1607
1578
|
# Create mutually exclusive group for server type
|
|
@@ -1609,125 +1580,89 @@ def main():
|
|
|
1609
1580
|
server_type_group.add_argument(
|
|
1610
1581
|
"--command",
|
|
1611
1582
|
dest="server_command",
|
|
1612
|
-
help="Command to execute the MCP server (for local servers)
|
|
1583
|
+
help="Command to execute the MCP server (for local servers)",
|
|
1613
1584
|
)
|
|
1614
1585
|
server_type_group.add_argument(
|
|
1615
|
-
"--url", help="Server URL for remote MCP servers (SSE transport)
|
|
1586
|
+
"--url", help="Server URL for remote MCP servers (SSE transport)"
|
|
1616
1587
|
)
|
|
1617
1588
|
server_type_group.add_argument(
|
|
1618
|
-
"--http-url", help="HTTP streaming endpoint URL
|
|
1589
|
+
"--http-url", help="HTTP streaming endpoint URL (Gemini only)"
|
|
1619
1590
|
)
|
|
1620
1591
|
|
|
1621
1592
|
mcp_configure_parser.add_argument(
|
|
1622
1593
|
"--args",
|
|
1623
1594
|
nargs="*",
|
|
1624
|
-
help="Arguments for the MCP server command (only with --command)
|
|
1595
|
+
help="Arguments for the MCP server command (only with --command)",
|
|
1625
1596
|
)
|
|
1626
1597
|
mcp_configure_parser.add_argument(
|
|
1627
|
-
"--env-var",
|
|
1628
|
-
action="append",
|
|
1629
|
-
help="Environment variables (format: KEY=VALUE) [hosts: all]",
|
|
1598
|
+
"--env-var", action="append", help="Environment variables (format: KEY=VALUE)"
|
|
1630
1599
|
)
|
|
1631
1600
|
mcp_configure_parser.add_argument(
|
|
1632
1601
|
"--header",
|
|
1633
1602
|
action="append",
|
|
1634
|
-
help="HTTP headers for remote servers (format: KEY=VALUE, only with --url)
|
|
1603
|
+
help="HTTP headers for remote servers (format: KEY=VALUE, only with --url)",
|
|
1635
1604
|
)
|
|
1636
1605
|
|
|
1637
1606
|
# Host-specific arguments (Gemini)
|
|
1638
1607
|
mcp_configure_parser.add_argument(
|
|
1639
|
-
"--timeout", type=int, help="Request timeout in milliseconds
|
|
1608
|
+
"--timeout", type=int, help="Request timeout in milliseconds (Gemini)"
|
|
1640
1609
|
)
|
|
1641
1610
|
mcp_configure_parser.add_argument(
|
|
1642
|
-
"--trust", action="store_true", help="Bypass tool call confirmations
|
|
1611
|
+
"--trust", action="store_true", help="Bypass tool call confirmations (Gemini)"
|
|
1643
1612
|
)
|
|
1644
1613
|
mcp_configure_parser.add_argument(
|
|
1645
|
-
"--cwd", help="Working directory for stdio transport
|
|
1614
|
+
"--cwd", help="Working directory for stdio transport (Gemini)"
|
|
1646
1615
|
)
|
|
1647
1616
|
mcp_configure_parser.add_argument(
|
|
1648
1617
|
"--include-tools",
|
|
1649
1618
|
nargs="*",
|
|
1650
|
-
help="Tool allowlist
|
|
1619
|
+
help="Tool allowlist - only these tools will be available (Gemini)",
|
|
1651
1620
|
)
|
|
1652
1621
|
mcp_configure_parser.add_argument(
|
|
1653
1622
|
"--exclude-tools",
|
|
1654
1623
|
nargs="*",
|
|
1655
|
-
help="Tool blocklist
|
|
1624
|
+
help="Tool blocklist - these tools will be excluded (Gemini)",
|
|
1656
1625
|
)
|
|
1657
1626
|
|
|
1658
1627
|
# Host-specific arguments (Cursor/VS Code/LM Studio)
|
|
1659
1628
|
mcp_configure_parser.add_argument(
|
|
1660
|
-
"--env-file", help="Path to environment file
|
|
1629
|
+
"--env-file", help="Path to environment file (Cursor, VS Code, LM Studio)"
|
|
1661
1630
|
)
|
|
1662
1631
|
|
|
1663
1632
|
# Host-specific arguments (VS Code)
|
|
1664
1633
|
mcp_configure_parser.add_argument(
|
|
1665
1634
|
"--input",
|
|
1666
1635
|
action="append",
|
|
1667
|
-
help="Input variable definitions in format: type,id,description[,password=true]
|
|
1636
|
+
help="Input variable definitions in format: type,id,description[,password=true] (VS Code)",
|
|
1668
1637
|
)
|
|
1669
1638
|
|
|
1670
1639
|
# Host-specific arguments (Kiro)
|
|
1671
1640
|
mcp_configure_parser.add_argument(
|
|
1672
1641
|
"--disabled",
|
|
1673
1642
|
action="store_true",
|
|
1674
|
-
|
|
1675
|
-
help="Disable the MCP server [hosts: kiro]"
|
|
1643
|
+
help="Disable the MCP server (Kiro)"
|
|
1676
1644
|
)
|
|
1677
1645
|
mcp_configure_parser.add_argument(
|
|
1678
1646
|
"--auto-approve-tools",
|
|
1679
1647
|
action="append",
|
|
1680
|
-
help="Tool names to auto-approve without prompting
|
|
1648
|
+
help="Tool names to auto-approve without prompting (Kiro)"
|
|
1681
1649
|
)
|
|
1682
1650
|
mcp_configure_parser.add_argument(
|
|
1683
1651
|
"--disable-tools",
|
|
1684
1652
|
action="append",
|
|
1685
|
-
help="Tool names to disable
|
|
1686
|
-
)
|
|
1687
|
-
|
|
1688
|
-
# Codex-specific arguments
|
|
1689
|
-
mcp_configure_parser.add_argument(
|
|
1690
|
-
"--env-vars",
|
|
1691
|
-
action="append",
|
|
1692
|
-
help="Environment variable names to whitelist/forward [hosts: codex]"
|
|
1693
|
-
)
|
|
1694
|
-
mcp_configure_parser.add_argument(
|
|
1695
|
-
"--startup-timeout",
|
|
1696
|
-
type=int,
|
|
1697
|
-
help="Server startup timeout in seconds (default: 10) [hosts: codex]"
|
|
1698
|
-
)
|
|
1699
|
-
mcp_configure_parser.add_argument(
|
|
1700
|
-
"--tool-timeout",
|
|
1701
|
-
type=int,
|
|
1702
|
-
help="Tool execution timeout in seconds (default: 60) [hosts: codex]"
|
|
1703
|
-
)
|
|
1704
|
-
mcp_configure_parser.add_argument(
|
|
1705
|
-
"--enabled",
|
|
1706
|
-
action="store_true",
|
|
1707
|
-
default=None,
|
|
1708
|
-
help="Enable the MCP server [hosts: codex]"
|
|
1709
|
-
)
|
|
1710
|
-
mcp_configure_parser.add_argument(
|
|
1711
|
-
"--bearer-token-env-var",
|
|
1712
|
-
type=str,
|
|
1713
|
-
help="Name of environment variable containing bearer token for Authorization header [hosts: codex]"
|
|
1714
|
-
)
|
|
1715
|
-
mcp_configure_parser.add_argument(
|
|
1716
|
-
"--env-header",
|
|
1717
|
-
action="append",
|
|
1718
|
-
help="HTTP header from environment variable in KEY=ENV_VAR_NAME format [hosts: codex]"
|
|
1653
|
+
help="Tool names to disable (Kiro)"
|
|
1719
1654
|
)
|
|
1720
1655
|
|
|
1721
1656
|
mcp_configure_parser.add_argument(
|
|
1722
1657
|
"--no-backup",
|
|
1723
1658
|
action="store_true",
|
|
1724
|
-
help="Skip backup creation before configuration
|
|
1659
|
+
help="Skip backup creation before configuration",
|
|
1725
1660
|
)
|
|
1726
1661
|
mcp_configure_parser.add_argument(
|
|
1727
|
-
"--dry-run", action="store_true", help="Preview configuration without execution
|
|
1662
|
+
"--dry-run", action="store_true", help="Preview configuration without execution"
|
|
1728
1663
|
)
|
|
1729
1664
|
mcp_configure_parser.add_argument(
|
|
1730
|
-
"--auto-approve", action="store_true", help="Skip confirmation prompts
|
|
1665
|
+
"--auto-approve", action="store_true", help="Skip confirmation prompts"
|
|
1731
1666
|
)
|
|
1732
1667
|
|
|
1733
1668
|
# Remove MCP commands (object-action pattern)
|
|
@@ -2789,12 +2724,6 @@ def main():
|
|
|
2789
2724
|
getattr(args, "disabled", None),
|
|
2790
2725
|
getattr(args, "auto_approve_tools", None),
|
|
2791
2726
|
getattr(args, "disable_tools", None),
|
|
2792
|
-
getattr(args, "env_vars", None),
|
|
2793
|
-
getattr(args, "startup_timeout", None),
|
|
2794
|
-
getattr(args, "tool_timeout", None),
|
|
2795
|
-
getattr(args, "enabled", None),
|
|
2796
|
-
getattr(args, "bearer_token_env_var", None),
|
|
2797
|
-
getattr(args, "env_header", None),
|
|
2798
2727
|
args.no_backup,
|
|
2799
2728
|
args.dry_run,
|
|
2800
2729
|
args.auto_approve,
|
|
@@ -11,8 +11,7 @@ from .models import (
|
|
|
11
11
|
PackageHostConfiguration, EnvironmentPackageEntry, ConfigurationResult, SyncResult,
|
|
12
12
|
# Host-specific configuration models
|
|
13
13
|
MCPServerConfigBase, MCPServerConfigGemini, MCPServerConfigVSCode,
|
|
14
|
-
MCPServerConfigCursor, MCPServerConfigClaude, MCPServerConfigKiro,
|
|
15
|
-
MCPServerConfigCodex, MCPServerConfigOmni,
|
|
14
|
+
MCPServerConfigCursor, MCPServerConfigClaude, MCPServerConfigKiro, MCPServerConfigOmni,
|
|
16
15
|
HOST_MODEL_REGISTRY
|
|
17
16
|
)
|
|
18
17
|
from .host_management import (
|
|
@@ -31,8 +30,7 @@ __all__ = [
|
|
|
31
30
|
'PackageHostConfiguration', 'EnvironmentPackageEntry', 'ConfigurationResult', 'SyncResult',
|
|
32
31
|
# Host-specific configuration models
|
|
33
32
|
'MCPServerConfigBase', 'MCPServerConfigGemini', 'MCPServerConfigVSCode',
|
|
34
|
-
'MCPServerConfigCursor', 'MCPServerConfigClaude', 'MCPServerConfigKiro',
|
|
35
|
-
'MCPServerConfigCodex', 'MCPServerConfigOmni',
|
|
33
|
+
'MCPServerConfigCursor', 'MCPServerConfigClaude', 'MCPServerConfigKiro', 'MCPServerConfigOmni',
|
|
36
34
|
'HOST_MODEL_REGISTRY',
|
|
37
35
|
# User feedback reporting
|
|
38
36
|
'FieldOperation', 'ConversionReport', 'generate_conversion_report', 'display_report',
|
hatch/mcp_host_config/backup.py
CHANGED
|
@@ -9,7 +9,7 @@ import shutil
|
|
|
9
9
|
import tempfile
|
|
10
10
|
from datetime import datetime
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Dict, List, Optional, Any
|
|
12
|
+
from typing import Dict, List, Optional, Any
|
|
13
13
|
|
|
14
14
|
from pydantic import BaseModel, Field, validator
|
|
15
15
|
|
|
@@ -36,8 +36,8 @@ class BackupInfo(BaseModel):
|
|
|
36
36
|
def validate_hostname(cls, v):
|
|
37
37
|
"""Validate hostname is supported."""
|
|
38
38
|
supported_hosts = {
|
|
39
|
-
'claude-desktop', 'claude-code', 'vscode',
|
|
40
|
-
'cursor', 'lmstudio', 'gemini', 'kiro'
|
|
39
|
+
'claude-desktop', 'claude-code', 'vscode',
|
|
40
|
+
'cursor', 'lmstudio', 'gemini', 'kiro'
|
|
41
41
|
}
|
|
42
42
|
if v not in supported_hosts:
|
|
43
43
|
raise ValueError(f"Unsupported hostname: {v}. Supported: {supported_hosts}")
|
|
@@ -53,9 +53,7 @@ class BackupInfo(BaseModel):
|
|
|
53
53
|
@property
|
|
54
54
|
def backup_name(self) -> str:
|
|
55
55
|
"""Get backup filename."""
|
|
56
|
-
|
|
57
|
-
# Backup filename format: {original_name}.{hostname}.{timestamp}
|
|
58
|
-
return self.file_path.name
|
|
56
|
+
return f"mcp.json.{self.hostname}.{self.timestamp.strftime('%Y%m%d_%H%M%S_%f')}"
|
|
59
57
|
|
|
60
58
|
@property
|
|
61
59
|
def age_days(self) -> int:
|
|
@@ -103,29 +101,22 @@ class BackupResult(BaseModel):
|
|
|
103
101
|
|
|
104
102
|
class AtomicFileOperations:
|
|
105
103
|
"""Atomic file operations for safe configuration updates."""
|
|
106
|
-
|
|
107
|
-
def
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
backup_manager: "MCPHostConfigBackupManager",
|
|
113
|
-
hostname: str,
|
|
114
|
-
skip_backup: bool = False
|
|
115
|
-
) -> bool:
|
|
116
|
-
"""Atomic write with custom serializer and automatic backup creation.
|
|
117
|
-
|
|
104
|
+
|
|
105
|
+
def atomic_write_with_backup(self, file_path: Path, data: Dict[str, Any],
|
|
106
|
+
backup_manager: "MCPHostConfigBackupManager",
|
|
107
|
+
hostname: str, skip_backup: bool = False) -> bool:
|
|
108
|
+
"""Atomic write with automatic backup creation.
|
|
109
|
+
|
|
118
110
|
Args:
|
|
119
|
-
file_path: Target file path for writing
|
|
120
|
-
data: Data to
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
111
|
+
file_path (Path): Target file path for writing
|
|
112
|
+
data (Dict[str, Any]): Data to write as JSON
|
|
113
|
+
backup_manager (MCPHostConfigBackupManager): Backup manager instance
|
|
114
|
+
hostname (str): Host identifier for backup
|
|
115
|
+
skip_backup (bool, optional): Skip backup creation. Defaults to False.
|
|
116
|
+
|
|
126
117
|
Returns:
|
|
127
|
-
bool: True if operation successful
|
|
128
|
-
|
|
118
|
+
bool: True if operation successful, False otherwise
|
|
119
|
+
|
|
129
120
|
Raises:
|
|
130
121
|
BackupError: If backup creation fails and skip_backup is False
|
|
131
122
|
"""
|
|
@@ -135,52 +126,32 @@ class AtomicFileOperations:
|
|
|
135
126
|
backup_result = backup_manager.create_backup(file_path, hostname)
|
|
136
127
|
if not backup_result.success:
|
|
137
128
|
raise BackupError(f"Required backup failed: {backup_result.error_message}")
|
|
138
|
-
|
|
129
|
+
|
|
130
|
+
# Create temporary file for atomic write
|
|
139
131
|
temp_file = None
|
|
140
132
|
try:
|
|
133
|
+
# Write to temporary file first
|
|
141
134
|
temp_file = file_path.with_suffix(f"{file_path.suffix}.tmp")
|
|
142
135
|
with open(temp_file, 'w', encoding='utf-8') as f:
|
|
143
|
-
|
|
144
|
-
|
|
136
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
137
|
+
|
|
138
|
+
# Atomic move to target location
|
|
145
139
|
temp_file.replace(file_path)
|
|
146
140
|
return True
|
|
147
|
-
|
|
141
|
+
|
|
148
142
|
except Exception as e:
|
|
143
|
+
# Clean up temporary file on failure
|
|
149
144
|
if temp_file and temp_file.exists():
|
|
150
145
|
temp_file.unlink()
|
|
151
|
-
|
|
146
|
+
|
|
147
|
+
# Restore from backup if available
|
|
152
148
|
if backup_result and backup_result.backup_path:
|
|
153
149
|
try:
|
|
154
150
|
backup_manager.restore_backup(hostname, backup_result.backup_path.name)
|
|
155
151
|
except Exception:
|
|
156
|
-
pass
|
|
157
|
-
|
|
152
|
+
pass # Log but don't raise - original error is more important
|
|
153
|
+
|
|
158
154
|
raise BackupError(f"Atomic write failed: {str(e)}")
|
|
159
|
-
|
|
160
|
-
def atomic_write_with_backup(self, file_path: Path, data: Dict[str, Any],
|
|
161
|
-
backup_manager: "MCPHostConfigBackupManager",
|
|
162
|
-
hostname: str, skip_backup: bool = False) -> bool:
|
|
163
|
-
"""Atomic write with JSON serialization (backward compatible).
|
|
164
|
-
|
|
165
|
-
Args:
|
|
166
|
-
file_path (Path): Target file path for writing
|
|
167
|
-
data (Dict[str, Any]): Data to write as JSON
|
|
168
|
-
backup_manager (MCPHostConfigBackupManager): Backup manager instance
|
|
169
|
-
hostname (str): Host identifier for backup
|
|
170
|
-
skip_backup (bool, optional): Skip backup creation. Defaults to False.
|
|
171
|
-
|
|
172
|
-
Returns:
|
|
173
|
-
bool: True if operation successful, False otherwise
|
|
174
|
-
|
|
175
|
-
Raises:
|
|
176
|
-
BackupError: If backup creation fails and skip_backup is False
|
|
177
|
-
"""
|
|
178
|
-
def json_serializer(data: Any, f: TextIO) -> None:
|
|
179
|
-
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
180
|
-
|
|
181
|
-
return self.atomic_write_with_serializer(
|
|
182
|
-
file_path, data, json_serializer, backup_manager, hostname, skip_backup
|
|
183
|
-
)
|
|
184
155
|
|
|
185
156
|
def atomic_copy(self, source: Path, target: Path) -> bool:
|
|
186
157
|
"""Atomic file copy operation.
|
|
@@ -257,10 +228,8 @@ class MCPHostConfigBackupManager:
|
|
|
257
228
|
host_backup_dir.mkdir(exist_ok=True)
|
|
258
229
|
|
|
259
230
|
# Generate timestamped backup filename with microseconds for uniqueness
|
|
260
|
-
# Preserve original filename instead of hardcoding 'mcp.json'
|
|
261
231
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
|
262
|
-
|
|
263
|
-
backup_name = f"{original_filename}.{hostname}.{timestamp}"
|
|
232
|
+
backup_name = f"mcp.json.{hostname}.{timestamp}"
|
|
264
233
|
backup_path = host_backup_dir / backup_name
|
|
265
234
|
|
|
266
235
|
# Get original file size
|
hatch/mcp_host_config/models.py
CHANGED
|
@@ -25,7 +25,6 @@ class MCPHostType(str, Enum):
|
|
|
25
25
|
LMSTUDIO = "lmstudio"
|
|
26
26
|
GEMINI = "gemini"
|
|
27
27
|
KIRO = "kiro"
|
|
28
|
-
CODEX = "codex"
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
class MCPServerConfig(BaseModel):
|
|
@@ -542,108 +541,28 @@ class MCPServerConfigClaude(MCPServerConfigBase):
|
|
|
542
541
|
|
|
543
542
|
class MCPServerConfigKiro(MCPServerConfigBase):
|
|
544
543
|
"""Kiro IDE-specific MCP server configuration.
|
|
545
|
-
|
|
544
|
+
|
|
546
545
|
Extends base model with Kiro-specific fields for server management
|
|
547
546
|
and tool control.
|
|
548
547
|
"""
|
|
549
|
-
|
|
548
|
+
|
|
550
549
|
# Kiro-specific fields
|
|
551
550
|
disabled: Optional[bool] = Field(None, description="Whether server is disabled")
|
|
552
551
|
autoApprove: Optional[List[str]] = Field(None, description="Auto-approved tool names")
|
|
553
552
|
disabledTools: Optional[List[str]] = Field(None, description="Disabled tool names")
|
|
554
|
-
|
|
553
|
+
|
|
555
554
|
@classmethod
|
|
556
555
|
def from_omni(cls, omni: 'MCPServerConfigOmni') -> 'MCPServerConfigKiro':
|
|
557
556
|
"""Convert Omni model to Kiro-specific model."""
|
|
558
557
|
# Get supported fields dynamically
|
|
559
558
|
supported_fields = set(cls.model_fields.keys())
|
|
560
|
-
|
|
559
|
+
|
|
561
560
|
# Single-call field filtering
|
|
562
561
|
kiro_data = omni.model_dump(include=supported_fields, exclude_unset=True)
|
|
563
|
-
|
|
562
|
+
|
|
564
563
|
return cls.model_validate(kiro_data)
|
|
565
564
|
|
|
566
565
|
|
|
567
|
-
class MCPServerConfigCodex(MCPServerConfigBase):
|
|
568
|
-
"""Codex-specific MCP server configuration.
|
|
569
|
-
|
|
570
|
-
Extends base model with Codex-specific fields including timeouts,
|
|
571
|
-
tool filtering, environment variable forwarding, and HTTP authentication.
|
|
572
|
-
"""
|
|
573
|
-
|
|
574
|
-
model_config = ConfigDict(extra="forbid")
|
|
575
|
-
|
|
576
|
-
# Codex-specific STDIO fields
|
|
577
|
-
env_vars: Optional[List[str]] = Field(
|
|
578
|
-
None,
|
|
579
|
-
description="Environment variables to whitelist/forward"
|
|
580
|
-
)
|
|
581
|
-
cwd: Optional[str] = Field(
|
|
582
|
-
None,
|
|
583
|
-
description="Working directory to launch server from"
|
|
584
|
-
)
|
|
585
|
-
|
|
586
|
-
# Timeout configuration
|
|
587
|
-
startup_timeout_sec: Optional[int] = Field(
|
|
588
|
-
None,
|
|
589
|
-
description="Server startup timeout in seconds (default: 10)"
|
|
590
|
-
)
|
|
591
|
-
tool_timeout_sec: Optional[int] = Field(
|
|
592
|
-
None,
|
|
593
|
-
description="Tool execution timeout in seconds (default: 60)"
|
|
594
|
-
)
|
|
595
|
-
|
|
596
|
-
# Server control
|
|
597
|
-
enabled: Optional[bool] = Field(
|
|
598
|
-
None,
|
|
599
|
-
description="Enable/disable server without deleting config"
|
|
600
|
-
)
|
|
601
|
-
enabled_tools: Optional[List[str]] = Field(
|
|
602
|
-
None,
|
|
603
|
-
description="Allow-list of tools to expose from server"
|
|
604
|
-
)
|
|
605
|
-
disabled_tools: Optional[List[str]] = Field(
|
|
606
|
-
None,
|
|
607
|
-
description="Deny-list of tools to hide (applied after enabled_tools)"
|
|
608
|
-
)
|
|
609
|
-
|
|
610
|
-
# HTTP authentication fields
|
|
611
|
-
bearer_token_env_var: Optional[str] = Field(
|
|
612
|
-
None,
|
|
613
|
-
description="Name of env var containing bearer token for Authorization header"
|
|
614
|
-
)
|
|
615
|
-
http_headers: Optional[Dict[str, str]] = Field(
|
|
616
|
-
None,
|
|
617
|
-
description="Map of header names to static values"
|
|
618
|
-
)
|
|
619
|
-
env_http_headers: Optional[Dict[str, str]] = Field(
|
|
620
|
-
None,
|
|
621
|
-
description="Map of header names to env var names (values pulled from env)"
|
|
622
|
-
)
|
|
623
|
-
|
|
624
|
-
@classmethod
|
|
625
|
-
def from_omni(cls, omni: 'MCPServerConfigOmni') -> 'MCPServerConfigCodex':
|
|
626
|
-
"""Convert Omni model to Codex-specific model.
|
|
627
|
-
|
|
628
|
-
Maps universal 'headers' field to Codex-specific 'http_headers' field.
|
|
629
|
-
"""
|
|
630
|
-
supported_fields = set(cls.model_fields.keys())
|
|
631
|
-
codex_data = omni.model_dump(include=supported_fields, exclude_unset=True)
|
|
632
|
-
|
|
633
|
-
# Map shared CLI tool filtering flags (Gemini naming) to Codex naming.
|
|
634
|
-
# This lets `--include-tools/--exclude-tools` work for both Gemini and Codex.
|
|
635
|
-
if getattr(omni, 'includeTools', None) is not None and codex_data.get('enabled_tools') is None:
|
|
636
|
-
codex_data['enabled_tools'] = omni.includeTools
|
|
637
|
-
if getattr(omni, 'excludeTools', None) is not None and codex_data.get('disabled_tools') is None:
|
|
638
|
-
codex_data['disabled_tools'] = omni.excludeTools
|
|
639
|
-
|
|
640
|
-
# Map universal 'headers' to Codex 'http_headers'
|
|
641
|
-
if hasattr(omni, 'headers') and omni.headers is not None:
|
|
642
|
-
codex_data['http_headers'] = omni.headers
|
|
643
|
-
|
|
644
|
-
return cls.model_validate(codex_data)
|
|
645
|
-
|
|
646
|
-
|
|
647
566
|
class MCPServerConfigOmni(BaseModel):
|
|
648
567
|
"""Omni configuration supporting all host-specific fields.
|
|
649
568
|
|
|
@@ -692,17 +611,6 @@ class MCPServerConfigOmni(BaseModel):
|
|
|
692
611
|
autoApprove: Optional[List[str]] = None
|
|
693
612
|
disabledTools: Optional[List[str]] = None
|
|
694
613
|
|
|
695
|
-
# Codex specific
|
|
696
|
-
env_vars: Optional[List[str]] = None
|
|
697
|
-
startup_timeout_sec: Optional[int] = None
|
|
698
|
-
tool_timeout_sec: Optional[int] = None
|
|
699
|
-
enabled: Optional[bool] = None
|
|
700
|
-
enabled_tools: Optional[List[str]] = None
|
|
701
|
-
disabled_tools: Optional[List[str]] = None
|
|
702
|
-
bearer_token_env_var: Optional[str] = None
|
|
703
|
-
env_http_headers: Optional[Dict[str, str]] = None
|
|
704
|
-
# Note: http_headers maps to universal 'headers' field, not a separate Codex field
|
|
705
|
-
|
|
706
614
|
@field_validator('url')
|
|
707
615
|
@classmethod
|
|
708
616
|
def validate_url_format(cls, v):
|
|
@@ -722,5 +630,4 @@ HOST_MODEL_REGISTRY: Dict[MCPHostType, type[MCPServerConfigBase]] = {
|
|
|
722
630
|
MCPHostType.CURSOR: MCPServerConfigCursor,
|
|
723
631
|
MCPHostType.LMSTUDIO: MCPServerConfigCursor, # Same as CURSOR
|
|
724
632
|
MCPHostType.KIRO: MCPServerConfigKiro,
|
|
725
|
-
MCPHostType.CODEX: MCPServerConfigCodex,
|
|
726
633
|
}
|