claude-mpm 4.4.0__py3-none-any.whl → 4.4.3__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 (50) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/WORKFLOW.md +2 -14
  3. claude_mpm/cli/commands/configure.py +2 -29
  4. claude_mpm/cli/commands/mpm_init.py +3 -3
  5. claude_mpm/cli/parsers/configure_parser.py +4 -15
  6. claude_mpm/core/framework/__init__.py +38 -0
  7. claude_mpm/core/framework/formatters/__init__.py +11 -0
  8. claude_mpm/core/framework/formatters/capability_generator.py +356 -0
  9. claude_mpm/core/framework/formatters/content_formatter.py +283 -0
  10. claude_mpm/core/framework/formatters/context_generator.py +180 -0
  11. claude_mpm/core/framework/loaders/__init__.py +13 -0
  12. claude_mpm/core/framework/loaders/agent_loader.py +202 -0
  13. claude_mpm/core/framework/loaders/file_loader.py +213 -0
  14. claude_mpm/core/framework/loaders/instruction_loader.py +151 -0
  15. claude_mpm/core/framework/loaders/packaged_loader.py +208 -0
  16. claude_mpm/core/framework/processors/__init__.py +11 -0
  17. claude_mpm/core/framework/processors/memory_processor.py +222 -0
  18. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  19. claude_mpm/core/framework/processors/template_processor.py +238 -0
  20. claude_mpm/core/framework_loader.py +277 -1798
  21. claude_mpm/hooks/__init__.py +9 -1
  22. claude_mpm/hooks/kuzu_memory_hook.py +352 -0
  23. claude_mpm/services/core/path_resolver.py +1 -0
  24. claude_mpm/services/diagnostics/diagnostic_runner.py +1 -0
  25. claude_mpm/services/mcp_config_manager.py +67 -4
  26. claude_mpm/services/mcp_gateway/core/process_pool.py +281 -0
  27. claude_mpm/services/mcp_gateway/core/startup_verification.py +2 -2
  28. claude_mpm/services/mcp_gateway/main.py +3 -13
  29. claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -10
  30. claude_mpm/services/mcp_gateway/tools/__init__.py +13 -2
  31. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +36 -6
  32. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +542 -0
  33. claude_mpm/services/shared/__init__.py +2 -1
  34. claude_mpm/services/shared/service_factory.py +8 -5
  35. claude_mpm/services/unified/config_strategies/__init__.py +190 -0
  36. claude_mpm/services/unified/config_strategies/config_schema.py +689 -0
  37. claude_mpm/services/unified/config_strategies/context_strategy.py +748 -0
  38. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +999 -0
  39. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +871 -0
  40. claude_mpm/services/unified/config_strategies/unified_config_service.py +802 -0
  41. claude_mpm/services/unified/config_strategies/validation_strategy.py +1105 -0
  42. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/METADATA +15 -15
  43. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/RECORD +47 -27
  44. claude_mpm/cli/commands/configure_tui.py +0 -1927
  45. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
  46. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
  47. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/WHEEL +0 -0
  48. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/entry_points.txt +0 -0
  49. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/licenses/LICENSE +0 -0
  50. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.3.dist-info}/top_level.txt +0 -0
@@ -377,8 +377,289 @@ def get_process_pool() -> MCPProcessPool:
377
377
  return _pool
378
378
 
379
379
 
380
+ async def auto_initialize_vector_search():
381
+ """
382
+ Auto-initialize mcp-vector-search for the current project.
383
+
384
+ WHY: Vector search requires project initialization before it can be used.
385
+ This function ensures the current project is automatically initialized
386
+ for vector search when the system starts up.
387
+
388
+ DESIGN DECISION:
389
+ - Automatically install mcp-vector-search if not present
390
+ - Run in background with timeout to avoid blocking startup
391
+ - Failures are logged but don't prevent the system from starting
392
+ """
393
+ logger = get_logger("vector_search_init")
394
+
395
+ try:
396
+ # Import MCPConfigManager to handle installation
397
+ from claude_mpm.services.mcp_config_manager import MCPConfigManager
398
+ config_manager = MCPConfigManager()
399
+
400
+ # Check if mcp-vector-search is already installed
401
+ vector_search_path = config_manager.detect_service_path("mcp-vector-search")
402
+
403
+ if vector_search_path:
404
+ logger.debug(f"mcp-vector-search found at: {vector_search_path}")
405
+ else:
406
+ # Not installed - attempt installation
407
+ logger.info("🔍 mcp-vector-search not found. Installing via pipx...")
408
+
409
+ # First check if pipx is available
410
+ import shutil
411
+ import subprocess
412
+
413
+ if not shutil.which("pipx"):
414
+ logger.warning("⚠️ pipx not found. Please install pipx to enable automatic mcp-vector-search installation")
415
+ logger.info(" Install pipx with: python -m pip install --user pipx")
416
+ return
417
+
418
+ try:
419
+ result = subprocess.run(
420
+ ["pipx", "install", "mcp-vector-search"],
421
+ capture_output=True,
422
+ text=True,
423
+ timeout=60 # 1 minute timeout for installation
424
+ )
425
+
426
+ if result.returncode == 0:
427
+ logger.info("✅ mcp-vector-search installed successfully")
428
+ # Detect the newly installed path
429
+ vector_search_path = config_manager.detect_service_path("mcp-vector-search")
430
+ if not vector_search_path:
431
+ logger.warning("mcp-vector-search installed but command not found in PATH")
432
+ return
433
+
434
+ # Update the Claude configuration to include the newly installed service
435
+ logger.info("📝 Updating Claude configuration...")
436
+ config_success, config_msg = config_manager.ensure_mcp_services_configured()
437
+ if config_success:
438
+ logger.info(f"✅ {config_msg}")
439
+ else:
440
+ logger.warning(f"⚠️ Configuration update issue: {config_msg}")
441
+ else:
442
+ logger.warning(f"Failed to install mcp-vector-search: {result.stderr}")
443
+ return
444
+
445
+ except subprocess.TimeoutExpired:
446
+ logger.warning("Installation of mcp-vector-search timed out")
447
+ return
448
+ except Exception as e:
449
+ logger.warning(f"Error installing mcp-vector-search: {e}")
450
+ return
451
+
452
+ # At this point, mcp-vector-search should be available
453
+ # Get the actual command to use
454
+ import shutil
455
+ vector_search_cmd = shutil.which("mcp-vector-search")
456
+ if not vector_search_cmd:
457
+ # Try pipx installation path as fallback
458
+ pipx_path = Path.home() / ".local/pipx/venvs/mcp-vector-search/bin/mcp-vector-search"
459
+ if pipx_path.exists():
460
+ vector_search_cmd = str(pipx_path)
461
+ else:
462
+ logger.debug("mcp-vector-search command not found after installation")
463
+ return
464
+
465
+ # Check if current project is already initialized
466
+ current_dir = Path.cwd()
467
+ vector_config = current_dir / ".mcp-vector-search/config.json"
468
+
469
+ if vector_config.exists():
470
+ logger.debug(f"Vector search already initialized for {current_dir}")
471
+ # Check if index needs rebuilding (corrupted database)
472
+ chroma_db = current_dir / ".mcp-vector-search/chroma.sqlite3"
473
+ if chroma_db.exists():
474
+ # Quick health check - verify database file exists and is accessible
475
+ try:
476
+ # Check if database file exists and has reasonable size
477
+ if chroma_db.exists() and chroma_db.stat().st_size > 0:
478
+ logger.info("✓ Vector search index is healthy and ready")
479
+ return
480
+ else:
481
+ logger.info("⚠️ Vector search index may be corrupted, rebuilding...")
482
+ except Exception as e:
483
+ logger.debug(f"Vector search health check failed: {e}, will attempt to rebuild")
484
+
485
+ # Initialize or reinitialize the project
486
+ logger.info(f"🎯 Initializing vector search for project: {current_dir}")
487
+
488
+ # Initialize the project (this creates the config)
489
+ # Note: mcp-vector-search operates on the current directory
490
+ import subprocess
491
+ proc = subprocess.run(
492
+ [vector_search_cmd, "init"],
493
+ capture_output=True,
494
+ text=True,
495
+ timeout=30,
496
+ cwd=str(current_dir) # Run in the project directory
497
+ )
498
+
499
+ if proc.returncode == 0:
500
+ logger.info("✅ Vector search initialization completed")
501
+
502
+ # Start background indexing (non-blocking)
503
+ def background_index():
504
+ try:
505
+ logger.info("🔄 Starting project indexing in background...")
506
+ index_proc = subprocess.run(
507
+ [vector_search_cmd, "index", "main"],
508
+ capture_output=True,
509
+ text=True,
510
+ timeout=300, # 5 minute timeout for indexing
511
+ cwd=str(current_dir) # Run in the project directory
512
+ )
513
+ if index_proc.returncode == 0:
514
+ logger.info("✅ Project indexing completed successfully")
515
+ # Parse output to show statistics if available
516
+ if "indexed" in index_proc.stdout.lower():
517
+ # Extract and log indexing statistics
518
+ lines = index_proc.stdout.strip().split('\n')
519
+ for line in lines:
520
+ if "indexed" in line.lower() or "files" in line.lower():
521
+ logger.info(f" {line.strip()}")
522
+ else:
523
+ logger.warning(f"⚠️ Project indexing failed: {index_proc.stderr}")
524
+ except subprocess.TimeoutExpired:
525
+ logger.warning("⚠️ Project indexing timed out (will continue in background)")
526
+ except Exception as e:
527
+ logger.debug(f"Background indexing error (non-critical): {e}")
528
+
529
+ # Run indexing in background thread
530
+ import threading
531
+ index_thread = threading.Thread(target=background_index, daemon=True)
532
+ index_thread.start()
533
+ logger.info("📚 Background indexing started - vector search will be available shortly")
534
+
535
+ else:
536
+ logger.warning(f"⚠️ Vector search initialization failed: {proc.stderr}")
537
+
538
+ except Exception as e:
539
+ logger.debug(f"Vector search auto-initialization error (non-critical): {e}")
540
+
541
+
542
+ async def auto_initialize_kuzu_memory():
543
+ """
544
+ Auto-initialize kuzu-memory for persistent knowledge storage.
545
+
546
+ WHY: Kuzu-memory provides a graph database for structured memory storage
547
+ with semantic search capabilities, enabling persistent context across sessions.
548
+
549
+ DESIGN DECISION:
550
+ - Automatically install kuzu-memory if not present via pipx
551
+ - Initialize database in background to avoid blocking startup
552
+ - Failures are logged but don't prevent the system from starting
553
+ """
554
+ logger = get_logger("kuzu_memory_init")
555
+
556
+ try:
557
+ # Import MCPConfigManager to handle installation
558
+ from claude_mpm.services.mcp_config_manager import MCPConfigManager
559
+ config_manager = MCPConfigManager()
560
+
561
+ # Check if kuzu-memory is already installed
562
+ kuzu_memory_path = config_manager.detect_service_path("kuzu-memory")
563
+
564
+ if kuzu_memory_path:
565
+ logger.debug(f"kuzu-memory found at: {kuzu_memory_path}")
566
+ else:
567
+ # Not installed - attempt installation
568
+ logger.info("🧠 kuzu-memory not found. Installing via pipx...")
569
+
570
+ # First check if pipx is available
571
+ import shutil
572
+ import subprocess
573
+
574
+ if not shutil.which("pipx"):
575
+ logger.warning("⚠️ pipx not found. Please install pipx to enable automatic kuzu-memory installation")
576
+ logger.info(" Install pipx with: python -m pip install --user pipx")
577
+ return
578
+
579
+ try:
580
+ result = subprocess.run(
581
+ ["pipx", "install", "kuzu-memory"],
582
+ capture_output=True,
583
+ text=True,
584
+ timeout=60 # 1 minute timeout for installation
585
+ )
586
+
587
+ if result.returncode == 0:
588
+ logger.info("✅ kuzu-memory installed successfully")
589
+ # Detect the newly installed path
590
+ kuzu_memory_path = config_manager.detect_service_path("kuzu-memory")
591
+ if not kuzu_memory_path:
592
+ logger.warning("kuzu-memory installed but command not found in PATH")
593
+ return
594
+
595
+ # Update the Claude configuration to include the newly installed service
596
+ logger.info("📝 Updating Claude configuration...")
597
+ config_success, config_msg = config_manager.ensure_mcp_services_configured()
598
+ if config_success:
599
+ logger.info(f"✅ {config_msg}")
600
+ else:
601
+ logger.warning(f"⚠️ Configuration update issue: {config_msg}")
602
+ else:
603
+ logger.warning(f"Failed to install kuzu-memory: {result.stderr}")
604
+ return
605
+
606
+ except subprocess.TimeoutExpired:
607
+ logger.warning("Installation of kuzu-memory timed out")
608
+ return
609
+ except Exception as e:
610
+ logger.warning(f"Error installing kuzu-memory: {e}")
611
+ return
612
+
613
+ # At this point, kuzu-memory should be available
614
+ # Get the actual command to use
615
+ import shutil
616
+ kuzu_memory_cmd = shutil.which("kuzu-memory")
617
+ if not kuzu_memory_cmd:
618
+ # Try pipx installation path as fallback
619
+ pipx_path = Path.home() / ".local/pipx/venvs/kuzu-memory/bin/kuzu-memory"
620
+ if pipx_path.exists():
621
+ kuzu_memory_cmd = str(pipx_path)
622
+ else:
623
+ logger.debug("kuzu-memory command not found after installation")
624
+ return
625
+
626
+ # Initialize kuzu-memory database in current project
627
+ current_dir = Path.cwd()
628
+ kuzu_memories_dir = current_dir / "kuzu-memories"
629
+
630
+ # Check if database is already initialized
631
+ if kuzu_memories_dir.exists():
632
+ logger.debug(f"Kuzu-memory database already initialized at {kuzu_memories_dir}")
633
+ else:
634
+ logger.info(f"🎯 Initializing kuzu-memory database for project: {current_dir}")
635
+
636
+ # Initialize the database in current project directory
637
+ import subprocess
638
+ proc = subprocess.run(
639
+ [kuzu_memory_cmd, "init"],
640
+ capture_output=True,
641
+ text=True,
642
+ timeout=30,
643
+ cwd=str(current_dir),
644
+ )
645
+
646
+ if proc.returncode == 0:
647
+ logger.info("✅ Kuzu-memory database initialized successfully")
648
+ else:
649
+ logger.warning(f"⚠️ Kuzu-memory initialization failed: {proc.stderr}")
650
+
651
+ except Exception as e:
652
+ logger.debug(f"Kuzu-memory auto-initialization error (non-critical): {e}")
653
+
654
+
380
655
  async def pre_warm_mcp_servers():
381
656
  """Pre-warm MCP servers from configuration."""
657
+ # Auto-initialize vector search for current project
658
+ await auto_initialize_vector_search()
659
+
660
+ # Auto-initialize kuzu-memory for persistent knowledge
661
+ await auto_initialize_kuzu_memory()
662
+
382
663
  pool = get_process_pool()
383
664
 
384
665
  # Load MCP configurations
@@ -45,7 +45,7 @@ class MCPGatewayStartupVerifier:
45
45
  "system_info", # System diagnostics
46
46
  "health_check", # Health diagnostics
47
47
  "document_summarizer", # File summarizer
48
- "ticket", # Ticket service (unified)
48
+ # Ticket functionality now provided by mcp-ticketer
49
49
  ]
50
50
 
51
51
  async def verify_and_configure(self) -> Dict[str, Any]:
@@ -210,7 +210,7 @@ class MCPGatewayStartupVerifier:
210
210
  "..tools.document_summarizer",
211
211
  "DocumentSummarizerTool",
212
212
  ),
213
- "ticket": ("..tools.unified_ticket_tool", "UnifiedTicketTool"),
213
+ # Ticket functionality now provided by mcp-ticketer
214
214
  }
215
215
 
216
216
  if tool_name not in tool_map:
@@ -107,13 +107,8 @@ try:
107
107
  except ImportError:
108
108
  DocumentSummarizerTool = None
109
109
 
110
- try:
111
- from claude_mpm.services.mcp_gateway.tools.unified_ticket_tool import (
112
- UnifiedTicketTool,
113
- )
114
- except ImportError:
115
- # Unified ticket tool is optional
116
- UnifiedTicketTool = None
110
+ # Ticket tools removed - using mcp-ticketer instead
111
+ UnifiedTicketTool = None
117
112
 
118
113
  try:
119
114
  from claude_mpm.services.mcp_gateway.tools.external_mcp_services import (
@@ -316,12 +311,7 @@ class MCPGatewayOrchestrator:
316
311
  except Exception as e:
317
312
  self.logger.warning(f"Could not load document summarizer: {e}")
318
313
 
319
- # Optional: Unified ticket management tool
320
- if UnifiedTicketTool is not None:
321
- try:
322
- tools.append(UnifiedTicketTool())
323
- except Exception as e:
324
- self.logger.warning(f"Could not load unified ticket tool: {e}")
314
+ # Ticket tools removed - mcp-ticketer provides ticket functionality
325
315
 
326
316
  if not tools:
327
317
  self.logger.warning("No tools available to register")
@@ -29,15 +29,8 @@ from mcp.types import TextContent, Tool
29
29
  # Import pydantic for model patching
30
30
  from claude_mpm.core.logger import get_logger
31
31
 
32
- # Import unified ticket tool if available
33
- try:
34
- from claude_mpm.services.mcp_gateway.tools.unified_ticket_tool import (
35
- UnifiedTicketTool,
36
- )
37
-
38
- TICKET_TOOLS_AVAILABLE = True
39
- except ImportError:
40
- TICKET_TOOLS_AVAILABLE = False
32
+ # Ticket tools removed - using mcp-ticketer instead
33
+ TICKET_TOOLS_AVAILABLE = False
41
34
 
42
35
 
43
36
  def apply_backward_compatibility_patches():
@@ -629,7 +622,8 @@ class SimpleMCPServer:
629
622
 
630
623
  try:
631
624
  self.logger.info("Initializing unified ticket tool...")
632
- self.unified_ticket_tool = UnifiedTicketTool()
625
+ # Ticket tools removed - using mcp-ticketer instead
626
+ self.unified_ticket_tool = None
633
627
  # If the tool has an async init method, call it
634
628
  if hasattr(self.unified_ticket_tool, "initialize"):
635
629
  await self.unified_ticket_tool.initialize()
@@ -12,7 +12,14 @@ from .base_adapter import (
12
12
  SystemInfoToolAdapter,
13
13
  )
14
14
  from .document_summarizer import DocumentSummarizerTool
15
- from .unified_ticket_tool import UnifiedTicketTool
15
+ from .kuzu_memory_service import (
16
+ KuzuMemoryService,
17
+ store_memory,
18
+ recall_memories,
19
+ search_memories,
20
+ get_context,
21
+ )
22
+ # Ticket tools removed - using mcp-ticketer instead
16
23
 
17
24
  __all__ = [
18
25
  "BaseToolAdapter",
@@ -20,5 +27,9 @@ __all__ = [
20
27
  "DocumentSummarizerTool",
21
28
  "EchoToolAdapter",
22
29
  "SystemInfoToolAdapter",
23
- "UnifiedTicketTool",
30
+ "KuzuMemoryService",
31
+ "store_memory",
32
+ "recall_memories",
33
+ "search_memories",
34
+ "get_context",
24
35
  ]
@@ -16,10 +16,10 @@ import sys
16
16
  from pathlib import Path
17
17
  from typing import Any, Dict, List
18
18
 
19
- from claude_mpm.services.mcp_gateway.tools.base_adapter import BaseMCPToolAdapter
19
+ from claude_mpm.services.mcp_gateway.tools.base_adapter import BaseToolAdapter
20
20
 
21
21
 
22
- class ExternalMCPService(BaseMCPToolAdapter):
22
+ class ExternalMCPService(BaseToolAdapter):
23
23
  """Base class for external MCP service integration."""
24
24
 
25
25
  def __init__(self, service_name: str, package_name: str):
@@ -30,12 +30,40 @@ class ExternalMCPService(BaseMCPToolAdapter):
30
30
  service_name: Name of the service for MCP
31
31
  package_name: Python package name to install/run
32
32
  """
33
- super().__init__()
33
+ # Import here to avoid circular imports
34
+ from claude_mpm.services.mcp_gateway.core.interfaces import MCPToolDefinition
35
+
36
+ # Create a basic tool definition for the service
37
+ tool_def = MCPToolDefinition(
38
+ name=service_name,
39
+ description=f"External MCP service: {package_name}",
40
+ input_schema={
41
+ "type": "object",
42
+ "properties": {},
43
+ "required": [],
44
+ },
45
+ )
46
+ super().__init__(tool_def)
34
47
  self.service_name = service_name
35
48
  self.package_name = package_name
36
49
  self.process = None
37
50
  self._is_installed = False
38
51
 
52
+ async def invoke(self, invocation):
53
+ """
54
+ Invoke method required by BaseToolAdapter interface.
55
+
56
+ This base implementation should be overridden by subclasses.
57
+ """
58
+ # Import here to avoid circular imports
59
+ from claude_mpm.services.mcp_gateway.core.interfaces import MCPToolResult
60
+
61
+ return MCPToolResult(
62
+ success=False,
63
+ error="invoke method not implemented in base ExternalMCPService",
64
+ execution_time=0.0,
65
+ )
66
+
39
67
  async def initialize(self) -> bool:
40
68
  """Initialize the external service."""
41
69
  try:
@@ -43,8 +71,8 @@ class ExternalMCPService(BaseMCPToolAdapter):
43
71
  self._is_installed = await self._check_installation()
44
72
 
45
73
  if not self._is_installed:
46
- self.logger.warning(
47
- f"{self.package_name} not installed, attempting installation..."
74
+ self.logger.debug(
75
+ f"{self.package_name} not installed - will attempt automatic installation if needed"
48
76
  )
49
77
  await self._install_package()
50
78
  self._is_installed = await self._check_installation()
@@ -389,6 +417,8 @@ class ExternalMCPServiceManager:
389
417
  them as tools in the gateway - they run as separate MCP servers.
390
418
  """
391
419
  # Create service instances
420
+ # Note: kuzu-memory is configured via MCPConfigManager and runs as a separate MCP server
421
+ # It doesn't need to be included here since it's already set up through the MCP config
392
422
  services = [MCPVectorSearchService(), MCPBrowserService()]
393
423
 
394
424
  # Initialize each service
@@ -402,7 +432,7 @@ class ExternalMCPServiceManager:
402
432
  f"Initialized external service: {service.service_name}"
403
433
  )
404
434
  elif self.logger:
405
- self.logger.warning(f"Failed to initialize: {service.service_name}")
435
+ self.logger.debug(f"Service not available (optional): {service.service_name}")
406
436
  except Exception as e:
407
437
  if self.logger:
408
438
  self.logger.error(f"Error initializing {service.service_name}: {e}")