@@ -1453,38 +1453,111 @@ def main():
14531453 hosts = parse_host_list (args .host )
14541454 env_name = args .env or env_manager .get_current_environment ()
14551455
1456- # Is it a path or a name?
1456+ package_name = args .package_path_or_name
1457+ package_service = None
1458+
1459+ # Check if it's a local package path
14571460 pkg_path = Path (args .package_path_or_name )
14581461 if pkg_path .exists () and pkg_path .is_dir ():
1462+ # Local package - load metadata from directory
14591463 with open (pkg_path / "hatch_metadata.json" , 'r' ) as f :
14601464 metadata = json .load (f )
1461- package_name = metadata ['name' ]
1465+ package_service = PackageService (metadata )
1466+ package_name = package_service .get_field ('name' )
14621467 else :
1463- package_name = args .package_path_or_name
1464-
1465- # Get MCP server configuration for the newly added package
1466- server_config = get_package_mcp_server_config (env_manager , env_name , package_name )
1468+ # Registry package - get metadata from environment manager
1469+ try :
1470+ env_data = env_manager .get_environment_data (env_name )
1471+ if env_data :
1472+ # Find the package in the environment
1473+ for pkg in env_data .packages :
1474+ if pkg .name == package_name :
1475+ # Create a minimal metadata structure for PackageService
1476+ metadata = {
1477+ "name" : pkg .name ,
1478+ "version" : pkg .version ,
1479+ "dependencies" : {} # Will be populated if needed
1480+ }
1481+ package_service = PackageService (metadata )
1482+ break
1483+
1484+ if package_service is None :
1485+ print (f"Warning: Could not find package '{ package_name } ' in environment '{ env_name } '. Skipping dependency analysis." )
1486+ package_service = None
1487+ except Exception as e :
1488+ print (f"Warning: Could not load package metadata for '{ package_name } ': { e } . Skipping dependency analysis." )
1489+ package_service = None
1490+
1491+ # Get dependency names if we have package service
1492+ package_names = []
1493+ if package_service :
1494+ # Get Hatch dependencies
1495+ dependencies = package_service .get_dependencies ()
1496+ hatch_deps = dependencies .get ('hatch' , [])
1497+ package_names = [dep .get ('name' ) for dep in hatch_deps if dep .get ('name' )]
1498+
1499+ # Resolve local dependency paths to actual names
1500+ for i in range (len (package_names )):
1501+ dep_path = Path (package_names [i ])
1502+ if dep_path .exists () and dep_path .is_dir ():
1503+ try :
1504+ with open (dep_path / "hatch_metadata.json" , 'r' ) as f :
1505+ dep_metadata = json .load (f )
1506+ dep_service = PackageService (dep_metadata )
1507+ package_names [i ] = dep_service .get_field ('name' )
1508+ except Exception as e :
1509+ print (f"Warning: Could not resolve dependency path '{ package_names [i ]} ': { e } " )
1510+
1511+ # Add the main package to the list
1512+ package_names .append (package_name )
1513+
1514+ # Get MCP server configuration for all packages
1515+ server_configs = [get_package_mcp_server_config (env_manager , env_name , pkg_name ) for pkg_name in package_names ]
14671516
14681517 print (f"Configuring MCP server for package '{ package_name } ' on { len (hosts )} host(s)..." )
14691518
14701519 # Configure on each host
14711520 success_count = 0
14721521 for host in hosts : # 'host', here, is a string
1473- try :
1474- result = mcp_manager .configure_server (
1475- hostname = host ,
1476- server_config = server_config ,
1477- no_backup = False # Always backup when adding packages
1478- )
1479-
1480- if result .success :
1481- print (f"✓ Configured { server_config .name } on { host } " )
1482- success_count += 1
1483- else :
1484- print (f"✗ Failed to configure { server_config .name } on { host } : { result .error_message } " )
1485-
1486- except Exception as e :
1487- print (f"✗ Error configuring { server_config .name } on { host } : { e } " )
1522+ host_success_count = 0
1523+ for i , server_config in enumerate (server_configs ):
1524+ pkg_name = package_names [i ]
1525+ try :
1526+ result = mcp_manager .configure_server (
1527+ hostname = host ,
1528+ server_config = server_config ,
1529+ no_backup = False # Always backup when adding packages
1530+ )
1531+
1532+ if result .success :
1533+ print (f"✓ Configured { server_config .name } ({ pkg_name } ) on { host } " )
1534+ host_success_count += 1
1535+
1536+ # Update package metadata with host configuration tracking
1537+ try :
1538+ server_config_dict = {
1539+ "name" : server_config .name ,
1540+ "command" : server_config .command ,
1541+ "args" : server_config .args
1542+ }
1543+
1544+ env_manager .update_package_host_configuration (
1545+ env_name = env_name ,
1546+ package_name = pkg_name ,
1547+ hostname = host ,
1548+ server_config = server_config_dict
1549+ )
1550+ except Exception as e :
1551+ # Log but don't fail the configuration operation
1552+ print (f"[WARNING] Failed to update package metadata for { pkg_name } : { e } " )
1553+ else :
1554+ print (f"✗ Failed to configure { server_config .name } ({ pkg_name } ) on { host } : { result .error_message } " )
1555+
1556+ except Exception as e :
1557+ print (f"✗ Error configuring { server_config .name } ({ pkg_name } ) on { host } : { e } " )
1558+
1559+ if host_success_count == len (server_configs ):
1560+ success_count += 1
14881561
14891562 if success_count > 0 :
14901563 print (f"MCP configuration completed: { success_count } /{ len (hosts )} hosts configured" )
@@ -1526,68 +1599,122 @@ def main():
15261599 hosts = parse_host_list (args .host )
15271600 env_name = args .env or env_manager .get_current_environment ()
15281601
1529- # Get MCP server configuration for the package
1530- server_config = get_package_mcp_server_config (env_manager , env_name , args .package_name )
1602+ # Get all packages to sync (main package + dependencies)
1603+ package_names = [args .package_name ]
1604+
1605+ # Try to get dependencies for the main package
1606+ try :
1607+ env_data = env_manager .get_environment_data (env_name )
1608+ if env_data :
1609+ # Find the main package in the environment
1610+ main_package = None
1611+ for pkg in env_data .packages :
1612+ if pkg .name == args .package_name :
1613+ main_package = pkg
1614+ break
1615+
1616+ if main_package :
1617+ # Create a minimal metadata structure for PackageService
1618+ metadata = {
1619+ "name" : main_package .name ,
1620+ "version" : main_package .version ,
1621+ "dependencies" : {} # Will be populated if needed
1622+ }
1623+ package_service = PackageService (metadata )
1624+
1625+ # Get Hatch dependencies
1626+ dependencies = package_service .get_dependencies ()
1627+ hatch_deps = dependencies .get ('hatch' , [])
1628+ dep_names = [dep .get ('name' ) for dep in hatch_deps if dep .get ('name' )]
1629+
1630+ # Add dependencies to the sync list (before main package)
1631+ package_names = dep_names + [args .package_name ]
1632+ else :
1633+ print (f"Warning: Package '{ args .package_name } ' not found in environment '{ env_name } '. Syncing only the specified package." )
1634+ else :
1635+ print (f"Warning: Could not access environment '{ env_name } '. Syncing only the specified package." )
1636+ except Exception as e :
1637+ print (f"Warning: Could not analyze dependencies for '{ args .package_name } ': { e } . Syncing only the specified package." )
1638+
1639+ # Get MCP server configurations for all packages
1640+ server_configs = []
1641+ for pkg_name in package_names :
1642+ try :
1643+ config = get_package_mcp_server_config (env_manager , env_name , pkg_name )
1644+ server_configs .append ((pkg_name , config ))
1645+ except Exception as e :
1646+ print (f"Warning: Could not get MCP configuration for package '{ pkg_name } ': { e } " )
1647+
1648+ if not server_configs :
1649+ print (f"Error: No MCP server configurations found for package '{ args .package_name } ' or its dependencies" )
1650+ return 1
15311651
15321652 if args .dry_run :
1533- print (f"[DRY RUN] Would synchronize MCP server for package '{ args .package_name } ' to hosts: { [h for h in hosts ]} " )
1534- print (f"[DRY RUN] Server config: { server_config .name } -> { ' ' .join (server_config .args )} " )
1653+ print (f"[DRY RUN] Would synchronize MCP servers for { len (server_configs )} package(s) to hosts: { [h for h in hosts ]} " )
1654+ for pkg_name , config in server_configs :
1655+ print (f"[DRY RUN] - { pkg_name } : { config .name } -> { ' ' .join (config .args )} " )
15351656 return 0
15361657
15371658 # Confirm operation unless auto-approved
1659+ package_desc = f"package '{ args .package_name } '" if len (server_configs ) == 1 else f"{ len (server_configs )} packages ('{ args .package_name } ' + dependencies)"
15381660 if not request_confirmation (
1539- f"Synchronize MCP server for package ' { args . package_name } ' to { len (hosts )} host(s)?" ,
1661+ f"Synchronize MCP servers for { package_desc } to { len (hosts )} host(s)?" ,
15401662 args .auto_approve
15411663 ):
15421664 print ("Operation cancelled." )
15431665 return 0
15441666
1545- # Perform synchronization to each host
1667+ # Perform synchronization to each host for all packages
1668+ total_operations = len (server_configs ) * len (hosts )
15461669 success_count = 0
1547- for host in hosts : # 'host', here, is a string
1548- try :
1549- result = mcp_manager .configure_server (
1550- hostname = host ,
1551- server_config = server_config ,
1552- no_backup = args .no_backup
1553- )
1554-
1555- if result .success :
1556- print (f"[SUCCESS] Successfully configured { server_config .name } on { host } " )
1557- success_count += 1
15581670
1559- # Update package metadata with host configuration tracking
1560- try :
1561- server_config_dict = {
1562- "name" : server_config .name ,
1563- "command" : server_config .command ,
1564- "args" : server_config .args
1565- }
1566-
1567- env_manager .update_package_host_configuration (
1568- env_name = env_name ,
1569- package_name = args .package_name ,
1570- hostname = host ,
1571- server_config = server_config_dict
1572- )
1573- except Exception as e :
1574- # Log but don't fail the sync operation
1575- print (f"[WARNING] Failed to update package metadata: { e } " )
1576- else :
1577- print (f"[ERROR] Failed to configure { server_config .name } on { host } : { result .error_message } " )
1578-
1579- except Exception as e :
1580- print (f"[ERROR] Error configuring { server_config .name } on { host } : { e } " )
1671+ for host in hosts :
1672+ for pkg_name , server_config in server_configs :
1673+ try :
1674+ result = mcp_manager .configure_server (
1675+ hostname = host ,
1676+ server_config = server_config ,
1677+ no_backup = args .no_backup
1678+ )
1679+
1680+ if result .success :
1681+ print (f"[SUCCESS] Successfully configured { server_config .name } ({ pkg_name } ) on { host } " )
1682+ success_count += 1
1683+
1684+ # Update package metadata with host configuration tracking
1685+ try :
1686+ server_config_dict = {
1687+ "name" : server_config .name ,
1688+ "command" : server_config .command ,
1689+ "args" : server_config .args
1690+ }
1691+
1692+ env_manager .update_package_host_configuration (
1693+ env_name = env_name ,
1694+ package_name = pkg_name ,
1695+ hostname = host ,
1696+ server_config = server_config_dict
1697+ )
1698+ except Exception as e :
1699+ # Log but don't fail the sync operation
1700+ print (f"[WARNING] Failed to update package metadata for { pkg_name } : { e } " )
1701+ else :
1702+ print (f"[ERROR] Failed to configure { server_config .name } ({ pkg_name } ) on { host } : { result .error_message } " )
1703+
1704+ except Exception as e :
1705+ print (f"[ERROR] Error configuring { server_config .name } ({ pkg_name } ) on { host } : { e } " )
15811706
15821707 # Report results
1583- if success_count == len (hosts ):
1584- print (f"Successfully synchronized package '{ args .package_name } ' to all { len (hosts )} host(s)" )
1708+ if success_count == total_operations :
1709+ package_desc = f"package '{ args .package_name } '" if len (server_configs ) == 1 else f"{ len (server_configs )} packages"
1710+ print (f"Successfully synchronized { package_desc } to all { len (hosts )} host(s)" )
15851711 return 0
15861712 elif success_count > 0 :
1587- print (f"Partially synchronized package ' { args . package_name } ' : { success_count } /{ len ( hosts ) } hosts succeeded" )
1713+ print (f"Partially synchronized: { success_count } /{ total_operations } operations succeeded" )
15881714 return 1
15891715 else :
1590- print (f"Failed to synchronize package '{ args .package_name } ' to any hosts" )
1716+ package_desc = f"package '{ args .package_name } '" if len (server_configs ) == 1 else f"{ len (server_configs )} packages"
1717+ print (f"Failed to synchronize { package_desc } to any hosts" )
15911718 return 1
15921719
15931720 except ValueError as e :
0 commit comments