claude-mpm 4.14.8__py3-none-any.whl → 4.15.0__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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (47) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/agent_loader.py +13 -1
  3. claude_mpm/agents/templates/project_organizer.json +3 -3
  4. claude_mpm/cli/commands/auto_configure.py +7 -9
  5. claude_mpm/cli/commands/local_deploy.py +3 -2
  6. claude_mpm/cli/commands/mpm_init.py +4 -4
  7. claude_mpm/cli/commands/mpm_init_handler.py +8 -3
  8. claude_mpm/core/base_service.py +13 -12
  9. claude_mpm/core/enums.py +124 -12
  10. claude_mpm/services/agents/auto_config_manager.py +9 -10
  11. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
  12. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
  13. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
  14. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
  15. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
  16. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +6 -4
  17. claude_mpm/services/agents/registry/modification_tracker.py +5 -2
  18. claude_mpm/services/command_handler_service.py +11 -5
  19. claude_mpm/services/core/interfaces/process.py +6 -6
  20. claude_mpm/services/core/models/__init__.py +0 -2
  21. claude_mpm/services/core/models/agent_config.py +12 -28
  22. claude_mpm/services/core/models/process.py +19 -42
  23. claude_mpm/services/local_ops/__init__.py +3 -3
  24. claude_mpm/services/local_ops/process_manager.py +12 -12
  25. claude_mpm/services/local_ops/state_manager.py +6 -5
  26. claude_mpm/services/local_ops/unified_manager.py +2 -2
  27. claude_mpm/services/mcp_config_manager.py +7 -2
  28. claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
  29. claude_mpm/services/mcp_gateway/core/base.py +18 -31
  30. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +71 -24
  31. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +23 -22
  32. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +2 -2
  33. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +1 -1
  34. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +3 -3
  35. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +3 -3
  36. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +1 -1
  37. claude_mpm/services/unified/deployment_strategies/local.py +3 -3
  38. claude_mpm/services/unified/deployment_strategies/utils.py +5 -5
  39. claude_mpm/services/unified/deployment_strategies/vercel.py +6 -6
  40. claude_mpm/services/unified/unified_analyzer.py +8 -5
  41. claude_mpm/services/unified/unified_deployment.py +2 -2
  42. {claude_mpm-4.14.8.dist-info → claude_mpm-4.15.0.dist-info}/METADATA +1 -1
  43. {claude_mpm-4.14.8.dist-info → claude_mpm-4.15.0.dist-info}/RECORD +47 -47
  44. {claude_mpm-4.14.8.dist-info → claude_mpm-4.15.0.dist-info}/WHEEL +0 -0
  45. {claude_mpm-4.14.8.dist-info → claude_mpm-4.15.0.dist-info}/entry_points.txt +0 -0
  46. {claude_mpm-4.14.8.dist-info → claude_mpm-4.15.0.dist-info}/licenses/LICENSE +0 -0
  47. {claude_mpm-4.14.8.dist-info → claude_mpm-4.15.0.dist-info}/top_level.txt +0 -0
@@ -30,9 +30,10 @@ from typing import Dict, List, Optional
30
30
  import psutil
31
31
  from filelock import FileLock
32
32
 
33
+ from claude_mpm.core.enums import ServiceState
33
34
  from claude_mpm.services.core.base import SyncBaseService
34
35
  from claude_mpm.services.core.interfaces.process import IDeploymentStateManager
35
- from claude_mpm.services.core.models.process import DeploymentState, ProcessStatus
36
+ from claude_mpm.services.core.models.process import DeploymentState
36
37
 
37
38
 
38
39
  class StateCorruptionError(Exception):
@@ -206,12 +207,12 @@ class DeploymentStateManager(SyncBaseService, IDeploymentStateManager):
206
207
  states = self.load_state()
207
208
  return list(states.values())
208
209
 
209
- def get_deployments_by_status(self, status: ProcessStatus) -> List[DeploymentState]:
210
+ def get_deployments_by_status(self, status: ServiceState) -> List[DeploymentState]:
210
211
  """
211
212
  Get all deployments with a specific status.
212
213
 
213
214
  Args:
214
- status: ProcessStatus to filter by
215
+ status: ServiceState to filter by
215
216
 
216
217
  Returns:
217
218
  List of matching DeploymentState objects
@@ -295,14 +296,14 @@ class DeploymentStateManager(SyncBaseService, IDeploymentStateManager):
295
296
  return False
296
297
 
297
298
  def update_deployment_status(
298
- self, deployment_id: str, status: ProcessStatus
299
+ self, deployment_id: str, status: ServiceState
299
300
  ) -> bool:
300
301
  """
301
302
  Update the status of a deployment.
302
303
 
303
304
  Args:
304
305
  deployment_id: Unique deployment identifier
305
- status: New ProcessStatus
306
+ status: New ServiceState
306
307
 
307
308
  Returns:
308
309
  True if updated, False if deployment not found
@@ -45,12 +45,12 @@ from typing import Any, Dict, List, Optional
45
45
 
46
46
  import yaml
47
47
 
48
+ from claude_mpm.core.enums import ServiceState
48
49
  from claude_mpm.services.core.base import SyncBaseService
49
50
  from claude_mpm.services.core.models.health import DeploymentHealth
50
51
  from claude_mpm.services.core.models.process import (
51
52
  DeploymentState,
52
53
  ProcessInfo,
53
- ProcessStatus,
54
54
  StartConfig,
55
55
  )
56
56
  from claude_mpm.services.core.models.restart import RestartConfig, RestartHistory
@@ -384,7 +384,7 @@ class UnifiedLocalOpsManager(SyncBaseService):
384
384
 
385
385
  def list_deployments(
386
386
  self,
387
- status_filter: Optional[ProcessStatus] = None,
387
+ status_filter: Optional[ServiceState] = None,
388
388
  ) -> List[DeploymentState]:
389
389
  """
390
390
  List all deployments.
@@ -1145,11 +1145,16 @@ class MCPConfigManager:
1145
1145
 
1146
1146
  # Check each service for issues
1147
1147
  for service_name in self.PIPX_SERVICES:
1148
- self.logger.info(f"🔍 Checking {service_name} for issues...")
1148
+ # Check if service is enabled in config
1149
+ if not self.should_enable_service(service_name):
1150
+ self.logger.debug(f"Skipping {service_name} (disabled in config)")
1151
+ continue
1152
+
1153
+ self.logger.debug(f"🔍 Checking {service_name} for issues...")
1149
1154
  issue_type = self._detect_service_issue(service_name)
1150
1155
  if issue_type:
1151
1156
  services_to_fix.append((service_name, issue_type))
1152
- self.logger.info(f" ⚠️ Found issue with {service_name}: {issue_type}")
1157
+ self.logger.debug(f" ⚠️ Found issue with {service_name}: {issue_type}")
1153
1158
  else:
1154
1159
  self.logger.debug(f" ✅ {service_name} is functioning correctly")
1155
1160
 
@@ -5,7 +5,7 @@ MCP Gateway Core Module
5
5
  Core interfaces and base classes for the MCP Gateway service.
6
6
  """
7
7
 
8
- from .base import BaseMCPService, MCPServiceState
8
+ from .base import BaseMCPService
9
9
  from .exceptions import (
10
10
  MCPCommunicationError,
11
11
  MCPConfigurationError,
@@ -38,7 +38,6 @@ __all__ = [
38
38
  # Exceptions
39
39
  "MCPException",
40
40
  "MCPServerError",
41
- "MCPServiceState",
42
41
  "MCPToolNotFoundError",
43
42
  "MCPValidationError",
44
43
  ]
@@ -8,25 +8,12 @@ Part of ISS-0034: Infrastructure Setup - MCP Gateway Project Foundation
8
8
  """
9
9
 
10
10
  import asyncio
11
- from enum import Enum
12
11
  from typing import Any, Dict, Optional
13
12
 
13
+ from claude_mpm.core.enums import ServiceState
14
14
  from claude_mpm.services.core.base import BaseService
15
15
 
16
16
 
17
- class MCPServiceState(Enum):
18
- """MCP service lifecycle states."""
19
-
20
- UNINITIALIZED = "uninitialized"
21
- INITIALIZING = "initializing"
22
- INITIALIZED = "initialized"
23
- STARTING = "starting"
24
- RUNNING = "running"
25
- STOPPING = "stopping"
26
- STOPPED = "stopped"
27
- ERROR = "error"
28
-
29
-
30
17
  class BaseMCPService(BaseService):
31
18
  """
32
19
  Base class for all MCP Gateway services.
@@ -53,7 +40,7 @@ class BaseMCPService(BaseService):
53
40
  config: Service-specific configuration
54
41
  """
55
42
  super().__init__(service_name or "MCPService", config)
56
- self._state = MCPServiceState.UNINITIALIZED
43
+ self._state = ServiceState.UNINITIALIZED
57
44
  self._health_status = {
58
45
  "healthy": False,
59
46
  "state": self._state.value,
@@ -76,13 +63,13 @@ class BaseMCPService(BaseService):
76
63
  """
77
64
  async with self._state_lock:
78
65
  if self._state not in [
79
- MCPServiceState.UNINITIALIZED,
80
- MCPServiceState.STOPPED,
66
+ ServiceState.UNINITIALIZED,
67
+ ServiceState.STOPPED,
81
68
  ]:
82
69
  self.log_warning(f"Cannot initialize from state {self._state.value}")
83
70
  return False
84
71
 
85
- self._state = MCPServiceState.INITIALIZING
72
+ self._state = ServiceState.INITIALIZING
86
73
  self.log_info("Initializing MCP service")
87
74
 
88
75
  try:
@@ -91,13 +78,13 @@ class BaseMCPService(BaseService):
91
78
 
92
79
  async with self._state_lock:
93
80
  if success:
94
- self._state = MCPServiceState.INITIALIZED
81
+ self._state = ServiceState.INITIALIZED
95
82
  self._initialized = True
96
83
  self._health_status["healthy"] = True
97
84
  self._health_status["state"] = self._state.value
98
85
  self.log_info("MCP service initialized successfully")
99
86
  else:
100
- self._state = MCPServiceState.ERROR
87
+ self._state = ServiceState.ERROR
101
88
  self._health_status["healthy"] = False
102
89
  self._health_status["state"] = self._state.value
103
90
  self.log_error("MCP service initialization failed")
@@ -106,7 +93,7 @@ class BaseMCPService(BaseService):
106
93
 
107
94
  except Exception as e:
108
95
  async with self._state_lock:
109
- self._state = MCPServiceState.ERROR
96
+ self._state = ServiceState.ERROR
110
97
  self._health_status["healthy"] = False
111
98
  self._health_status["state"] = self._state.value
112
99
  self._health_status["details"]["error"] = str(e)
@@ -134,11 +121,11 @@ class BaseMCPService(BaseService):
134
121
  True if startup successful
135
122
  """
136
123
  async with self._state_lock:
137
- if self._state != MCPServiceState.INITIALIZED:
124
+ if self._state != ServiceState.INITIALIZED:
138
125
  self.log_warning(f"Cannot start from state {self._state.value}")
139
126
  return False
140
127
 
141
- self._state = MCPServiceState.STARTING
128
+ self._state = ServiceState.STARTING
142
129
  self.log_info("Starting MCP service")
143
130
 
144
131
  try:
@@ -146,12 +133,12 @@ class BaseMCPService(BaseService):
146
133
 
147
134
  async with self._state_lock:
148
135
  if success:
149
- self._state = MCPServiceState.RUNNING
136
+ self._state = ServiceState.RUNNING
150
137
  self._health_status["healthy"] = True
151
138
  self._health_status["state"] = self._state.value
152
139
  self.log_info("MCP service started successfully")
153
140
  else:
154
- self._state = MCPServiceState.ERROR
141
+ self._state = ServiceState.ERROR
155
142
  self._health_status["healthy"] = False
156
143
  self._health_status["state"] = self._state.value
157
144
  self.log_error("MCP service startup failed")
@@ -160,7 +147,7 @@ class BaseMCPService(BaseService):
160
147
 
161
148
  except Exception as e:
162
149
  async with self._state_lock:
163
- self._state = MCPServiceState.ERROR
150
+ self._state = ServiceState.ERROR
164
151
  self._health_status["healthy"] = False
165
152
  self._health_status["state"] = self._state.value
166
153
  self._health_status["details"]["error"] = str(e)
@@ -188,18 +175,18 @@ class BaseMCPService(BaseService):
188
175
  Subclasses should override _do_shutdown() for custom shutdown logic.
189
176
  """
190
177
  async with self._state_lock:
191
- if self._state in [MCPServiceState.STOPPED, MCPServiceState.STOPPING]:
178
+ if self._state in [ServiceState.STOPPED, ServiceState.STOPPING]:
192
179
  self.log_warning(f"Already in state {self._state.value}")
193
180
  return
194
181
 
195
- self._state = MCPServiceState.STOPPING
182
+ self._state = ServiceState.STOPPING
196
183
  self.log_info("Shutting down MCP service")
197
184
 
198
185
  try:
199
186
  await self._do_shutdown()
200
187
 
201
188
  async with self._state_lock:
202
- self._state = MCPServiceState.STOPPED
189
+ self._state = ServiceState.STOPPED
203
190
  self._shutdown = True
204
191
  self._health_status["healthy"] = False
205
192
  self._health_status["state"] = self._state.value
@@ -207,7 +194,7 @@ class BaseMCPService(BaseService):
207
194
 
208
195
  except Exception as e:
209
196
  async with self._state_lock:
210
- self._state = MCPServiceState.ERROR
197
+ self._state = ServiceState.ERROR
211
198
  self._health_status["healthy"] = False
212
199
  self._health_status["state"] = self._state.value
213
200
  self._health_status["details"]["error"] = str(e)
@@ -232,7 +219,7 @@ class BaseMCPService(BaseService):
232
219
  self.log_info("Restarting MCP service")
233
220
 
234
221
  # Shutdown if running
235
- if self._state == MCPServiceState.RUNNING:
222
+ if self._state == ServiceState.RUNNING:
236
223
  await self.shutdown()
237
224
 
238
225
  # Re-initialize
@@ -2,12 +2,22 @@
2
2
  External MCP Services Integration
3
3
  ==================================
4
4
 
5
- Manages installation and basic setup of external MCP services like mcp-vector-search
5
+ Manages detection and setup of external MCP services like mcp-vector-search
6
6
  and mcp-browser. These services run as separate MCP servers in Claude Code,
7
7
  not as part of the Claude MPM MCP Gateway.
8
8
 
9
- Note: As of the latest architecture, external services are registered as separate
10
- MCP servers in Claude Code configuration, not as tools within the gateway.
9
+ IMPORTANT: External services are NOT auto-installed. Users must manually install
10
+ them using pipx or pip. This gives users explicit control over which optional
11
+ services they want to enable.
12
+
13
+ Installation:
14
+ pipx install mcp-vector-search
15
+ pipx install mcp-browser
16
+ pipx install kuzu-memory
17
+ pipx install mcp-ticketer
18
+
19
+ Note: External services are registered as separate MCP servers in Claude Code
20
+ configuration, not as tools within the gateway.
11
21
  """
12
22
 
13
23
  import json
@@ -20,7 +30,12 @@ from claude_mpm.services.mcp_gateway.tools.base_adapter import BaseToolAdapter
20
30
 
21
31
 
22
32
  class ExternalMCPService(BaseToolAdapter):
23
- """Base class for external MCP service integration."""
33
+ """Base class for external MCP service integration.
34
+
35
+ External services are detected if already installed but are NOT
36
+ automatically installed. Users must install them manually using
37
+ pipx or pip to enable these optional features.
38
+ """
24
39
 
25
40
  def __init__(self, service_name: str, package_name: str):
26
41
  """
@@ -65,27 +80,37 @@ class ExternalMCPService(BaseToolAdapter):
65
80
  )
66
81
 
67
82
  async def initialize(
68
- self, auto_install: bool = True, interactive: bool = True
83
+ self, auto_install: bool = False, interactive: bool = False
69
84
  ) -> bool:
70
85
  """Initialize the external service.
71
86
 
87
+ NOTE: Auto-installation is disabled by default (v4.9.0+). Users must
88
+ manually install external services using pipx or pip.
89
+
72
90
  Args:
73
- auto_install: Whether to automatically install if not found
74
- interactive: Whether to prompt user for installation preferences
91
+ auto_install: Whether to automatically install if not found (default: False)
92
+ Deprecated - will be removed in future versions
93
+ interactive: Whether to prompt user for installation preferences (default: False)
94
+ Only used if auto_install=True
75
95
  """
76
96
  try:
77
97
  # Check if package is installed
78
98
  self._is_installed = await self._check_installation()
79
99
 
80
100
  if not self._is_installed and auto_install:
81
- self.logger.info(
82
- f"{self.package_name} not installed - attempting installation"
101
+ # This path is deprecated but kept for backward compatibility
102
+ self.logger.warning(
103
+ f"Auto-installation is deprecated. Please install {self.package_name} manually: "
104
+ f"pipx install {self.package_name}"
83
105
  )
84
106
  await self._install_package(interactive=interactive)
85
107
  self._is_installed = await self._check_installation()
86
108
 
87
109
  if not self._is_installed:
88
- self.logger.warning(f"{self.package_name} is not available")
110
+ self.logger.debug(
111
+ f"{self.package_name} is not available. "
112
+ f"Install manually with: pipx install {self.package_name}"
113
+ )
89
114
  return False
90
115
 
91
116
  self.logger.info(f"{self.package_name} is available")
@@ -522,13 +547,20 @@ class MCPBrowserService(ExternalMCPService):
522
547
  class ExternalMCPServiceManager:
523
548
  """Manager for external MCP services.
524
549
 
525
- This manager is responsible for checking and installing Python packages
526
- for external MCP services. The actual registration of these services
527
- happens in Claude Code configuration as separate MCP servers.
550
+ This manager is responsible for detecting (but NOT installing) Python packages
551
+ for external MCP services. The actual registration of these services happens
552
+ in Claude Code configuration as separate MCP servers.
553
+
554
+ IMPORTANT: As of v4.9.0, this manager NO LONGER auto-installs missing services.
555
+ Users must manually install external services using pipx or pip:
556
+ - pipx install mcp-vector-search
557
+ - pipx install mcp-browser
558
+ - pipx install kuzu-memory
559
+ - pipx install mcp-ticketer
528
560
 
529
- Note: This class is maintained for backward compatibility and package
530
- management. The actual tool registration is handled by separate MCP
531
- server instances in Claude Code.
561
+ Note: This class is maintained for backward compatibility and service detection.
562
+ The actual tool registration is handled by separate MCP server instances in
563
+ Claude Code.
532
564
  """
533
565
 
534
566
  def __init__(self):
@@ -539,20 +571,34 @@ class ExternalMCPServiceManager:
539
571
  async def initialize_services(self) -> List[ExternalMCPService]:
540
572
  """Initialize all external MCP services.
541
573
 
542
- This method checks if external service packages are installed
543
- and attempts to install them if missing. It does NOT register
544
- them as tools in the gateway - they run as separate MCP servers.
574
+ This method checks if external service packages are already installed
575
+ and registers them if available. It does NOT auto-install missing services.
576
+
577
+ External MCP services (mcp-vector-search, mcp-browser, kuzu-memory, mcp-ticketer)
578
+ must be manually installed by users. This gives users explicit control over
579
+ which services they want to use.
580
+
581
+ Installation instructions:
582
+ - mcp-vector-search: pipx install mcp-vector-search
583
+ - mcp-browser: pipx install mcp-browser
584
+ - kuzu-memory: pipx install kuzu-memory
585
+ - mcp-ticketer: pipx install mcp-ticketer
586
+
587
+ Services run as separate MCP servers in Claude Code, not as tools within
588
+ the gateway.
545
589
  """
546
590
  # Create service instances
547
- # Note: kuzu-memory is configured via MCPConfigManager and runs as a separate MCP server
548
- # It doesn't need to be included here since it's already set up through the MCP config
591
+ # Note: kuzu-memory and mcp-ticketer are configured via MCPConfigManager
592
+ # and run as separate MCP servers. They don't need to be included here
593
+ # since they're already set up through the MCP config.
549
594
  services = [MCPVectorSearchService(), MCPBrowserService()]
550
595
 
551
- # Initialize each service
596
+ # Initialize each service (check if installed, but DO NOT auto-install)
552
597
  initialized_services = []
553
598
  for service in services:
554
599
  try:
555
- if await service.initialize():
600
+ # Pass auto_install=False to prevent automatic installation
601
+ if await service.initialize(auto_install=False, interactive=False):
556
602
  initialized_services.append(service)
557
603
  if self.logger:
558
604
  self.logger.info(
@@ -560,7 +606,8 @@ class ExternalMCPServiceManager:
560
606
  )
561
607
  elif self.logger:
562
608
  self.logger.debug(
563
- f"Service not available (optional): {service.service_name}"
609
+ f"Service not available (optional): {service.service_name}. "
610
+ f"Install manually with: pipx install {service.package_name}"
564
611
  )
565
612
  except Exception as e:
566
613
  if self.logger:
@@ -26,7 +26,7 @@ from typing import Any, Dict
26
26
  import psutil
27
27
 
28
28
  from claude_mpm.config.paths import paths
29
- from claude_mpm.core.enums import OperationResult, ServiceState
29
+ from claude_mpm.core.enums import HealthStatus, OperationResult, ServiceState
30
30
  from claude_mpm.core.logger import get_logger
31
31
  from claude_mpm.services.mcp_gateway.core.interfaces import (
32
32
  MCPToolDefinition,
@@ -220,7 +220,7 @@ class HealthCheckTool(BaseToolAdapter):
220
220
 
221
221
  if memory_usage > 90:
222
222
  check_result["errors"].append("High memory usage detected")
223
- check_result["status"] = "unhealthy"
223
+ check_result["status"] = HealthStatus.UNHEALTHY
224
224
  elif memory_usage > 80:
225
225
  check_result["warnings"].append("Elevated memory usage")
226
226
 
@@ -233,7 +233,7 @@ class HealthCheckTool(BaseToolAdapter):
233
233
 
234
234
  if cpu_usage > 95:
235
235
  check_result["errors"].append("High CPU usage detected")
236
- check_result["status"] = "unhealthy"
236
+ check_result["status"] = HealthStatus.UNHEALTHY
237
237
  elif cpu_usage > 80:
238
238
  check_result["warnings"].append("Elevated CPU usage")
239
239
 
@@ -249,7 +249,7 @@ class HealthCheckTool(BaseToolAdapter):
249
249
 
250
250
  if disk_usage_percent > 95:
251
251
  check_result["errors"].append("Disk space critically low")
252
- check_result["status"] = "unhealthy"
252
+ check_result["status"] = HealthStatus.UNHEALTHY
253
253
  elif disk_usage_percent > 85:
254
254
  check_result["warnings"].append("Disk space running low")
255
255
 
@@ -263,7 +263,7 @@ class HealthCheckTool(BaseToolAdapter):
263
263
  }
264
264
 
265
265
  except Exception as e:
266
- check_result["status"] = "error"
266
+ check_result["status"] = HealthStatus.UNHEALTHY
267
267
  check_result["errors"].append(f"System health check failed: {e}")
268
268
 
269
269
  return check_result
@@ -303,10 +303,10 @@ class HealthCheckTool(BaseToolAdapter):
303
303
 
304
304
  if not mcp_dir.exists():
305
305
  check_result["errors"].append("MCP directory does not exist")
306
- check_result["status"] = "unhealthy"
306
+ check_result["status"] = HealthStatus.UNHEALTHY
307
307
 
308
308
  except Exception as e:
309
- check_result["status"] = "error"
309
+ check_result["status"] = HealthStatus.UNHEALTHY
310
310
  check_result["errors"].append(f"Gateway health check failed: {e}")
311
311
 
312
312
  return check_result
@@ -354,11 +354,11 @@ class HealthCheckTool(BaseToolAdapter):
354
354
  )
355
355
 
356
356
  if len(available_essential) == 0:
357
- check_result["status"] = "unhealthy"
357
+ check_result["status"] = HealthStatus.UNHEALTHY
358
358
  check_result["errors"].append("No essential tools available")
359
359
 
360
360
  except Exception as e:
361
- check_result["status"] = "error"
361
+ check_result["status"] = HealthStatus.UNHEALTHY
362
362
  check_result["errors"].append(f"Tools health check failed: {e}")
363
363
 
364
364
  return check_result
@@ -402,7 +402,7 @@ class HealthCheckTool(BaseToolAdapter):
402
402
  }
403
403
 
404
404
  except Exception as e:
405
- check_result["status"] = "error"
405
+ check_result["status"] = HealthStatus.UNHEALTHY
406
406
  check_result["errors"].append(f"Config health check failed: {e}")
407
407
 
408
408
  return check_result
@@ -414,13 +414,13 @@ class HealthCheckTool(BaseToolAdapter):
414
414
 
415
415
  statuses = [check.get("status", "unknown") for check in checks.values()]
416
416
 
417
- if "error" in statuses:
418
- return "error"
419
- if "unhealthy" in statuses:
417
+ # Check for unhealthy (handle both string and enum)
418
+ if HealthStatus.UNHEALTHY in statuses or "unhealthy" in statuses:
420
419
  return "unhealthy"
421
420
  if "warning" in statuses:
422
421
  return "warning"
423
- if all(status == "healthy" for status in statuses):
422
+ # Check for healthy (handle both string and enum)
423
+ if all(status in (HealthStatus.HEALTHY, "healthy") for status in statuses):
424
424
  return "healthy"
425
425
  return "unknown"
426
426
 
@@ -437,19 +437,20 @@ class HealthCheckTool(BaseToolAdapter):
437
437
  for check_name, check_result in checks.items():
438
438
  status = check_result.get("status", "unknown")
439
439
 
440
- if status == "healthy":
440
+ # Check for healthy (handle both string and enum)
441
+ if status in (HealthStatus.HEALTHY, "healthy"):
441
442
  summary["healthy"] += 1
442
- elif status in ["warning", "unhealthy"]:
443
+ elif status in ["warning", HealthStatus.UNHEALTHY, "unhealthy"]:
443
444
  summary["warnings"] += 1
444
445
  # Collect warning messages
445
446
  warnings = check_result.get("warnings", [])
446
447
  for warning in warnings:
447
448
  summary["issues"].append(f"{check_name}: {warning}")
448
- elif status == "error":
449
- summary["errors"] += 1
450
- # Collect error messages
451
- errors = check_result.get("errors", [])
452
- for error in errors:
453
- summary["issues"].append(f"{check_name}: {error}")
449
+ # Collect error messages if status is unhealthy
450
+ if status in (HealthStatus.UNHEALTHY, "unhealthy"):
451
+ summary["errors"] += 1
452
+ errors = check_result.get("errors", [])
453
+ for error in errors:
454
+ summary["issues"].append(f"{check_name}: {error}")
454
455
 
455
456
  return summary
@@ -196,7 +196,7 @@ class CodeAnalyzerStrategy(AnalyzerStrategy):
196
196
  total_metrics = {}
197
197
  for file_path in code_files:
198
198
  file_result = self._analyze_file(file_path, options)
199
- if file_result["status"] == "success":
199
+ if file_result["status"] == OperationResult.SUCCESS:
200
200
  results["files"].append(file_result)
201
201
 
202
202
  # Aggregate metrics
@@ -427,7 +427,7 @@ class CodeAnalyzerStrategy(AnalyzerStrategy):
427
427
  """Extract key metrics from analysis results."""
428
428
  metrics = {}
429
429
 
430
- if analysis_result.get("status") != "success":
430
+ if analysis_result.get("status") != OperationResult.SUCCESS:
431
431
  return metrics
432
432
 
433
433
  # Extract relevant metrics
@@ -599,7 +599,7 @@ class DependencyAnalyzerStrategy(AnalyzerStrategy):
599
599
  """Extract key metrics from analysis results."""
600
600
  metrics = {}
601
601
 
602
- if analysis_result.get("status") != "success":
602
+ if analysis_result.get("status") != OperationResult.SUCCESS:
603
603
  return metrics
604
604
 
605
605
  # Extract dependency counts
@@ -241,7 +241,7 @@ class PerformanceAnalyzerStrategy(AnalyzerStrategy):
241
241
 
242
242
  except Exception as e:
243
243
  logger.error(f"Error analyzing file {file_path}: {e}")
244
- results["status"] = "error"
244
+ results["status"] = OperationResult.ERROR
245
245
  results["error"] = str(e)
246
246
 
247
247
  return results
@@ -292,7 +292,7 @@ class PerformanceAnalyzerStrategy(AnalyzerStrategy):
292
292
  continue
293
293
 
294
294
  file_result = self._analyze_file(file_path, options)
295
- if file_result["status"] == "success":
295
+ if file_result["status"] == OperationResult.SUCCESS:
296
296
  results["files_analyzed"] += 1
297
297
  total_score += file_result["performance_score"]
298
298
 
@@ -803,7 +803,7 @@ class PerformanceAnalyzerStrategy(AnalyzerStrategy):
803
803
  """Extract key metrics from analysis results."""
804
804
  metrics = {}
805
805
 
806
- if analysis_result.get("status") != "success":
806
+ if analysis_result.get("status") != OperationResult.SUCCESS:
807
807
  return metrics
808
808
 
809
809
  if analysis_result.get("type") == "file":
@@ -242,7 +242,7 @@ class SecurityAnalyzerStrategy(AnalyzerStrategy):
242
242
 
243
243
  except Exception as e:
244
244
  logger.error(f"Error analyzing file {file_path}: {e}")
245
- results["status"] = "error"
245
+ results["status"] = OperationResult.ERROR
246
246
  results["error"] = str(e)
247
247
 
248
248
  return results
@@ -302,7 +302,7 @@ class SecurityAnalyzerStrategy(AnalyzerStrategy):
302
302
 
303
303
  file_result = self._analyze_file(file_path, options)
304
304
  if (
305
- file_result["status"] == "success"
305
+ file_result["status"] == OperationResult.SUCCESS
306
306
  and file_result["vulnerabilities"]
307
307
  ):
308
308
  results["files"].append(file_result)
@@ -646,7 +646,7 @@ class SecurityAnalyzerStrategy(AnalyzerStrategy):
646
646
  """Extract key metrics from analysis results."""
647
647
  metrics = {}
648
648
 
649
- if analysis_result.get("status") != "success":
649
+ if analysis_result.get("status") != OperationResult.SUCCESS:
650
650
  return metrics
651
651
 
652
652
  if analysis_result.get("type") == "file":
@@ -641,7 +641,7 @@ class StructureAnalyzerStrategy(AnalyzerStrategy):
641
641
  """Extract key metrics from analysis results."""
642
642
  metrics = {}
643
643
 
644
- if analysis_result.get("status") != "success":
644
+ if analysis_result.get("status") != OperationResult.SUCCESS:
645
645
  return metrics
646
646
 
647
647
  # Extract structure statistics
@@ -19,7 +19,7 @@ from typing import Any, Dict, List, Optional
19
19
 
20
20
  import yaml
21
21
 
22
- from claude_mpm.core.enums import OperationResult
22
+ from claude_mpm.core.enums import HealthStatus, OperationResult
23
23
  from claude_mpm.core.logging_utils import get_logger
24
24
  from claude_mpm.services.unified.strategies import StrategyMetadata, StrategyPriority
25
25
 
@@ -289,10 +289,10 @@ class LocalDeploymentStrategy(DeploymentStrategy):
289
289
 
290
290
  # Check if any file is missing
291
291
  if any(not check for check in health["checks"].values()):
292
- health["status"] = "degraded"
292
+ health["status"] = HealthStatus.DEGRADED
293
293
 
294
294
  else:
295
- health["status"] = "unhealthy"
295
+ health["status"] = HealthStatus.UNHEALTHY
296
296
 
297
297
  return health
298
298