Skip to content

Commit 40faabb

Browse files
author
LittleCoinCoin
committed
feat: add host-specific CLI arguments for MCP configure command
- Add --timeout argument for Gemini (request timeout in milliseconds) - Add --trust argument for Gemini (bypass tool call confirmations) - Add --cwd argument for Gemini (working directory for stdio transport) - Add --env-file argument for Cursor/VS Code/LM Studio (path to environment file) Implementation details: - Updated handle_mcp_configure() signature with 4 new parameters - Added host-specific argument validation (error if used with incompatible hosts) - Integrated new fields into MCPServerConfigOmni creation - Updated argument parser with new CLI flags - Updated main() function call to pass new parameters Testing: - Created test_mcp_cli_host_specific_args.py with 12 comprehensive tests - Updated test_mcp_cli_direct_management.py to match new function signature - All 260 MCP tests passing (100% success rate) This implements Phase 2 of the original design specifications for commonly-used host-specific fields across Gemini, Cursor, and VS Code hosts.
1 parent 478c655 commit 40faabb

File tree

3 files changed

+360
-7
lines changed

3 files changed

+360
-7
lines changed

hatch/cli_hatch.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -584,9 +584,11 @@ def parse_headers(headers_list: Optional[list]) -> dict:
584584

585585
def handle_mcp_configure(host: str, server_name: str, command: str, args: list,
586586
env: Optional[list] = None, url: Optional[str] = None,
587-
headers: Optional[list] = None, no_backup: bool = False,
587+
headers: Optional[list] = None, timeout: Optional[int] = None,
588+
trust: bool = False, cwd: Optional[str] = None,
589+
env_file: Optional[str] = None, no_backup: bool = False,
588590
dry_run: bool = False, auto_approve: bool = False):
589-
"""Handle 'hatch mcp configure' command."""
591+
"""Handle 'hatch mcp configure' command with host-specific arguments."""
590592
try:
591593
# Validate host type
592594
try:
@@ -604,6 +606,23 @@ def handle_mcp_configure(host: str, server_name: str, command: str, args: list,
604606
print("Error: --args can only be used with --command (local servers), not with --url (remote servers)")
605607
return 1
606608

609+
# Validate host-specific arguments
610+
if timeout is not None and host_type != MCPHostType.GEMINI:
611+
print(f"Error: --timeout is only supported for Gemini host, not '{host}'")
612+
return 1
613+
614+
if trust and host_type != MCPHostType.GEMINI:
615+
print(f"Error: --trust is only supported for Gemini host, not '{host}'")
616+
return 1
617+
618+
if cwd is not None and host_type != MCPHostType.GEMINI:
619+
print(f"Error: --cwd is only supported for Gemini host, not '{host}'")
620+
return 1
621+
622+
if env_file is not None and host_type not in (MCPHostType.CURSOR, MCPHostType.VSCODE, MCPHostType.LMSTUDIO):
623+
print(f"Error: --env-file is only supported for Cursor, VS Code, and LM Studio hosts, not '{host}'")
624+
return 1
625+
607626
# Parse environment variables and headers
608627
env_dict = parse_env_vars(env)
609628
headers_dict = parse_headers(headers)
@@ -623,6 +642,16 @@ def handle_mcp_configure(host: str, server_name: str, command: str, args: list,
623642
if url and headers_dict:
624643
omni_config_data['headers'] = headers_dict
625644

645+
# Host-specific fields
646+
if timeout is not None:
647+
omni_config_data['timeout'] = timeout
648+
if trust:
649+
omni_config_data['trust'] = trust
650+
if cwd is not None:
651+
omni_config_data['cwd'] = cwd
652+
if env_file is not None:
653+
omni_config_data['envFile'] = env_file
654+
626655
# Create Omni model
627656
omni_config = MCPServerConfigOmni(**omni_config_data)
628657

@@ -1144,6 +1173,13 @@ def main():
11441173
mcp_configure_parser.add_argument("--args", nargs="*", help="Arguments for the MCP server command (only with --command)")
11451174
mcp_configure_parser.add_argument("--env-var", action="append", help="Environment variables (format: KEY=VALUE)")
11461175
mcp_configure_parser.add_argument("--headers", action="append", help="HTTP headers for remote servers (format: KEY=VALUE, only with --url)")
1176+
1177+
# Host-specific arguments
1178+
mcp_configure_parser.add_argument("--timeout", type=int, help="Request timeout in milliseconds (Gemini only)")
1179+
mcp_configure_parser.add_argument("--trust", action="store_true", help="Bypass tool call confirmations (Gemini only)")
1180+
mcp_configure_parser.add_argument("--cwd", help="Working directory for stdio transport (Gemini only)")
1181+
mcp_configure_parser.add_argument("--env-file", help="Path to environment file (Cursor, VS Code only)")
1182+
11471183
mcp_configure_parser.add_argument("--no-backup", action="store_true", help="Skip backup creation before configuration")
11481184
mcp_configure_parser.add_argument("--dry-run", action="store_true", help="Preview configuration without execution")
11491185
mcp_configure_parser.add_argument("--auto-approve", action="store_true", help="Skip confirmation prompts")
@@ -1938,8 +1974,10 @@ def main():
19381974
elif args.mcp_command == "configure":
19391975
return handle_mcp_configure(
19401976
args.host, args.server_name, args.server_command, args.args,
1941-
getattr(args, 'env_var', None), args.url, args.headers, args.no_backup,
1942-
args.dry_run, args.auto_approve
1977+
getattr(args, 'env_var', None), args.url, args.headers,
1978+
getattr(args, 'timeout', None), getattr(args, 'trust', False),
1979+
getattr(args, 'cwd', None), getattr(args, 'env_file', None),
1980+
args.no_backup, args.dry_run, args.auto_approve
19431981
)
19441982

19451983
elif args.mcp_command == "remove":

tests/test_mcp_cli_direct_management.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,17 @@ def test_configure_argument_parsing_basic(self):
4040
try:
4141
result = main()
4242
# If main() returns without SystemExit, check the handler was called
43+
# Updated to include new host-specific parameters: timeout, trust, cwd, env_file
4344
mock_handler.assert_called_once_with(
4445
'claude-desktop', 'weather-server', 'python', ['weather.py'],
45-
None, None, None, False, False, False
46+
None, None, None, None, False, None, None, False, False, False
4647
)
4748
except SystemExit as e:
4849
# If SystemExit is raised, it should be 0 (success) and handler should have been called
4950
if e.code == 0:
5051
mock_handler.assert_called_once_with(
5152
'claude-desktop', 'weather-server', 'python', ['weather.py'],
52-
None, None, None, False, False, False
53+
None, None, None, None, False, None, None, False, False, False
5354
)
5455
else:
5556
self.fail(f"main() exited with code {e.code}, expected 0")
@@ -69,10 +70,11 @@ def test_configure_argument_parsing_with_options(self):
6970
with patch('hatch.cli_hatch.handle_mcp_configure', return_value=0) as mock_handler:
7071
try:
7172
main()
73+
# Updated to include new host-specific parameters: timeout, trust, cwd, env_file
7274
mock_handler.assert_called_once_with(
7375
'cursor', 'file-server', None, None,
7476
['API_KEY=secret', 'DEBUG=true'], 'http://localhost:8080',
75-
['Authorization=Bearer token'], True, True, True
77+
['Authorization=Bearer token'], None, False, None, None, True, True, True
7678
)
7779
except SystemExit as e:
7880
self.assertEqual(e.code, 0)

0 commit comments

Comments
 (0)