Skip to content

Commit f69be90

Browse files
refactor(cli): extract handle_mcp_sync to cli_mcp
1 parent 16f8520 commit f69be90

File tree

2 files changed

+124
-79
lines changed

2 files changed

+124
-79
lines changed

hatch/cli/cli_mcp.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,3 +1107,112 @@ def handle_mcp_remove_host(
11071107
except Exception as e:
11081108
print(f"Error removing host configuration: {e}")
11091109
return EXIT_ERROR
1110+
1111+
1112+
def handle_mcp_sync(
1113+
from_env: Optional[str] = None,
1114+
from_host: Optional[str] = None,
1115+
to_hosts: Optional[str] = None,
1116+
servers: Optional[str] = None,
1117+
pattern: Optional[str] = None,
1118+
dry_run: bool = False,
1119+
auto_approve: bool = False,
1120+
no_backup: bool = False,
1121+
) -> int:
1122+
"""Handle 'hatch mcp sync' command.
1123+
1124+
Synchronizes MCP server configurations from a source to target hosts.
1125+
1126+
Args:
1127+
from_env: Source environment name
1128+
from_host: Source host name
1129+
to_hosts: Comma-separated list of target hosts
1130+
servers: Comma-separated list of server names to sync
1131+
pattern: Pattern to filter servers
1132+
dry_run: If True, show what would be done without making changes
1133+
auto_approve: If True, skip confirmation prompt
1134+
no_backup: If True, skip creating backups
1135+
1136+
Returns:
1137+
int: EXIT_SUCCESS (0) on success, EXIT_ERROR (1) on failure
1138+
"""
1139+
from hatch.cli.cli_utils import request_confirmation, parse_host_list
1140+
1141+
try:
1142+
# Parse target hosts
1143+
if not to_hosts:
1144+
print("Error: Must specify --to-host")
1145+
return EXIT_ERROR
1146+
1147+
target_hosts = parse_host_list(to_hosts)
1148+
1149+
# Parse server filters
1150+
server_list = None
1151+
if servers:
1152+
server_list = [s.strip() for s in servers.split(",") if s.strip()]
1153+
1154+
if dry_run:
1155+
source_desc = (
1156+
f"environment '{from_env}'" if from_env else f"host '{from_host}'"
1157+
)
1158+
target_desc = f"hosts: {', '.join(target_hosts)}"
1159+
print(f"[DRY RUN] Would synchronize from {source_desc} to {target_desc}")
1160+
1161+
if server_list:
1162+
print(f"[DRY RUN] Server filter: {', '.join(server_list)}")
1163+
elif pattern:
1164+
print(f"[DRY RUN] Pattern filter: {pattern}")
1165+
1166+
print(f"[DRY RUN] Backup: {'Disabled' if no_backup else 'Enabled'}")
1167+
return EXIT_SUCCESS
1168+
1169+
# Confirm operation unless auto-approved
1170+
source_desc = f"environment '{from_env}'" if from_env else f"host '{from_host}'"
1171+
target_desc = f"{len(target_hosts)} host(s)"
1172+
if not request_confirmation(
1173+
f"Synchronize MCP configurations from {source_desc} to {target_desc}?",
1174+
auto_approve,
1175+
):
1176+
print("Operation cancelled.")
1177+
return EXIT_SUCCESS
1178+
1179+
# Perform synchronization
1180+
mcp_manager = MCPHostConfigurationManager()
1181+
result = mcp_manager.sync_configurations(
1182+
from_env=from_env,
1183+
from_host=from_host,
1184+
to_hosts=target_hosts,
1185+
servers=server_list,
1186+
pattern=pattern,
1187+
no_backup=no_backup,
1188+
)
1189+
1190+
if result.success:
1191+
print(f"[SUCCESS] Synchronization completed")
1192+
print(f" Servers synced: {result.servers_synced}")
1193+
print(f" Hosts updated: {result.hosts_updated}")
1194+
1195+
# Show detailed results
1196+
for res in result.results:
1197+
if res.success:
1198+
backup_info = (
1199+
f" (backup: {res.backup_path})" if res.backup_path else ""
1200+
)
1201+
print(f" ✓ {res.hostname}{backup_info}")
1202+
else:
1203+
print(f" ✗ {res.hostname}: {res.error_message}")
1204+
1205+
return EXIT_SUCCESS
1206+
else:
1207+
print(f"[ERROR] Synchronization failed")
1208+
for res in result.results:
1209+
if not res.success:
1210+
print(f" ✗ {res.hostname}: {res.error_message}")
1211+
return EXIT_ERROR
1212+
1213+
except ValueError as e:
1214+
print(f"Error: {e}")
1215+
return EXIT_ERROR
1216+
except Exception as e:
1217+
print(f"Error during synchronization: {e}")
1218+
return EXIT_ERROR

hatch/cli_hatch.py

Lines changed: 15 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -310,85 +310,21 @@ def handle_mcp_sync(
310310
auto_approve: bool = False,
311311
no_backup: bool = False,
312312
) -> int:
313-
"""Handle 'hatch mcp sync' command."""
314-
try:
315-
# Parse target hosts
316-
if not to_hosts:
317-
print("Error: Must specify --to-host")
318-
return 1
319-
320-
target_hosts = parse_host_list(to_hosts)
321-
322-
# Parse server filters
323-
server_list = None
324-
if servers:
325-
server_list = [s.strip() for s in servers.split(",") if s.strip()]
326-
327-
if dry_run:
328-
source_desc = (
329-
f"environment '{from_env}'" if from_env else f"host '{from_host}'"
330-
)
331-
target_desc = f"hosts: {', '.join(target_hosts)}"
332-
print(f"[DRY RUN] Would synchronize from {source_desc} to {target_desc}")
333-
334-
if server_list:
335-
print(f"[DRY RUN] Server filter: {', '.join(server_list)}")
336-
elif pattern:
337-
print(f"[DRY RUN] Pattern filter: {pattern}")
338-
339-
print(f"[DRY RUN] Backup: {'Disabled' if no_backup else 'Enabled'}")
340-
return 0
341-
342-
# Confirm operation unless auto-approved
343-
source_desc = f"environment '{from_env}'" if from_env else f"host '{from_host}'"
344-
target_desc = f"{len(target_hosts)} host(s)"
345-
if not request_confirmation(
346-
f"Synchronize MCP configurations from {source_desc} to {target_desc}?",
347-
auto_approve,
348-
):
349-
print("Operation cancelled.")
350-
return 0
351-
352-
# Perform synchronization
353-
mcp_manager = MCPHostConfigurationManager()
354-
result = mcp_manager.sync_configurations(
355-
from_env=from_env,
356-
from_host=from_host,
357-
to_hosts=target_hosts,
358-
servers=server_list,
359-
pattern=pattern,
360-
no_backup=no_backup,
361-
)
362-
363-
if result.success:
364-
print(f"[SUCCESS] Synchronization completed")
365-
print(f" Servers synced: {result.servers_synced}")
366-
print(f" Hosts updated: {result.hosts_updated}")
367-
368-
# Show detailed results
369-
for res in result.results:
370-
if res.success:
371-
backup_info = (
372-
f" (backup: {res.backup_path})" if res.backup_path else ""
373-
)
374-
print(f" ✓ {res.hostname}{backup_info}")
375-
else:
376-
print(f" ✗ {res.hostname}: {res.error_message}")
377-
378-
return 0
379-
else:
380-
print(f"[ERROR] Synchronization failed")
381-
for res in result.results:
382-
if not res.success:
383-
print(f" ✗ {res.hostname}: {res.error_message}")
384-
return 1
385-
386-
except ValueError as e:
387-
print(f"Error: {e}")
388-
return 1
389-
except Exception as e:
390-
print(f"Error during synchronization: {e}")
391-
return 1
313+
"""Handle 'hatch mcp sync' command.
314+
315+
Backward compatibility wrapper - delegates to cli_mcp module.
316+
"""
317+
from hatch.cli.cli_mcp import handle_mcp_sync as _handle_mcp_sync
318+
return _handle_mcp_sync(
319+
from_env=from_env,
320+
from_host=from_host,
321+
to_hosts=to_hosts,
322+
servers=servers,
323+
pattern=pattern,
324+
dry_run=dry_run,
325+
auto_approve=auto_approve,
326+
no_backup=no_backup,
327+
)
392328

393329

394330
def main():

0 commit comments

Comments
 (0)