claude-mpm 4.4.3__py3-none-any.whl → 4.4.5__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.
Files changed (118) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/agent_loader.py +3 -2
  3. claude_mpm/agents/agent_loader_integration.py +2 -1
  4. claude_mpm/agents/async_agent_loader.py +2 -2
  5. claude_mpm/agents/base_agent_loader.py +2 -2
  6. claude_mpm/agents/frontmatter_validator.py +1 -0
  7. claude_mpm/agents/system_agent_config.py +2 -1
  8. claude_mpm/cli/commands/doctor.py +44 -5
  9. claude_mpm/cli/commands/mpm_init.py +116 -62
  10. claude_mpm/cli/parsers/configure_parser.py +3 -1
  11. claude_mpm/cli/startup_logging.py +1 -3
  12. claude_mpm/config/agent_config.py +1 -1
  13. claude_mpm/config/paths.py +2 -1
  14. claude_mpm/core/agent_name_normalizer.py +1 -0
  15. claude_mpm/core/config.py +2 -1
  16. claude_mpm/core/config_aliases.py +2 -1
  17. claude_mpm/core/file_utils.py +0 -1
  18. claude_mpm/core/framework/__init__.py +6 -6
  19. claude_mpm/core/framework/formatters/__init__.py +2 -2
  20. claude_mpm/core/framework/formatters/capability_generator.py +19 -8
  21. claude_mpm/core/framework/formatters/content_formatter.py +8 -3
  22. claude_mpm/core/framework/formatters/context_generator.py +7 -3
  23. claude_mpm/core/framework/loaders/__init__.py +3 -3
  24. claude_mpm/core/framework/loaders/agent_loader.py +7 -3
  25. claude_mpm/core/framework/loaders/file_loader.py +16 -6
  26. claude_mpm/core/framework/loaders/instruction_loader.py +16 -6
  27. claude_mpm/core/framework/loaders/packaged_loader.py +36 -12
  28. claude_mpm/core/framework/processors/__init__.py +2 -2
  29. claude_mpm/core/framework/processors/memory_processor.py +14 -6
  30. claude_mpm/core/framework/processors/metadata_processor.py +5 -5
  31. claude_mpm/core/framework/processors/template_processor.py +12 -6
  32. claude_mpm/core/framework_loader.py +44 -20
  33. claude_mpm/core/log_manager.py +2 -1
  34. claude_mpm/core/tool_access_control.py +1 -0
  35. claude_mpm/core/unified_agent_registry.py +2 -1
  36. claude_mpm/core/unified_paths.py +1 -0
  37. claude_mpm/experimental/cli_enhancements.py +1 -0
  38. claude_mpm/hooks/base_hook.py +1 -0
  39. claude_mpm/hooks/instruction_reinforcement.py +1 -0
  40. claude_mpm/hooks/kuzu_memory_hook.py +20 -13
  41. claude_mpm/hooks/validation_hooks.py +1 -1
  42. claude_mpm/scripts/mpm_doctor.py +1 -0
  43. claude_mpm/services/agents/loading/agent_profile_loader.py +1 -1
  44. claude_mpm/services/agents/loading/base_agent_manager.py +1 -1
  45. claude_mpm/services/agents/loading/framework_agent_loader.py +1 -1
  46. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -0
  47. claude_mpm/services/agents/management/agent_management_service.py +1 -1
  48. claude_mpm/services/agents/memory/memory_categorization_service.py +0 -1
  49. claude_mpm/services/agents/memory/memory_file_service.py +6 -2
  50. claude_mpm/services/agents/memory/memory_format_service.py +0 -1
  51. claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
  52. claude_mpm/services/async_session_logger.py +1 -1
  53. claude_mpm/services/claude_session_logger.py +1 -0
  54. claude_mpm/services/core/path_resolver.py +1 -0
  55. claude_mpm/services/diagnostics/checks/__init__.py +2 -0
  56. claude_mpm/services/diagnostics/checks/installation_check.py +126 -25
  57. claude_mpm/services/diagnostics/checks/mcp_services_check.py +451 -0
  58. claude_mpm/services/diagnostics/diagnostic_runner.py +3 -0
  59. claude_mpm/services/diagnostics/doctor_reporter.py +259 -32
  60. claude_mpm/services/event_bus/direct_relay.py +2 -1
  61. claude_mpm/services/event_bus/event_bus.py +1 -0
  62. claude_mpm/services/event_bus/relay.py +3 -2
  63. claude_mpm/services/framework_claude_md_generator/content_assembler.py +1 -1
  64. claude_mpm/services/infrastructure/daemon_manager.py +1 -1
  65. claude_mpm/services/mcp_config_manager.py +301 -54
  66. claude_mpm/services/mcp_gateway/core/process_pool.py +62 -23
  67. claude_mpm/services/mcp_gateway/tools/__init__.py +6 -5
  68. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +3 -1
  69. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +16 -31
  70. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  71. claude_mpm/services/project/archive_manager.py +159 -96
  72. claude_mpm/services/project/documentation_manager.py +64 -45
  73. claude_mpm/services/project/enhanced_analyzer.py +132 -89
  74. claude_mpm/services/project/project_organizer.py +225 -131
  75. claude_mpm/services/response_tracker.py +1 -1
  76. claude_mpm/services/socketio/server/eventbus_integration.py +1 -1
  77. claude_mpm/services/unified/__init__.py +1 -1
  78. claude_mpm/services/unified/analyzer_strategies/__init__.py +3 -3
  79. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +97 -53
  80. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +81 -40
  81. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +277 -178
  82. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +196 -112
  83. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +83 -49
  84. claude_mpm/services/unified/config_strategies/__init__.py +111 -126
  85. claude_mpm/services/unified/config_strategies/config_schema.py +157 -111
  86. claude_mpm/services/unified/config_strategies/context_strategy.py +91 -89
  87. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +183 -173
  88. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +160 -152
  89. claude_mpm/services/unified/config_strategies/unified_config_service.py +124 -112
  90. claude_mpm/services/unified/config_strategies/validation_strategy.py +298 -259
  91. claude_mpm/services/unified/deployment_strategies/__init__.py +7 -7
  92. claude_mpm/services/unified/deployment_strategies/base.py +24 -28
  93. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +168 -88
  94. claude_mpm/services/unified/deployment_strategies/local.py +49 -34
  95. claude_mpm/services/unified/deployment_strategies/utils.py +39 -43
  96. claude_mpm/services/unified/deployment_strategies/vercel.py +30 -24
  97. claude_mpm/services/unified/interfaces.py +0 -26
  98. claude_mpm/services/unified/migration.py +17 -40
  99. claude_mpm/services/unified/strategies.py +9 -26
  100. claude_mpm/services/unified/unified_analyzer.py +48 -44
  101. claude_mpm/services/unified/unified_config.py +21 -19
  102. claude_mpm/services/unified/unified_deployment.py +21 -26
  103. claude_mpm/storage/state_storage.py +1 -0
  104. claude_mpm/utils/agent_dependency_loader.py +18 -6
  105. claude_mpm/utils/common.py +14 -12
  106. claude_mpm/utils/database_connector.py +15 -12
  107. claude_mpm/utils/error_handler.py +1 -0
  108. claude_mpm/utils/log_cleanup.py +1 -0
  109. claude_mpm/utils/path_operations.py +1 -0
  110. claude_mpm/utils/session_logging.py +1 -1
  111. claude_mpm/utils/subprocess_utils.py +1 -0
  112. claude_mpm/validation/agent_validator.py +1 -1
  113. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/METADATA +35 -15
  114. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/RECORD +118 -117
  115. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/WHEEL +0 -0
  116. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/entry_points.txt +0 -0
  117. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/licenses/LICENSE +0 -0
  118. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/top_level.txt +0 -0
@@ -22,7 +22,6 @@ Features:
22
22
  - Version control and rollback capabilities
23
23
  """
24
24
 
25
- import asyncio
26
25
  import json
27
26
  from pathlib import Path
28
27
  from typing import Any, Dict, List, Optional, Union
@@ -121,7 +120,7 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
121
120
  return True
122
121
 
123
122
  except Exception as e:
124
- self._logger.error(f"Failed to initialize: {str(e)}")
123
+ self._logger.error(f"Failed to initialize: {e!s}")
125
124
  return False
126
125
 
127
126
  async def shutdown(self) -> None:
@@ -266,16 +265,18 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
266
265
  success=True,
267
266
  config=config_with_defaults,
268
267
  validation_errors=[],
269
- applied_defaults=self._get_applied_defaults(config, config_with_defaults),
268
+ applied_defaults=self._get_applied_defaults(
269
+ config, config_with_defaults
270
+ ),
270
271
  source=str(source),
271
272
  )
272
273
 
273
274
  except Exception as e:
274
- self._logger.error(f"Failed to load configuration: {str(e)}")
275
+ self._logger.error(f"Failed to load configuration: {e!s}")
275
276
  self._metrics["validation_errors"] += 1
276
277
  return ConfigurationResult(
277
278
  success=False,
278
- validation_errors=[f"Load failed: {str(e)}"],
279
+ validation_errors=[f"Load failed: {e!s}"],
279
280
  )
280
281
 
281
282
  def save_config(
@@ -352,10 +353,10 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
352
353
  )
353
354
 
354
355
  except Exception as e:
355
- self._logger.error(f"Failed to save configuration: {str(e)}")
356
+ self._logger.error(f"Failed to save configuration: {e!s}")
356
357
  return ConfigurationResult(
357
358
  success=False,
358
- validation_errors=[f"Save failed: {str(e)}"],
359
+ validation_errors=[f"Save failed: {e!s}"],
359
360
  )
360
361
 
361
362
  def validate_config(self, config: Dict[str, Any]) -> List[str]:
@@ -414,13 +415,12 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
414
415
  # Implement merge based on strategy
415
416
  if strategy == "deep":
416
417
  return self._deep_merge(*configs)
417
- elif strategy == "shallow":
418
+ if strategy == "shallow":
418
419
  return self._shallow_merge(*configs)
419
- elif strategy == "override":
420
+ if strategy == "override":
420
421
  return self._override_merge(*configs)
421
- else:
422
- self._logger.warning(f"Unknown merge strategy: {strategy}, using deep")
423
- return self._deep_merge(*configs)
422
+ self._logger.warning(f"Unknown merge strategy: {strategy}, using deep")
423
+ return self._deep_merge(*configs)
424
424
 
425
425
  def get_config_value(
426
426
  self, key: str, default: Any = None, config: Optional[Dict[str, Any]] = None
@@ -595,9 +595,9 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
595
595
  # Infer from filename
596
596
  if "project" in path.name.lower():
597
597
  return "project"
598
- elif "agent" in path.name.lower():
598
+ if "agent" in path.name.lower():
599
599
  return "agent"
600
- elif "env" in path.name.lower():
600
+ if "env" in path.name.lower():
601
601
  return "environment"
602
602
 
603
603
  return "generic"
@@ -639,9 +639,7 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
639
639
  applied[key] = value
640
640
  return applied
641
641
 
642
- def _add_to_version_history(
643
- self, config_id: str, config: Dict[str, Any]
644
- ) -> None:
642
+ def _add_to_version_history(self, config_id: str, config: Dict[str, Any]) -> None:
645
643
  """Add configuration to version history."""
646
644
  if config_id not in self._config_versions:
647
645
  self._config_versions[config_id] = []
@@ -663,7 +661,11 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
663
661
 
664
662
  for config in configs:
665
663
  for key, value in config.items():
666
- if key in result and isinstance(result[key], dict) and isinstance(value, dict):
664
+ if (
665
+ key in result
666
+ and isinstance(result[key], dict)
667
+ and isinstance(value, dict)
668
+ ):
667
669
  result[key] = self._deep_merge(result[key], value)
668
670
  else:
669
671
  result[key] = value
@@ -685,4 +687,4 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
685
687
  """Get current timestamp."""
686
688
  from datetime import datetime
687
689
 
688
- return datetime.now().isoformat()
690
+ return datetime.now().isoformat()
@@ -21,7 +21,6 @@ Features:
21
21
  - Metrics and monitoring integration
22
22
  """
23
23
 
24
- import asyncio
25
24
  from pathlib import Path
26
25
  from typing import Any, Dict, List, Optional, Union
27
26
 
@@ -114,7 +113,7 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
114
113
  return True
115
114
 
116
115
  except Exception as e:
117
- self._logger.error(f"Failed to initialize: {str(e)}")
116
+ self._logger.error(f"Failed to initialize: {e!s}")
118
117
  return False
119
118
 
120
119
  async def shutdown(self) -> None:
@@ -215,7 +214,9 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
215
214
  strategy = self._registry.select_strategy(DeploymentStrategy, context)
216
215
 
217
216
  if not strategy:
218
- errors.append(f"No strategy available for deployment type: {deployment_type}")
217
+ errors.append(
218
+ f"No strategy available for deployment type: {deployment_type}"
219
+ )
219
220
  else:
220
221
  # Delegate validation to strategy
221
222
  strategy_errors = strategy.validate_input(config)
@@ -314,20 +315,19 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
314
315
  metadata=result,
315
316
  rollback_info=rollback_info,
316
317
  )
317
- else:
318
- self._metrics["failed_deployments"] += 1
319
- return DeploymentResult(
320
- success=False,
321
- message=result.get("error", "Deployment failed"),
322
- metadata=result,
323
- )
318
+ self._metrics["failed_deployments"] += 1
319
+ return DeploymentResult(
320
+ success=False,
321
+ message=result.get("error", "Deployment failed"),
322
+ metadata=result,
323
+ )
324
324
 
325
325
  except Exception as e:
326
- self._logger.error(f"Deployment error: {str(e)}")
326
+ self._logger.error(f"Deployment error: {e!s}")
327
327
  self._metrics["failed_deployments"] += 1
328
328
  return DeploymentResult(
329
329
  success=False,
330
- message=f"Deployment failed: {str(e)}",
330
+ message=f"Deployment failed: {e!s}",
331
331
  )
332
332
 
333
333
  def rollback(
@@ -355,9 +355,7 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
355
355
  try:
356
356
  # Get the strategy used for deployment
357
357
  strategy_name = deployment["strategy"]
358
- strategy = self._registry.get_strategy(
359
- DeploymentStrategy, strategy_name
360
- )
358
+ strategy = self._registry.get_strategy(DeploymentStrategy, strategy_name)
361
359
 
362
360
  if not strategy:
363
361
  return DeploymentResult(
@@ -380,17 +378,16 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
380
378
  success=True,
381
379
  message=f"Successfully rolled back deployment {deployment_id}",
382
380
  )
383
- else:
384
- return DeploymentResult(
385
- success=False,
386
- message="Rollback failed",
387
- )
381
+ return DeploymentResult(
382
+ success=False,
383
+ message="Rollback failed",
384
+ )
388
385
 
389
386
  except Exception as e:
390
- self._logger.error(f"Rollback error: {str(e)}")
387
+ self._logger.error(f"Rollback error: {e!s}")
391
388
  return DeploymentResult(
392
389
  success=False,
393
- message=f"Rollback failed: {str(e)}",
390
+ message=f"Rollback failed: {e!s}",
394
391
  )
395
392
 
396
393
  def list_deployments(
@@ -409,9 +406,7 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
409
406
 
410
407
  if target:
411
408
  target_str = str(target)
412
- deployments = [
413
- d for d in deployments if d["target"] == target_str
414
- ]
409
+ deployments = [d for d in deployments if d["target"] == target_str]
415
410
 
416
411
  return deployments
417
412
 
@@ -467,4 +462,4 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
467
462
  """Get current timestamp."""
468
463
  from datetime import datetime
469
464
 
470
- return datetime.now().isoformat()
465
+ return datetime.now().isoformat()
@@ -39,6 +39,7 @@ class StateStorage:
39
39
 
40
40
  # Logging
41
41
  from claude_mpm.core.logging_utils import get_logger
42
+
42
43
  logger = get_logger(__name__)
43
44
 
44
45
  # File locking support (Unix-like systems)
@@ -149,7 +149,9 @@ class AgentDependencyLoader:
149
149
 
150
150
  # Check if this is an optional package that already failed
151
151
  if package_name in self.optional_failed:
152
- logger.debug(f"Skipping optional package {package_name} (previously failed)")
152
+ logger.debug(
153
+ f"Skipping optional package {package_name} (previously failed)"
154
+ )
153
155
  return True, "optional-skipped"
154
156
 
155
157
  # Try to import and check version
@@ -174,14 +176,18 @@ class AgentDependencyLoader:
174
176
  for alternative in self.OPTIONAL_DB_PACKAGES[package_name]:
175
177
  try:
176
178
  alt_version = importlib.metadata.version(alternative)
177
- logger.info(f"Using {alternative} as alternative to {package_name}")
179
+ logger.info(
180
+ f"Using {alternative} as alternative to {package_name}"
181
+ )
178
182
  self.checked_packages.add(package_name)
179
183
  return True, f"{alternative}:{alt_version}"
180
184
  except importlib.metadata.PackageNotFoundError:
181
185
  continue
182
186
  # If no alternatives work, mark as optional failure
183
187
  self.optional_failed[package_name] = "No alternatives available"
184
- logger.warning(f"Optional package {package_name} not found, marking as optional")
188
+ logger.warning(
189
+ f"Optional package {package_name} not found, marking as optional"
190
+ )
185
191
  return True, "optional-not-found"
186
192
  return False, None
187
193
 
@@ -202,14 +208,20 @@ class AgentDependencyLoader:
202
208
  if package_name in self.OPTIONAL_DB_PACKAGES:
203
209
  for alternative in self.OPTIONAL_DB_PACKAGES[package_name]:
204
210
  try:
205
- alt_version = pkg_resources.get_distribution(alternative).version
206
- logger.info(f"Using {alternative} as alternative to {package_name}")
211
+ alt_version = pkg_resources.get_distribution(
212
+ alternative
213
+ ).version
214
+ logger.info(
215
+ f"Using {alternative} as alternative to {package_name}"
216
+ )
207
217
  self.checked_packages.add(package_name)
208
218
  return True, f"{alternative}:{alt_version}"
209
219
  except pkg_resources.DistributionNotFound:
210
220
  continue
211
221
  self.optional_failed[package_name] = "No alternatives available"
212
- logger.warning(f"Optional package {package_name} not found, marking as optional")
222
+ logger.warning(
223
+ f"Optional package {package_name} not found, marking as optional"
224
+ )
213
225
  return True, "optional-not-found"
214
226
  return False, None
215
227
 
@@ -46,7 +46,7 @@ def load_json_safe(
46
46
  file_path = Path(file_path)
47
47
 
48
48
  try:
49
- with open(file_path, "r", encoding=encoding) as f:
49
+ with open(file_path, encoding=encoding) as f:
50
50
  return json.load(f)
51
51
  except FileNotFoundError:
52
52
  logger.debug(f"JSON file not found: {file_path}")
@@ -112,7 +112,7 @@ def load_yaml_safe(
112
112
  file_path = Path(file_path)
113
113
 
114
114
  try:
115
- with open(file_path, "r", encoding=encoding) as f:
115
+ with open(file_path, encoding=encoding) as f:
116
116
  return yaml.safe_load(f) or default or {}
117
117
  except FileNotFoundError:
118
118
  logger.debug(f"YAML file not found: {file_path}")
@@ -191,11 +191,10 @@ def ensure_path_exists(
191
191
  path.parent.mkdir(parents=True, exist_ok=True)
192
192
  # Don't create the file itself, just ensure parent exists
193
193
  return path.parent.exists()
194
- else:
195
- if create_parents:
196
- path.mkdir(parents=True, exist_ok=True)
197
- return True
198
- return False
194
+ if create_parents:
195
+ path.mkdir(parents=True, exist_ok=True)
196
+ return True
197
+ return False
199
198
  except Exception as e:
200
199
  logger.error(f"Error ensuring path exists {path}: {e}")
201
200
  return False
@@ -304,8 +303,7 @@ def find_files(
304
303
 
305
304
  if recursive:
306
305
  return list(directory.rglob(pattern))
307
- else:
308
- return list(directory.glob(pattern))
306
+ return list(directory.glob(pattern))
309
307
  except Exception as e:
310
308
  logger.error(f"Error finding files in {directory}: {e}")
311
309
  return []
@@ -357,7 +355,7 @@ def run_command_safe(
357
355
  env=env,
358
356
  )
359
357
  return result
360
- except subprocess.TimeoutExpired as e:
358
+ except subprocess.TimeoutExpired:
361
359
  logger.error(f"Command timed out: {command}")
362
360
  raise
363
361
  except subprocess.CalledProcessError as e:
@@ -436,7 +434,9 @@ def get_env_int(key: str, default: int = 0) -> int:
436
434
  return default
437
435
 
438
436
 
439
- def get_env_list(key: str, separator: str = ",", default: Optional[List[str]] = None) -> List[str]:
437
+ def get_env_list(
438
+ key: str, separator: str = ",", default: Optional[List[str]] = None
439
+ ) -> List[str]:
440
440
  """
441
441
  Get list from environment variable.
442
442
 
@@ -476,6 +476,7 @@ def safe_import(module_name: str, fallback: Any = None) -> Any:
476
476
  """
477
477
  try:
478
478
  import importlib
479
+
479
480
  return importlib.import_module(module_name)
480
481
  except ImportError as e:
481
482
  logger.debug(f"Could not import {module_name}: {e}")
@@ -524,6 +525,7 @@ def deprecated(replacement: str = None):
524
525
  Returns:
525
526
  Decorated function
526
527
  """
528
+
527
529
  def decorator(func):
528
530
  def wrapper(*args, **kwargs):
529
531
  import warnings
@@ -539,4 +541,4 @@ def deprecated(replacement: str = None):
539
541
  wrapper.__doc__ = func.__doc__
540
542
  return wrapper
541
543
 
542
- return decorator
544
+ return decorator
@@ -10,7 +10,6 @@ DESIGN DECISION: We prioritize pure Python implementations over native ones
10
10
  for better cross-platform compatibility, even if they might be slightly slower.
11
11
  """
12
12
 
13
- import logging
14
13
  from typing import Any, Dict, Optional, Tuple
15
14
 
16
15
  from ..core.logger import get_logger
@@ -92,12 +91,14 @@ class DatabaseConnector:
92
91
  """
93
92
  try:
94
93
  import importlib
94
+
95
95
  return importlib.import_module(module_name)
96
96
  except ImportError:
97
97
  return None
98
98
 
99
- def get_mysql_connection_string(self, host: str, database: str, user: str,
100
- password: str, port: int = 3306) -> Optional[str]:
99
+ def get_mysql_connection_string(
100
+ self, host: str, database: str, user: str, password: str, port: int = 3306
101
+ ) -> Optional[str]:
101
102
  """
102
103
  Get a SQLAlchemy connection string for MySQL with automatic driver selection.
103
104
 
@@ -125,15 +126,16 @@ class DatabaseConnector:
125
126
  # Format connection string based on driver
126
127
  if package_name == "pymysql":
127
128
  return f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}"
128
- elif package_name == "mysqlclient":
129
+ if package_name == "mysqlclient":
129
130
  return f"mysql+mysqldb://{user}:{password}@{host}:{port}/{database}"
130
- elif package_name == "mysql-connector-python":
131
+ if package_name == "mysql-connector-python":
131
132
  return f"mysql+mysqlconnector://{user}:{password}@{host}:{port}/{database}"
132
133
 
133
134
  return None
134
135
 
135
- def get_postgresql_connection_string(self, host: str, database: str, user: str,
136
- password: str, port: int = 5432) -> Optional[str]:
136
+ def get_postgresql_connection_string(
137
+ self, host: str, database: str, user: str, password: str, port: int = 5432
138
+ ) -> Optional[str]:
137
139
  """
138
140
  Get a SQLAlchemy connection string for PostgreSQL with automatic driver selection.
139
141
 
@@ -158,13 +160,14 @@ class DatabaseConnector:
158
160
  # Format connection string based on driver
159
161
  if package_name in ["psycopg2-binary", "psycopg2"]:
160
162
  return f"postgresql+psycopg2://{user}:{password}@{host}:{port}/{database}"
161
- elif package_name == "pg8000":
163
+ if package_name == "pg8000":
162
164
  return f"postgresql+pg8000://{user}:{password}@{host}:{port}/{database}"
163
165
 
164
166
  return None
165
167
 
166
- def get_oracle_connection_string(self, host: str, database: str, user: str,
167
- password: str, port: int = 1521) -> Optional[str]:
168
+ def get_oracle_connection_string(
169
+ self, host: str, database: str, user: str, password: str, port: int = 1521
170
+ ) -> Optional[str]:
168
171
  """
169
172
  Get a SQLAlchemy connection string for Oracle with automatic driver selection.
170
173
 
@@ -189,7 +192,7 @@ class DatabaseConnector:
189
192
  # Format connection string based on driver
190
193
  if package_name == "cx_Oracle":
191
194
  return f"oracle+cx_oracle://{user}:{password}@{host}:{port}/{database}"
192
- elif package_name == "oracledb":
195
+ if package_name == "oracledb":
193
196
  return f"oracle+oracledb://{user}:{password}@{host}:{port}/{database}"
194
197
 
195
198
  return None
@@ -295,4 +298,4 @@ def test_database_connectivity() -> None:
295
298
 
296
299
  if __name__ == "__main__":
297
300
  # Run connectivity test when module is executed directly
298
- test_database_connectivity()
301
+ test_database_connectivity()
@@ -11,6 +11,7 @@ from functools import wraps
11
11
  from typing import Any, Callable, Dict, List, Optional, Type
12
12
 
13
13
  from claude_mpm.core.logging_utils import get_logger
14
+
14
15
  logger = get_logger(__name__)
15
16
 
16
17
 
@@ -13,6 +13,7 @@ from pathlib import Path
13
13
  from typing import Dict, Optional, Tuple
14
14
 
15
15
  from claude_mpm.core.logging_utils import get_logger
16
+
16
17
  logger = get_logger(__name__)
17
18
 
18
19
 
@@ -11,6 +11,7 @@ from pathlib import Path
11
11
  from typing import Callable, List, Optional, Union
12
12
 
13
13
  from claude_mpm.core.logging_utils import get_logger
14
+
14
15
  logger = get_logger(__name__)
15
16
 
16
17
 
@@ -9,9 +9,9 @@ Convenience functions for session-based response logging.
9
9
  import os
10
10
  from typing import Any, Dict, Optional
11
11
 
12
+ from claude_mpm.core.logging_utils import get_logger
12
13
  from claude_mpm.services.claude_session_logger import get_session_logger
13
14
 
14
- from claude_mpm.core.logging_utils import get_logger
15
15
  logger = get_logger(__name__)
16
16
 
17
17
 
@@ -16,6 +16,7 @@ from typing import Any, Dict, List, Optional
16
16
  import psutil
17
17
 
18
18
  from claude_mpm.core.logging_utils import get_logger
19
+
19
20
  logger = get_logger(__name__)
20
21
 
21
22
 
@@ -34,8 +34,8 @@ from claude_mpm.core.constants import (
34
34
  SystemLimits,
35
35
  TimeoutConfig,
36
36
  )
37
-
38
37
  from claude_mpm.core.logging_utils import get_logger
38
+
39
39
  logger = get_logger(__name__)
40
40
 
41
41
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.4.3
3
+ Version: 4.4.5
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team
@@ -41,11 +41,6 @@ Requires-Dist: python-frontmatter>=1.0.0
41
41
  Requires-Dist: mistune>=3.0.0
42
42
  Requires-Dist: tree-sitter>=0.21.0
43
43
  Requires-Dist: ijson>=3.2.0
44
- Requires-Dist: kuzu-memory>=1.1.1
45
- Requires-Dist: mcp>=0.1.0
46
- Requires-Dist: mcp-vector-search>=0.1.0
47
- Requires-Dist: mcp-browser>=0.1.0
48
- Requires-Dist: mcp-ticketer>=0.1.0
49
44
  Requires-Dist: toml>=0.10.2
50
45
  Requires-Dist: packaging>=21.0
51
46
  Requires-Dist: pydantic>=2.0.0
@@ -54,6 +49,12 @@ Requires-Dist: rich>=13.0.0
54
49
  Requires-Dist: pyee>=13.0.0
55
50
  Requires-Dist: importlib-resources>=5.0; python_version < "3.9"
56
51
  Requires-Dist: pathspec>=0.11.0
52
+ Provides-Extra: mcp
53
+ Requires-Dist: mcp>=0.1.0; extra == "mcp"
54
+ Requires-Dist: mcp-vector-search>=0.1.0; extra == "mcp"
55
+ Requires-Dist: mcp-browser>=0.1.0; extra == "mcp"
56
+ Requires-Dist: mcp-ticketer>=0.1.0; extra == "mcp"
57
+ Requires-Dist: kuzu-memory>=1.1.1; extra == "mcp"
57
58
  Provides-Extra: dev
58
59
  Requires-Dist: pytest>=7.0; extra == "dev"
59
60
  Requires-Dist: pytest-asyncio; extra == "dev"
@@ -157,7 +158,7 @@ A powerful orchestration framework for Claude Code that enables multi-agent work
157
158
  - 🧠 **Persistent Knowledge System**: Project-specific kuzu-memory integration for intelligent context retention
158
159
  - 🔄 **Session Management**: Resume previous sessions with `--resume`
159
160
  - 📊 **Real-Time Monitoring**: Live dashboard with `--monitor` flag
160
- - 🔌 **Auto-Installing MCP Services**: mcp-vector-search and kuzu-memory automatically installed via pipx
161
+ - 🔌 **Optional MCP Services**: mcp-vector-search and kuzu-memory with automatic fallback installation
161
162
  - 📁 **Multi-Project Support**: Per-session working directories with persistent knowledge graphs
162
163
  - 🔍 **Git Integration**: View diffs and track changes across projects
163
164
  - 🎯 **Smart Task Orchestration**: PM agent intelligently routes work to specialists
@@ -167,22 +168,32 @@ A powerful orchestration framework for Claude Code that enables multi-agent work
167
168
  ## Quick Installation
168
169
 
169
170
  ```bash
171
+ # Basic installation
170
172
  pip install claude-mpm
173
+
174
+ # Install with optional MCP services (recommended)
175
+ pip install "claude-mpm[mcp]"
171
176
  ```
172
177
 
173
178
  Or with pipx (recommended for isolated installation):
174
179
  ```bash
175
- # Install with monitor support (recommended)
176
- pipx install "claude-mpm[monitor]"
177
-
178
- # Basic installation without monitor
180
+ # Basic installation
179
181
  pipx install claude-mpm
180
182
 
183
+ # Install with optional MCP services (recommended)
184
+ pipx install "claude-mpm[mcp]"
185
+
186
+ # Install with all features
187
+ pipx install "claude-mpm[mcp,monitor]"
188
+
181
189
  # Configure MCP for pipx users:
182
190
  claude-mpm mcp-pipx-config
183
191
  ```
184
192
 
185
- **💡 Pipx Tip**: Use `"claude-mpm[monitor]"` to get full monitoring dashboard functionality! The `[monitor]` optional dependency includes Socket.IO and async web server components needed for real-time agent monitoring.
193
+ **💡 Optional Dependencies**:
194
+ - `[mcp]` - Include MCP services (mcp-vector-search, kuzu-memory) as dependencies
195
+ - `[monitor]` - Full monitoring dashboard with Socket.IO and async web server components
196
+ - Without optional dependencies, services auto-install on first use via pipx
186
197
 
187
198
  **🎉 Pipx Support Now Fully Functional!** Recent improvements ensure complete compatibility:
188
199
  - ✅ Socket.IO daemon script path resolution (fixed)
@@ -204,9 +215,18 @@ claude-mpm run --monitor
204
215
  # Use MCP Gateway for external tool integration
205
216
  claude-mpm mcp
206
217
 
207
- # Run health diagnostics
218
+ # Run comprehensive health diagnostics
208
219
  claude-mpm doctor
209
220
 
221
+ # Generate detailed diagnostic report with MCP service analysis
222
+ claude-mpm doctor --verbose --output-file doctor-report.md
223
+
224
+ # Run specific diagnostic checks including MCP services
225
+ claude-mpm doctor --checks installation configuration agents mcp
226
+
227
+ # Check MCP service status specifically
228
+ claude-mpm doctor --checks mcp --verbose
229
+
210
230
  # Manage memory for large conversation histories
211
231
  claude-mpm cleanup-memory
212
232
  ```
@@ -219,7 +239,7 @@ See [QUICKSTART.md](QUICKSTART.md) for complete usage examples.
219
239
  Following Phase 3 architectural simplification in v4.4.1, Claude MPM features:
220
240
 
221
241
  - **Streamlined Rich Interface**: Removed complex TUI system (~2,500 lines) for cleaner user experience
222
- - **Auto-Installing MCP Services**: mcp-vector-search and kuzu-memory install automatically via pipx
242
+ - **Optional MCP Services**: mcp-vector-search and kuzu-memory with automatic fallback installation
223
243
  - **Persistent Knowledge System**: Project-specific kuzu-memory databases with intelligent prompt enrichment
224
244
  - **Service-Oriented Architecture**: Simplified five specialized service domains
225
245
  - **Interface-Based Contracts**: All services implement explicit interfaces
@@ -316,7 +336,7 @@ See [docs/MEMORY.md](docs/MEMORY.md) and [docs/developer/11-dashboard/README.md]
316
336
  #### 🚀 For Operations
317
337
  - **[🚀 Deployment](docs/DEPLOYMENT.md)** - Release management & versioning
318
338
  - **[📊 Monitoring](docs/MONITOR.md)** - Real-time dashboard & metrics
319
- - **[🐛 Troubleshooting](docs/TROUBLESHOOTING.md)** - Diagnostic & problem resolution
339
+ - **[🐛 Troubleshooting](docs/TROUBLESHOOTING.md)** - Enhanced `doctor` command with detailed reports and auto-fix capabilities
320
340
 
321
341
  ### 🎯 Documentation Features
322
342
  - **Single Entry Point**: [docs/README.md](docs/README.md) is your navigation hub