claude-mpm 4.4.0__py3-none-any.whl → 4.4.4__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 (129) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/WORKFLOW.md +2 -14
  3. claude_mpm/agents/agent_loader.py +3 -2
  4. claude_mpm/agents/agent_loader_integration.py +2 -1
  5. claude_mpm/agents/async_agent_loader.py +2 -2
  6. claude_mpm/agents/base_agent_loader.py +2 -2
  7. claude_mpm/agents/frontmatter_validator.py +1 -0
  8. claude_mpm/agents/system_agent_config.py +2 -1
  9. claude_mpm/cli/commands/configure.py +2 -29
  10. claude_mpm/cli/commands/doctor.py +44 -5
  11. claude_mpm/cli/commands/mpm_init.py +117 -63
  12. claude_mpm/cli/parsers/configure_parser.py +6 -15
  13. claude_mpm/cli/startup_logging.py +1 -3
  14. claude_mpm/config/agent_config.py +1 -1
  15. claude_mpm/config/paths.py +2 -1
  16. claude_mpm/core/agent_name_normalizer.py +1 -0
  17. claude_mpm/core/config.py +2 -1
  18. claude_mpm/core/config_aliases.py +2 -1
  19. claude_mpm/core/file_utils.py +0 -1
  20. claude_mpm/core/framework/__init__.py +38 -0
  21. claude_mpm/core/framework/formatters/__init__.py +11 -0
  22. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  23. claude_mpm/core/framework/formatters/content_formatter.py +288 -0
  24. claude_mpm/core/framework/formatters/context_generator.py +184 -0
  25. claude_mpm/core/framework/loaders/__init__.py +13 -0
  26. claude_mpm/core/framework/loaders/agent_loader.py +206 -0
  27. claude_mpm/core/framework/loaders/file_loader.py +223 -0
  28. claude_mpm/core/framework/loaders/instruction_loader.py +161 -0
  29. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  30. claude_mpm/core/framework/processors/__init__.py +11 -0
  31. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  32. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  33. claude_mpm/core/framework/processors/template_processor.py +244 -0
  34. claude_mpm/core/framework_loader.py +298 -1795
  35. claude_mpm/core/log_manager.py +2 -1
  36. claude_mpm/core/tool_access_control.py +1 -0
  37. claude_mpm/core/unified_agent_registry.py +2 -1
  38. claude_mpm/core/unified_paths.py +1 -0
  39. claude_mpm/experimental/cli_enhancements.py +1 -0
  40. claude_mpm/hooks/__init__.py +9 -1
  41. claude_mpm/hooks/base_hook.py +1 -0
  42. claude_mpm/hooks/instruction_reinforcement.py +1 -0
  43. claude_mpm/hooks/kuzu_memory_hook.py +359 -0
  44. claude_mpm/hooks/validation_hooks.py +1 -1
  45. claude_mpm/scripts/mpm_doctor.py +1 -0
  46. claude_mpm/services/agents/loading/agent_profile_loader.py +1 -1
  47. claude_mpm/services/agents/loading/base_agent_manager.py +1 -1
  48. claude_mpm/services/agents/loading/framework_agent_loader.py +1 -1
  49. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -0
  50. claude_mpm/services/agents/management/agent_management_service.py +1 -1
  51. claude_mpm/services/agents/memory/memory_categorization_service.py +0 -1
  52. claude_mpm/services/agents/memory/memory_file_service.py +6 -2
  53. claude_mpm/services/agents/memory/memory_format_service.py +0 -1
  54. claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
  55. claude_mpm/services/async_session_logger.py +1 -1
  56. claude_mpm/services/claude_session_logger.py +1 -0
  57. claude_mpm/services/core/path_resolver.py +2 -0
  58. claude_mpm/services/diagnostics/checks/__init__.py +2 -0
  59. claude_mpm/services/diagnostics/checks/installation_check.py +126 -25
  60. claude_mpm/services/diagnostics/checks/mcp_services_check.py +399 -0
  61. claude_mpm/services/diagnostics/diagnostic_runner.py +4 -0
  62. claude_mpm/services/diagnostics/doctor_reporter.py +259 -32
  63. claude_mpm/services/event_bus/direct_relay.py +2 -1
  64. claude_mpm/services/event_bus/event_bus.py +1 -0
  65. claude_mpm/services/event_bus/relay.py +3 -2
  66. claude_mpm/services/framework_claude_md_generator/content_assembler.py +1 -1
  67. claude_mpm/services/infrastructure/daemon_manager.py +1 -1
  68. claude_mpm/services/mcp_config_manager.py +67 -4
  69. claude_mpm/services/mcp_gateway/core/process_pool.py +320 -0
  70. claude_mpm/services/mcp_gateway/core/startup_verification.py +2 -2
  71. claude_mpm/services/mcp_gateway/main.py +3 -13
  72. claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -10
  73. claude_mpm/services/mcp_gateway/tools/__init__.py +14 -2
  74. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +38 -6
  75. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +527 -0
  76. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  77. claude_mpm/services/project/archive_manager.py +159 -96
  78. claude_mpm/services/project/documentation_manager.py +64 -45
  79. claude_mpm/services/project/enhanced_analyzer.py +132 -89
  80. claude_mpm/services/project/project_organizer.py +225 -131
  81. claude_mpm/services/response_tracker.py +1 -1
  82. claude_mpm/services/shared/__init__.py +2 -1
  83. claude_mpm/services/shared/service_factory.py +8 -5
  84. claude_mpm/services/socketio/server/eventbus_integration.py +1 -1
  85. claude_mpm/services/unified/__init__.py +1 -1
  86. claude_mpm/services/unified/analyzer_strategies/__init__.py +3 -3
  87. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +97 -53
  88. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +81 -40
  89. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +277 -178
  90. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +196 -112
  91. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +83 -49
  92. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  93. claude_mpm/services/unified/config_strategies/config_schema.py +735 -0
  94. claude_mpm/services/unified/config_strategies/context_strategy.py +750 -0
  95. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1009 -0
  96. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +879 -0
  97. claude_mpm/services/unified/config_strategies/unified_config_service.py +814 -0
  98. claude_mpm/services/unified/config_strategies/validation_strategy.py +1144 -0
  99. claude_mpm/services/unified/deployment_strategies/__init__.py +7 -7
  100. claude_mpm/services/unified/deployment_strategies/base.py +24 -28
  101. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +168 -88
  102. claude_mpm/services/unified/deployment_strategies/local.py +49 -34
  103. claude_mpm/services/unified/deployment_strategies/utils.py +39 -43
  104. claude_mpm/services/unified/deployment_strategies/vercel.py +30 -24
  105. claude_mpm/services/unified/interfaces.py +0 -26
  106. claude_mpm/services/unified/migration.py +17 -40
  107. claude_mpm/services/unified/strategies.py +9 -26
  108. claude_mpm/services/unified/unified_analyzer.py +48 -44
  109. claude_mpm/services/unified/unified_config.py +21 -19
  110. claude_mpm/services/unified/unified_deployment.py +21 -26
  111. claude_mpm/storage/state_storage.py +1 -0
  112. claude_mpm/utils/agent_dependency_loader.py +18 -6
  113. claude_mpm/utils/common.py +14 -12
  114. claude_mpm/utils/database_connector.py +15 -12
  115. claude_mpm/utils/error_handler.py +1 -0
  116. claude_mpm/utils/log_cleanup.py +1 -0
  117. claude_mpm/utils/path_operations.py +1 -0
  118. claude_mpm/utils/session_logging.py +1 -1
  119. claude_mpm/utils/subprocess_utils.py +1 -0
  120. claude_mpm/validation/agent_validator.py +1 -1
  121. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/METADATA +23 -17
  122. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/RECORD +126 -105
  123. claude_mpm/cli/commands/configure_tui.py +0 -1927
  124. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
  125. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
  126. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/WHEEL +0 -0
  127. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/entry_points.txt +0 -0
  128. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/licenses/LICENSE +0 -0
  129. {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/top_level.txt +0 -0
@@ -242,40 +242,74 @@ class DoctorReporter:
242
242
  print(json.dumps(output, indent=2))
243
243
 
244
244
  def _report_markdown(self, summary: DiagnosticSummary):
245
- """Generate Markdown-formatted report."""
246
- print("# Claude MPM Doctor Report\n")
247
-
248
- # Summary table
249
- print("## Summary\n")
250
- print("| Status | Count |")
251
- print("|--------|-------|")
252
- print(f"| ✅ OK | {summary.ok_count} |")
253
- print(f"| ⚠️ Warning | {summary.warning_count} |")
254
- print(f"| ❌ Error | {summary.error_count} |")
255
- print(f"| ⏭️ Skipped | {summary.skipped_count} |")
245
+ """Generate comprehensive Markdown-formatted report."""
246
+ import datetime
247
+
248
+ # Header with timestamp
249
+ print("# Claude MPM Doctor Report")
250
+ print(
251
+ f"\n**Generated:** {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
252
+ )
253
+ print(f"**Version:** {self._get_version()}\n")
254
+ print("---\n")
255
+
256
+ # System Overview
257
+ print("## System Overview\n")
258
+ self._print_system_overview_markdown(summary)
256
259
  print()
257
260
 
258
- # Detailed results
259
- print("## Diagnostic Results\n")
261
+ # Summary Statistics
262
+ print("## Summary Statistics\n")
263
+ print("| Status | Count | Percentage |")
264
+ print("|--------|-------|------------|")
265
+ total = (
266
+ summary.ok_count
267
+ + summary.warning_count
268
+ + summary.error_count
269
+ + summary.skipped_count
270
+ )
271
+ if total > 0:
272
+ print(f"| ✅ OK | {summary.ok_count} | {summary.ok_count*100//total}% |")
273
+ print(
274
+ f"| ⚠️ Warning | {summary.warning_count} | {summary.warning_count*100//total}% |"
275
+ )
276
+ print(
277
+ f"| ❌ Error | {summary.error_count} | {summary.error_count*100//total}% |"
278
+ )
279
+ print(
280
+ f"| ⏭️ Skipped | {summary.skipped_count} | {summary.skipped_count*100//total}% |"
281
+ )
282
+ print()
283
+
284
+ # Overall Health Status
285
+ overall = summary.overall_status
286
+ if overall == DiagnosticStatus.OK:
287
+ print("### 🎉 Overall Status: **Healthy**")
288
+ print("Your Claude MPM installation is functioning properly.\n")
289
+ elif overall == DiagnosticStatus.WARNING:
290
+ print("### ⚠️ Overall Status: **Needs Attention**")
291
+ print("Your installation has minor issues that should be addressed.\n")
292
+ else:
293
+ print("### ❌ Overall Status: **Critical Issues**")
294
+ print(
295
+ "Your installation has critical issues that need immediate attention.\n"
296
+ )
297
+
298
+ # MCP Services Status (if available)
299
+ self._print_mcp_services_markdown(summary)
260
300
 
301
+ # Installation Details
302
+ self._print_installation_details_markdown(summary)
303
+
304
+ # Detailed Diagnostic Results
305
+ print("## Detailed Diagnostic Results\n")
261
306
  for result in summary.results:
262
- symbol = self.STATUS_SYMBOLS.get(result.status, "?")
263
- print(f"### {symbol} {result.category}\n")
264
- print(f"**Status:** {result.status.value}")
265
- print(f"**Message:** {result.message}\n")
266
-
267
- if result.fix_command:
268
- print(f"**Fix:** `{result.fix_command}`")
269
- if result.fix_description:
270
- print(f"_{result.fix_description}_\n")
271
-
272
- if self.verbose and result.details:
273
- print("**Details:**")
274
- for key, value in result.details.items():
275
- print(f"- {key}: {value}")
276
- print()
307
+ self._print_result_markdown(result)
277
308
 
278
- # Fixes section
309
+ # Recommendations Section
310
+ self._print_recommendations_markdown(summary)
311
+
312
+ # Fixes Section
279
313
  fixes = [
280
314
  (r.category, r.fix_command, r.fix_description)
281
315
  for r in summary.results
@@ -283,13 +317,24 @@ class DoctorReporter:
283
317
  ]
284
318
 
285
319
  if fixes:
286
- print("## Suggested Fixes\n")
320
+ print("## 🔧 Suggested Fixes\n")
321
+ print("Run these commands to fix identified issues:\n")
322
+ print("```bash")
287
323
  for category, command, description in fixes:
288
- print(f"- **{category}:** `{command}`")
324
+ print(f"# Fix: {category}")
289
325
  if description:
290
- print(f" - {description}")
326
+ print(f"# {description}")
327
+ print(command)
328
+ print()
329
+ print("```")
291
330
  print()
292
331
 
332
+ # Footer
333
+ print("---")
334
+ print(
335
+ "\n*For more information, run `claude-mpm doctor --verbose` or visit the [documentation](https://github.com/bobmatnyc/claude-mpm).*"
336
+ )
337
+
293
338
  def _color(self, text: str, color: str) -> str:
294
339
  """Apply color to text if colors are enabled."""
295
340
  if not self.use_color:
@@ -318,3 +363,185 @@ class DoctorReporter:
318
363
  return service.get_version()
319
364
  except Exception:
320
365
  return "unknown"
366
+
367
+ def _print_system_overview_markdown(self, summary: DiagnosticSummary):
368
+ """Print system overview in markdown format."""
369
+ import platform
370
+ import sys
371
+
372
+ print("| Component | Value |")
373
+ print("|-----------|-------|")
374
+ print(f"| Platform | {platform.system()} {platform.release()} |")
375
+ print(f"| Python Version | {sys.version.split()[0]} |")
376
+
377
+ # Extract key details from results
378
+ for result in summary.results:
379
+ if result.category == "Installation":
380
+ if result.details.get("claude_mpm_version"):
381
+ print(
382
+ f"| Claude MPM Version | {result.details['claude_mpm_version']} |"
383
+ )
384
+ if result.details.get("installation_method"):
385
+ print(
386
+ f"| Installation Method | {result.details['installation_method']} |"
387
+ )
388
+ elif result.category == "Claude Desktop":
389
+ if result.details.get("version"):
390
+ print(f"| Claude Desktop | {result.details['version']} |")
391
+
392
+ def _print_mcp_services_markdown(self, summary: DiagnosticSummary):
393
+ """Print MCP services status table in markdown."""
394
+ # Find MCP Services result
395
+ mcp_services_result = None
396
+ for result in summary.results:
397
+ if result.category == "MCP Services":
398
+ mcp_services_result = result
399
+ break
400
+
401
+ if not mcp_services_result or not mcp_services_result.details.get("services"):
402
+ return
403
+
404
+ print("## MCP Services Status\n")
405
+ print("| Service | Installed | Accessible | Version | Status |")
406
+ print("|---------|-----------|------------|---------|--------|")
407
+
408
+ services = mcp_services_result.details.get("services", {})
409
+ for service_name, service_info in services.items():
410
+ installed = "✅" if service_info.get("installed") else "❌"
411
+ accessible = "✅" if service_info.get("accessible") else "❌"
412
+ version = service_info.get("version")
413
+ if version:
414
+ version = str(version)[:20] # Truncate long versions
415
+ else:
416
+ version = "N/A"
417
+ status = service_info.get("status", "unknown")
418
+
419
+ # Map status to emoji
420
+ if status == "ok":
421
+ status_emoji = "✅"
422
+ elif status == "warning":
423
+ status_emoji = "⚠️"
424
+ elif status == "error":
425
+ status_emoji = "❌"
426
+ else:
427
+ status_emoji = "❓"
428
+
429
+ print(
430
+ f"| {service_name} | {installed} | {accessible} | {version} | {status_emoji} |"
431
+ )
432
+ print()
433
+
434
+ def _print_installation_details_markdown(self, summary: DiagnosticSummary):
435
+ """Print installation details in markdown."""
436
+ # Find installation result
437
+ install_result = None
438
+ for result in summary.results:
439
+ if result.category == "Installation":
440
+ install_result = result
441
+ break
442
+
443
+ if not install_result:
444
+ return
445
+
446
+ print("## Installation Details\n")
447
+
448
+ # Print sub-results if available
449
+ if install_result.sub_results and self.verbose:
450
+ for sub in install_result.sub_results:
451
+ if sub.category == "Python Version":
452
+ print("### Python Environment")
453
+ print(f"- **Version:** {sub.message}")
454
+ elif sub.category == "Installation Method":
455
+ print("### Installation Method")
456
+ print(f"- **Method:** {sub.message}")
457
+ if sub.details.get("container_type"):
458
+ print(f"- **Container:** {sub.details['container_type']}")
459
+ if sub.details.get("pipx_metadata"):
460
+ metadata = sub.details["pipx_metadata"]
461
+ if metadata.get("version"):
462
+ print(f"- **Pipx Version:** {metadata['version']}")
463
+ elif sub.category == "Dependencies":
464
+ print("### Dependencies")
465
+ print(f"- **Status:** {sub.message}")
466
+ if sub.details.get("installed"):
467
+ print(
468
+ f"- **Installed Packages:** {len(sub.details['installed'])}"
469
+ )
470
+ print()
471
+
472
+ def _print_result_markdown(self, result: DiagnosticResult):
473
+ """Print a single result in markdown format."""
474
+ symbol = self.STATUS_SYMBOLS.get(result.status, "?")
475
+ print(f"### {symbol} {result.category}\n")
476
+
477
+ # Status badge
478
+ status_badge = {
479
+ DiagnosticStatus.OK: "![OK](https://img.shields.io/badge/status-OK-green)",
480
+ DiagnosticStatus.WARNING: "![Warning](https://img.shields.io/badge/status-Warning-yellow)",
481
+ DiagnosticStatus.ERROR: "![Error](https://img.shields.io/badge/status-Error-red)",
482
+ DiagnosticStatus.SKIPPED: "![Skipped](https://img.shields.io/badge/status-Skipped-gray)",
483
+ }.get(result.status, "")
484
+
485
+ print(f"{status_badge}")
486
+ print(f"\n**Message:** {result.message}\n")
487
+
488
+ if result.fix_command:
489
+ print("**Fix Available:**")
490
+ print("```bash")
491
+ print(result.fix_command)
492
+ print("```")
493
+ if result.fix_description:
494
+ print(f"*{result.fix_description}*\n")
495
+
496
+ if self.verbose and result.details:
497
+ print("<details>")
498
+ print("<summary>Details</summary>\n")
499
+ print("```json")
500
+ import json
501
+
502
+ print(json.dumps(result.details, indent=2, default=str))
503
+ print("```")
504
+ print("</details>\n")
505
+
506
+ def _print_recommendations_markdown(self, summary: DiagnosticSummary):
507
+ """Print recommendations based on diagnostic results."""
508
+ recommendations = []
509
+
510
+ # Analyze results for recommendations
511
+ has_errors = summary.error_count > 0
512
+ has_warnings = summary.warning_count > 0
513
+
514
+ # Check specific conditions
515
+ for result in summary.results:
516
+ if (
517
+ result.category == "Installation"
518
+ and result.status != DiagnosticStatus.OK
519
+ ):
520
+ if "pipx" not in str(result.details.get("installation_method", "")):
521
+ recommendations.append(
522
+ "Consider using pipx for isolated installation: `pipx install claude-mpm`"
523
+ )
524
+
525
+ if result.category == "MCP Services":
526
+ services = result.details.get("services", {})
527
+ missing = [
528
+ s for s, info in services.items() if not info.get("installed")
529
+ ]
530
+ if missing:
531
+ recommendations.append(
532
+ f"Install missing MCP services for enhanced features: {', '.join(missing)}"
533
+ )
534
+
535
+ if (
536
+ result.category == "Claude Desktop"
537
+ and result.status == DiagnosticStatus.WARNING
538
+ ):
539
+ recommendations.append(
540
+ "Update Claude Desktop to the latest version for best compatibility"
541
+ )
542
+
543
+ if recommendations:
544
+ print("## 📋 Recommendations\n")
545
+ for i, rec in enumerate(recommendations, 1):
546
+ print(f"{i}. {rec}")
547
+ print()
@@ -18,9 +18,10 @@ import logging
18
18
  from datetime import datetime, timezone
19
19
  from typing import Any
20
20
 
21
+ from claude_mpm.core.logging_utils import get_logger
22
+
21
23
  from .event_bus import EventBus
22
24
 
23
- from claude_mpm.core.logging_utils import get_logger
24
25
  logger = get_logger(__name__)
25
26
 
26
27
 
@@ -18,6 +18,7 @@ from pyee.asyncio import AsyncIOEventEmitter
18
18
 
19
19
  # Configure logger
20
20
  from claude_mpm.core.logging_utils import get_logger
21
+
21
22
  logger = get_logger(__name__)
22
23
 
23
24
 
@@ -24,10 +24,11 @@ except ImportError:
24
24
 
25
25
  import contextlib
26
26
 
27
- from .event_bus import EventBus
28
-
29
27
  # Configure logger
30
28
  from claude_mpm.core.logging_utils import get_logger
29
+
30
+ from .event_bus import EventBus
31
+
31
32
  logger = get_logger(__name__)
32
33
 
33
34
 
@@ -9,10 +9,10 @@ from collections import OrderedDict
9
9
  from datetime import datetime, timezone
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.agents.management import AgentCapabilitiesGenerator
13
14
  from claude_mpm.services.agents.registry import DeployedAgentDiscovery
14
15
 
15
- from claude_mpm.core.logging_utils import get_logger
16
16
  logger = get_logger(__name__)
17
17
 
18
18
 
@@ -31,9 +31,9 @@ except ImportError:
31
31
  import psutil
32
32
 
33
33
  # from claude_mpm.core.base_service import BaseService
34
+ from claude_mpm.core.logging_utils import get_logger
34
35
  from claude_mpm.services.socketio.server.main import SocketIOServer
35
36
 
36
- from claude_mpm.core.logging_utils import get_logger
37
37
  logger = get_logger(__name__)
38
38
 
39
39
 
@@ -37,6 +37,7 @@ class MCPConfigManager:
37
37
  "mcp-vector-search",
38
38
  "mcp-browser",
39
39
  "mcp-ticketer",
40
+ "kuzu-memory",
40
41
  }
41
42
 
42
43
  def __init__(self):
@@ -53,9 +54,10 @@ class MCPConfigManager:
53
54
  Detect the best path for an MCP service.
54
55
 
55
56
  Priority order:
56
- 1. Pipx installation (preferred)
57
- 2. System PATH (likely from pipx)
58
- 3. Local venv (fallback)
57
+ 1. For kuzu-memory: prefer v1.1.0+ with MCP support
58
+ 2. Pipx installation (preferred)
59
+ 3. System PATH (likely from pipx or homebrew)
60
+ 4. Local venv (fallback)
59
61
 
60
62
  Args:
61
63
  service_name: Name of the MCP service
@@ -63,6 +65,46 @@ class MCPConfigManager:
63
65
  Returns:
64
66
  Path to the service executable or None if not found
65
67
  """
68
+ # Special handling for kuzu-memory - prefer v1.1.0+ with MCP support
69
+ if service_name == "kuzu-memory":
70
+ candidates = []
71
+
72
+ # Check pipx installation
73
+ pipx_path = self._check_pipx_installation(service_name)
74
+ if pipx_path:
75
+ candidates.append(pipx_path)
76
+
77
+ # Check system PATH (including homebrew)
78
+ import shutil
79
+
80
+ system_path = shutil.which(service_name)
81
+ if system_path and system_path not in candidates:
82
+ candidates.append(system_path)
83
+
84
+ # Choose the best candidate (prefer v1.1.0+ with MCP support)
85
+ for path in candidates:
86
+ try:
87
+ result = subprocess.run(
88
+ [path, "--help"], capture_output=True, text=True, timeout=5, check=False
89
+ )
90
+ # Check if this version has MCP support
91
+ if "claude" in result.stdout or "mcp" in result.stdout:
92
+ self.logger.debug(
93
+ f"Found kuzu-memory with MCP support at {path}"
94
+ )
95
+ return path
96
+ except:
97
+ pass
98
+
99
+ # If no MCP-capable version found, log warning but return None
100
+ if candidates:
101
+ self.logger.warning(
102
+ f"Found kuzu-memory at {candidates[0]} but it lacks MCP support. "
103
+ f"Upgrade to v1.1.0+ for MCP integration: pipx upgrade kuzu-memory"
104
+ )
105
+ return None # Don't configure MCP for incompatible versions
106
+
107
+ # Standard detection for other services
66
108
  # Check pipx installation first
67
109
  pipx_path = self._check_pipx_installation(service_name)
68
110
  if pipx_path:
@@ -83,7 +125,9 @@ class MCPConfigManager:
83
125
  )
84
126
  return local_path
85
127
 
86
- self.logger.warning(f"Service {service_name} not found")
128
+ self.logger.debug(
129
+ f"Service {service_name} not found - will auto-install when needed"
130
+ )
87
131
  return None
88
132
 
89
133
  def _check_pipx_installation(self, service_name: str) -> Optional[str]:
@@ -178,6 +222,25 @@ class MCPConfigManager:
178
222
  config["env"] = {"MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")}
179
223
  elif service_name == "mcp-ticketer":
180
224
  config["args"] = ["mcp"]
225
+ elif service_name == "kuzu-memory":
226
+ # Check kuzu-memory version to determine correct command
227
+ # v1.1.0+ has "claude mcp-server", v1.0.0 has "serve"
228
+ import subprocess
229
+
230
+ try:
231
+ result = subprocess.run(
232
+ [service_path, "--help"], capture_output=True, text=True, timeout=10, check=False
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
181
244
  else:
182
245
  # Generic config for unknown services
183
246
  config["args"] = []