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
@@ -11,6 +11,7 @@ MCP service installations.
11
11
 
12
12
  import json
13
13
  import subprocess
14
+ import sys
14
15
  from datetime import datetime, timezone
15
16
  from enum import Enum
16
17
  from pathlib import Path
@@ -76,6 +77,7 @@ class MCPConfigManager:
76
77
 
77
78
  # Check system PATH (including homebrew)
78
79
  import shutil
80
+
79
81
  system_path = shutil.which(service_name)
80
82
  if system_path and system_path not in candidates:
81
83
  candidates.append(system_path)
@@ -84,14 +86,13 @@ class MCPConfigManager:
84
86
  for path in candidates:
85
87
  try:
86
88
  result = subprocess.run(
87
- [path, "--help"],
88
- capture_output=True,
89
- text=True,
90
- timeout=5
89
+ [path, "--help"], capture_output=True, text=True, timeout=5, check=False
91
90
  )
92
91
  # Check if this version has MCP support
93
92
  if "claude" in result.stdout or "mcp" in result.stdout:
94
- self.logger.debug(f"Found kuzu-memory with MCP support at {path}")
93
+ self.logger.debug(
94
+ f"Found kuzu-memory with MCP support at {path}"
95
+ )
95
96
  return path
96
97
  except:
97
98
  pass
@@ -125,7 +126,9 @@ class MCPConfigManager:
125
126
  )
126
127
  return local_path
127
128
 
128
- self.logger.debug(f"Service {service_name} not found - will auto-install when needed")
129
+ self.logger.debug(
130
+ f"Service {service_name} not found - will auto-install when needed"
131
+ )
129
132
  return None
130
133
 
131
134
  def _check_pipx_installation(self, service_name: str) -> Optional[str]:
@@ -192,58 +195,161 @@ class MCPConfigManager:
192
195
  """
193
196
  Generate configuration for a specific MCP service.
194
197
 
198
+ Prefers 'pipx run' or 'uvx' commands over direct execution for better isolation.
199
+
195
200
  Args:
196
201
  service_name: Name of the MCP service
197
202
 
198
203
  Returns:
199
204
  Service configuration dict or None if service not found
200
205
  """
201
- service_path = self.detect_service_path(service_name)
202
- if not service_path:
203
- return None
206
+ import shutil
207
+
208
+ # Check for pipx run first (preferred for isolation)
209
+ use_pipx_run = False
210
+ use_uvx = False
211
+
212
+ # Try pipx run test
213
+ if shutil.which("pipx"):
214
+ try:
215
+ result = subprocess.run(
216
+ ["pipx", "run", service_name, "--version"],
217
+ capture_output=True,
218
+ text=True,
219
+ timeout=5,
220
+ check=False,
221
+ )
222
+ if result.returncode == 0 or "version" in result.stdout.lower():
223
+ use_pipx_run = True
224
+ self.logger.debug(f"Will use 'pipx run' for {service_name}")
225
+ except:
226
+ pass
227
+
228
+ # Try uvx if pipx run not available
229
+ if not use_pipx_run and shutil.which("uvx"):
230
+ try:
231
+ result = subprocess.run(
232
+ ["uvx", service_name, "--version"],
233
+ capture_output=True,
234
+ text=True,
235
+ timeout=5,
236
+ check=False,
237
+ )
238
+ if result.returncode == 0 or "version" in result.stdout.lower():
239
+ use_uvx = True
240
+ self.logger.debug(f"Will use 'uvx' for {service_name}")
241
+ except:
242
+ pass
204
243
 
205
- config = {
206
- "type": "stdio",
207
- "command": service_path,
208
- }
244
+ # If neither work, try to find direct path
245
+ service_path = None
246
+ if not use_pipx_run and not use_uvx:
247
+ service_path = self.detect_service_path(service_name)
248
+ if not service_path:
249
+ return None
250
+
251
+ # Build configuration
252
+ config = {"type": "stdio"}
209
253
 
210
254
  # Service-specific configurations
211
255
  if service_name == "mcp-vector-search":
212
- config["args"] = [
213
- "-m",
214
- "mcp_vector_search.mcp.server",
215
- str(self.project_root),
216
- ]
256
+ if use_pipx_run:
257
+ config["command"] = "pipx"
258
+ config["args"] = [
259
+ "run",
260
+ "mcp-vector-search",
261
+ "-m",
262
+ "mcp_vector_search.mcp.server",
263
+ str(self.project_root),
264
+ ]
265
+ elif use_uvx:
266
+ config["command"] = "uvx"
267
+ config["args"] = [
268
+ "mcp-vector-search",
269
+ "-m",
270
+ "mcp_vector_search.mcp.server",
271
+ str(self.project_root),
272
+ ]
273
+ else:
274
+ config["command"] = service_path
275
+ config["args"] = [
276
+ "-m",
277
+ "mcp_vector_search.mcp.server",
278
+ str(self.project_root),
279
+ ]
217
280
  config["env"] = {}
281
+
218
282
  elif service_name == "mcp-browser":
219
- config["args"] = ["mcp"]
283
+ if use_pipx_run:
284
+ config["command"] = "pipx"
285
+ config["args"] = ["run", "mcp-browser", "mcp"]
286
+ elif use_uvx:
287
+ config["command"] = "uvx"
288
+ config["args"] = ["mcp-browser", "mcp"]
289
+ else:
290
+ config["command"] = service_path
291
+ config["args"] = ["mcp"]
220
292
  config["env"] = {"MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")}
293
+
221
294
  elif service_name == "mcp-ticketer":
222
- config["args"] = ["mcp"]
295
+ if use_pipx_run:
296
+ config["command"] = "pipx"
297
+ config["args"] = ["run", "mcp-ticketer", "mcp"]
298
+ elif use_uvx:
299
+ config["command"] = "uvx"
300
+ config["args"] = ["mcp-ticketer", "mcp"]
301
+ else:
302
+ config["command"] = service_path
303
+ config["args"] = ["mcp"]
304
+
223
305
  elif service_name == "kuzu-memory":
224
- # Check kuzu-memory version to determine correct command
225
- # v1.1.0+ has "claude mcp-server", v1.0.0 has "serve"
226
- import subprocess
227
- try:
228
- result = subprocess.run(
229
- [service_path, "--help"],
230
- capture_output=True,
231
- text=True,
232
- timeout=10
233
- )
234
- if "claude" in result.stdout:
235
- # v1.1.0+ with claude command
236
- config["args"] = ["claude", "mcp-server"]
237
- else:
238
- # v1.0.0 with serve command
239
- config["args"] = ["serve"]
240
- except:
241
- # Default to older version command
242
- config["args"] = ["serve"]
243
- # kuzu-memory works with project-specific databases, no custom path needed
306
+ # Determine kuzu-memory command version
307
+ kuzu_args = []
308
+ test_cmd = None
309
+
310
+ if use_pipx_run:
311
+ test_cmd = ["pipx", "run", "kuzu-memory", "--help"]
312
+ elif use_uvx:
313
+ test_cmd = ["uvx", "kuzu-memory", "--help"]
314
+ elif service_path:
315
+ test_cmd = [service_path, "--help"]
316
+
317
+ if test_cmd:
318
+ try:
319
+ result = subprocess.run(
320
+ test_cmd, capture_output=True, text=True, timeout=10, check=False
321
+ )
322
+ if "claude" in result.stdout:
323
+ # v1.1.0+ with claude command
324
+ kuzu_args = ["claude", "mcp-server"]
325
+ else:
326
+ # v1.0.0 with serve command
327
+ kuzu_args = ["serve"]
328
+ except:
329
+ # Default to newer version command
330
+ kuzu_args = ["claude", "mcp-server"]
331
+
332
+ if use_pipx_run:
333
+ config["command"] = "pipx"
334
+ config["args"] = ["run", "kuzu-memory"] + kuzu_args
335
+ elif use_uvx:
336
+ config["command"] = "uvx"
337
+ config["args"] = ["kuzu-memory"] + kuzu_args
338
+ else:
339
+ config["command"] = service_path
340
+ config["args"] = kuzu_args
341
+
244
342
  else:
245
343
  # Generic config for unknown services
246
- config["args"] = []
344
+ if use_pipx_run:
345
+ config["command"] = "pipx"
346
+ config["args"] = ["run", service_name]
347
+ elif use_uvx:
348
+ config["command"] = "uvx"
349
+ config["args"] = [service_name]
350
+ else:
351
+ config["command"] = service_path
352
+ config["args"] = []
247
353
 
248
354
  return config
249
355
 
@@ -464,7 +570,7 @@ class MCPConfigManager:
464
570
 
465
571
  def install_missing_services(self) -> Tuple[bool, str]:
466
572
  """
467
- Install missing MCP services via pipx.
573
+ Install missing MCP services via pipx with verification and fallbacks.
468
574
 
469
575
  Returns:
470
576
  Tuple of (success, message)
@@ -481,22 +587,163 @@ class MCPConfigManager:
481
587
  failed = []
482
588
 
483
589
  for service_name in missing:
484
- try:
485
- self.logger.info(f"Installing {service_name} via pipx...")
486
- subprocess.run(
487
- ["pipx", "install", service_name],
488
- capture_output=True,
489
- text=True,
490
- check=True,
491
- )
492
- installed.append(service_name)
493
- self.logger.info(f"Successfully installed {service_name}")
494
- except subprocess.CalledProcessError as e:
590
+ # Try pipx install first
591
+ success, method = self._install_service_with_fallback(service_name)
592
+ if success:
593
+ installed.append(f"{service_name} ({method})")
594
+ self.logger.info(f"Successfully installed {service_name} via {method}")
595
+ else:
495
596
  failed.append(service_name)
496
- self.logger.error(f"Failed to install {service_name}: {e.stderr}")
597
+ self.logger.error(f"Failed to install {service_name}")
497
598
 
498
599
  if failed:
499
600
  return False, f"Failed to install: {', '.join(failed)}"
500
601
  if installed:
501
602
  return True, f"Successfully installed: {', '.join(installed)}"
502
603
  return True, "No services needed installation"
604
+
605
+ def _install_service_with_fallback(self, service_name: str) -> Tuple[bool, str]:
606
+ """
607
+ Install a service with multiple fallback methods.
608
+
609
+ Returns:
610
+ Tuple of (success, installation_method)
611
+ """
612
+ import shutil
613
+
614
+ # Method 1: Try pipx install
615
+ if shutil.which("pipx"):
616
+ try:
617
+ self.logger.debug(f"Attempting to install {service_name} via pipx...")
618
+ result = subprocess.run(
619
+ ["pipx", "install", service_name],
620
+ capture_output=True,
621
+ text=True,
622
+ timeout=120, # 2 minute timeout
623
+ check=False,
624
+ )
625
+
626
+ if result.returncode == 0:
627
+ # Verify installation worked
628
+ if self._verify_service_installed(service_name, "pipx"):
629
+ return True, "pipx"
630
+
631
+ self.logger.warning(
632
+ f"pipx install succeeded but verification failed for {service_name}"
633
+ )
634
+ else:
635
+ self.logger.debug(
636
+ f"pipx install failed: {result.stderr}"
637
+ )
638
+ except subprocess.TimeoutExpired:
639
+ self.logger.warning(f"pipx install timed out for {service_name}")
640
+ except Exception as e:
641
+ self.logger.debug(f"pipx install error: {e}")
642
+
643
+ # Method 2: Try uvx (if available)
644
+ if shutil.which("uvx"):
645
+ try:
646
+ self.logger.debug(f"Attempting to install {service_name} via uvx...")
647
+ result = subprocess.run(
648
+ ["uvx", "install", service_name],
649
+ capture_output=True,
650
+ text=True,
651
+ timeout=120,
652
+ check=False,
653
+ )
654
+
655
+ if result.returncode == 0:
656
+ if self._verify_service_installed(service_name, "uvx"):
657
+ return True, "uvx"
658
+ except Exception as e:
659
+ self.logger.debug(f"uvx install error: {e}")
660
+
661
+ # Method 3: Try pip install --user
662
+ try:
663
+ self.logger.debug(f"Attempting to install {service_name} via pip --user...")
664
+ result = subprocess.run(
665
+ [sys.executable, "-m", "pip", "install", "--user", service_name],
666
+ capture_output=True,
667
+ text=True,
668
+ timeout=120,
669
+ check=False,
670
+ )
671
+
672
+ if result.returncode == 0:
673
+ if self._verify_service_installed(service_name, "pip"):
674
+ return True, "pip --user"
675
+
676
+ self.logger.warning(
677
+ f"pip install succeeded but verification failed for {service_name}"
678
+ )
679
+ except Exception as e:
680
+ self.logger.debug(f"pip install error: {e}")
681
+
682
+ return False, "none"
683
+
684
+ def _verify_service_installed(self, service_name: str, method: str) -> bool:
685
+ """
686
+ Verify that a service was successfully installed and is functional.
687
+
688
+ Args:
689
+ service_name: Name of the service
690
+ method: Installation method used
691
+
692
+ Returns:
693
+ True if service is installed and functional
694
+ """
695
+ import time
696
+
697
+ # Give the installation a moment to settle
698
+ time.sleep(1)
699
+
700
+ # Check if we can find the service
701
+ service_path = self.detect_service_path(service_name)
702
+ if not service_path:
703
+ # Try pipx run as fallback for pipx installations
704
+ if method == "pipx":
705
+ try:
706
+ result = subprocess.run(
707
+ ["pipx", "run", service_name, "--version"],
708
+ capture_output=True,
709
+ text=True,
710
+ timeout=10,
711
+ check=False,
712
+ )
713
+ if result.returncode == 0 or "version" in result.stdout.lower():
714
+ self.logger.debug(f"{service_name} accessible via 'pipx run'")
715
+ return True
716
+ except:
717
+ pass
718
+ return False
719
+
720
+ # Try to verify it works
721
+ try:
722
+ # Different services may need different verification
723
+ test_commands = [
724
+ [service_path, "--version"],
725
+ [service_path, "--help"],
726
+ ]
727
+
728
+ for cmd in test_commands:
729
+ result = subprocess.run(
730
+ cmd,
731
+ capture_output=True,
732
+ text=True,
733
+ timeout=10,
734
+ check=False,
735
+ )
736
+
737
+ output = (result.stdout + result.stderr).lower()
738
+ # Check for signs of success
739
+ if result.returncode == 0:
740
+ return True
741
+ # Some tools return non-zero but still work
742
+ elif any(indicator in output for indicator in ["version", "usage", "help", service_name.lower()]):
743
+ # Make sure it's not an error message
744
+ if not any(error in output for error in ["error", "not found", "traceback", "no such"]):
745
+ return True
746
+ except Exception as e:
747
+ self.logger.debug(f"Verification error for {service_name}: {e}")
748
+
749
+ return False
@@ -395,6 +395,7 @@ async def auto_initialize_vector_search():
395
395
  try:
396
396
  # Import MCPConfigManager to handle installation
397
397
  from claude_mpm.services.mcp_config_manager import MCPConfigManager
398
+
398
399
  config_manager = MCPConfigManager()
399
400
 
400
401
  # Check if mcp-vector-search is already installed
@@ -411,7 +412,9 @@ async def auto_initialize_vector_search():
411
412
  import subprocess
412
413
 
413
414
  if not shutil.which("pipx"):
414
- logger.warning("⚠️ pipx not found. Please install pipx to enable automatic mcp-vector-search installation")
415
+ logger.warning(
416
+ "⚠️ pipx not found. Please install pipx to enable automatic mcp-vector-search installation"
417
+ )
415
418
  logger.info(" Install pipx with: python -m pip install --user pipx")
416
419
  return
417
420
 
@@ -420,26 +423,34 @@ async def auto_initialize_vector_search():
420
423
  ["pipx", "install", "mcp-vector-search"],
421
424
  capture_output=True,
422
425
  text=True,
423
- timeout=60 # 1 minute timeout for installation
426
+ timeout=60, check=False, # 1 minute timeout for installation
424
427
  )
425
428
 
426
429
  if result.returncode == 0:
427
430
  logger.info("✅ mcp-vector-search installed successfully")
428
431
  # Detect the newly installed path
429
- vector_search_path = config_manager.detect_service_path("mcp-vector-search")
432
+ vector_search_path = config_manager.detect_service_path(
433
+ "mcp-vector-search"
434
+ )
430
435
  if not vector_search_path:
431
- logger.warning("mcp-vector-search installed but command not found in PATH")
436
+ logger.warning(
437
+ "mcp-vector-search installed but command not found in PATH"
438
+ )
432
439
  return
433
440
 
434
441
  # Update the Claude configuration to include the newly installed service
435
442
  logger.info("📝 Updating Claude configuration...")
436
- config_success, config_msg = config_manager.ensure_mcp_services_configured()
443
+ config_success, config_msg = (
444
+ config_manager.ensure_mcp_services_configured()
445
+ )
437
446
  if config_success:
438
447
  logger.info(f"✅ {config_msg}")
439
448
  else:
440
449
  logger.warning(f"⚠️ Configuration update issue: {config_msg}")
441
450
  else:
442
- logger.warning(f"Failed to install mcp-vector-search: {result.stderr}")
451
+ logger.warning(
452
+ f"Failed to install mcp-vector-search: {result.stderr}"
453
+ )
443
454
  return
444
455
 
445
456
  except subprocess.TimeoutExpired:
@@ -452,10 +463,14 @@ async def auto_initialize_vector_search():
452
463
  # At this point, mcp-vector-search should be available
453
464
  # Get the actual command to use
454
465
  import shutil
466
+
455
467
  vector_search_cmd = shutil.which("mcp-vector-search")
456
468
  if not vector_search_cmd:
457
469
  # Try pipx installation path as fallback
458
- pipx_path = Path.home() / ".local/pipx/venvs/mcp-vector-search/bin/mcp-vector-search"
470
+ pipx_path = (
471
+ Path.home()
472
+ / ".local/pipx/venvs/mcp-vector-search/bin/mcp-vector-search"
473
+ )
459
474
  if pipx_path.exists():
460
475
  vector_search_cmd = str(pipx_path)
461
476
  else:
@@ -477,10 +492,13 @@ async def auto_initialize_vector_search():
477
492
  if chroma_db.exists() and chroma_db.stat().st_size > 0:
478
493
  logger.info("✓ Vector search index is healthy and ready")
479
494
  return
480
- else:
481
- logger.info("⚠️ Vector search index may be corrupted, rebuilding...")
495
+ logger.info(
496
+ "⚠️ Vector search index may be corrupted, rebuilding..."
497
+ )
482
498
  except Exception as e:
483
- logger.debug(f"Vector search health check failed: {e}, will attempt to rebuild")
499
+ logger.debug(
500
+ f"Vector search health check failed: {e}, will attempt to rebuild"
501
+ )
484
502
 
485
503
  # Initialize or reinitialize the project
486
504
  logger.info(f"🎯 Initializing vector search for project: {current_dir}")
@@ -488,12 +506,13 @@ async def auto_initialize_vector_search():
488
506
  # Initialize the project (this creates the config)
489
507
  # Note: mcp-vector-search operates on the current directory
490
508
  import subprocess
509
+
491
510
  proc = subprocess.run(
492
511
  [vector_search_cmd, "init"],
493
512
  capture_output=True,
494
513
  text=True,
495
514
  timeout=30,
496
- cwd=str(current_dir) # Run in the project directory
515
+ cwd=str(current_dir), check=False, # Run in the project directory
497
516
  )
498
517
 
499
518
  if proc.returncode == 0:
@@ -508,29 +527,36 @@ async def auto_initialize_vector_search():
508
527
  capture_output=True,
509
528
  text=True,
510
529
  timeout=300, # 5 minute timeout for indexing
511
- cwd=str(current_dir) # Run in the project directory
530
+ cwd=str(current_dir), check=False, # Run in the project directory
512
531
  )
513
532
  if index_proc.returncode == 0:
514
533
  logger.info("✅ Project indexing completed successfully")
515
534
  # Parse output to show statistics if available
516
535
  if "indexed" in index_proc.stdout.lower():
517
536
  # Extract and log indexing statistics
518
- lines = index_proc.stdout.strip().split('\n')
537
+ lines = index_proc.stdout.strip().split("\n")
519
538
  for line in lines:
520
539
  if "indexed" in line.lower() or "files" in line.lower():
521
540
  logger.info(f" {line.strip()}")
522
541
  else:
523
- logger.warning(f"⚠️ Project indexing failed: {index_proc.stderr}")
542
+ logger.warning(
543
+ f"⚠️ Project indexing failed: {index_proc.stderr}"
544
+ )
524
545
  except subprocess.TimeoutExpired:
525
- logger.warning("⚠️ Project indexing timed out (will continue in background)")
546
+ logger.warning(
547
+ "⚠️ Project indexing timed out (will continue in background)"
548
+ )
526
549
  except Exception as e:
527
550
  logger.debug(f"Background indexing error (non-critical): {e}")
528
551
 
529
552
  # Run indexing in background thread
530
553
  import threading
554
+
531
555
  index_thread = threading.Thread(target=background_index, daemon=True)
532
556
  index_thread.start()
533
- logger.info("📚 Background indexing started - vector search will be available shortly")
557
+ logger.info(
558
+ "📚 Background indexing started - vector search will be available shortly"
559
+ )
534
560
 
535
561
  else:
536
562
  logger.warning(f"⚠️ Vector search initialization failed: {proc.stderr}")
@@ -556,6 +582,7 @@ async def auto_initialize_kuzu_memory():
556
582
  try:
557
583
  # Import MCPConfigManager to handle installation
558
584
  from claude_mpm.services.mcp_config_manager import MCPConfigManager
585
+
559
586
  config_manager = MCPConfigManager()
560
587
 
561
588
  # Check if kuzu-memory is already installed
@@ -572,7 +599,9 @@ async def auto_initialize_kuzu_memory():
572
599
  import subprocess
573
600
 
574
601
  if not shutil.which("pipx"):
575
- logger.warning("⚠️ pipx not found. Please install pipx to enable automatic kuzu-memory installation")
602
+ logger.warning(
603
+ "⚠️ pipx not found. Please install pipx to enable automatic kuzu-memory installation"
604
+ )
576
605
  logger.info(" Install pipx with: python -m pip install --user pipx")
577
606
  return
578
607
 
@@ -581,7 +610,7 @@ async def auto_initialize_kuzu_memory():
581
610
  ["pipx", "install", "kuzu-memory"],
582
611
  capture_output=True,
583
612
  text=True,
584
- timeout=60 # 1 minute timeout for installation
613
+ timeout=60, check=False, # 1 minute timeout for installation
585
614
  )
586
615
 
587
616
  if result.returncode == 0:
@@ -589,12 +618,16 @@ async def auto_initialize_kuzu_memory():
589
618
  # Detect the newly installed path
590
619
  kuzu_memory_path = config_manager.detect_service_path("kuzu-memory")
591
620
  if not kuzu_memory_path:
592
- logger.warning("kuzu-memory installed but command not found in PATH")
621
+ logger.warning(
622
+ "kuzu-memory installed but command not found in PATH"
623
+ )
593
624
  return
594
625
 
595
626
  # Update the Claude configuration to include the newly installed service
596
627
  logger.info("📝 Updating Claude configuration...")
597
- config_success, config_msg = config_manager.ensure_mcp_services_configured()
628
+ config_success, config_msg = (
629
+ config_manager.ensure_mcp_services_configured()
630
+ )
598
631
  if config_success:
599
632
  logger.info(f"✅ {config_msg}")
600
633
  else:
@@ -613,6 +646,7 @@ async def auto_initialize_kuzu_memory():
613
646
  # At this point, kuzu-memory should be available
614
647
  # Get the actual command to use
615
648
  import shutil
649
+
616
650
  kuzu_memory_cmd = shutil.which("kuzu-memory")
617
651
  if not kuzu_memory_cmd:
618
652
  # Try pipx installation path as fallback
@@ -629,18 +663,23 @@ async def auto_initialize_kuzu_memory():
629
663
 
630
664
  # Check if database is already initialized
631
665
  if kuzu_memories_dir.exists():
632
- logger.debug(f"Kuzu-memory database already initialized at {kuzu_memories_dir}")
666
+ logger.debug(
667
+ f"Kuzu-memory database already initialized at {kuzu_memories_dir}"
668
+ )
633
669
  else:
634
- logger.info(f"🎯 Initializing kuzu-memory database for project: {current_dir}")
670
+ logger.info(
671
+ f"🎯 Initializing kuzu-memory database for project: {current_dir}"
672
+ )
635
673
 
636
674
  # Initialize the database in current project directory
637
675
  import subprocess
676
+
638
677
  proc = subprocess.run(
639
678
  [kuzu_memory_cmd, "init"],
640
679
  capture_output=True,
641
680
  text=True,
642
681
  timeout=30,
643
- cwd=str(current_dir),
682
+ cwd=str(current_dir), check=False,
644
683
  )
645
684
 
646
685
  if proc.returncode == 0:
@@ -14,11 +14,12 @@ from .base_adapter import (
14
14
  from .document_summarizer import DocumentSummarizerTool
15
15
  from .kuzu_memory_service import (
16
16
  KuzuMemoryService,
17
- store_memory,
17
+ get_context,
18
18
  recall_memories,
19
19
  search_memories,
20
- get_context,
20
+ store_memory,
21
21
  )
22
+
22
23
  # Ticket tools removed - using mcp-ticketer instead
23
24
 
24
25
  __all__ = [
@@ -26,10 +27,10 @@ __all__ = [
26
27
  "CalculatorToolAdapter",
27
28
  "DocumentSummarizerTool",
28
29
  "EchoToolAdapter",
29
- "SystemInfoToolAdapter",
30
30
  "KuzuMemoryService",
31
- "store_memory",
31
+ "SystemInfoToolAdapter",
32
+ "get_context",
32
33
  "recall_memories",
33
34
  "search_memories",
34
- "get_context",
35
+ "store_memory",
35
36
  ]