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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/WORKFLOW.md +2 -14
- claude_mpm/agents/agent_loader.py +3 -2
- claude_mpm/agents/agent_loader_integration.py +2 -1
- claude_mpm/agents/async_agent_loader.py +2 -2
- claude_mpm/agents/base_agent_loader.py +2 -2
- claude_mpm/agents/frontmatter_validator.py +1 -0
- claude_mpm/agents/system_agent_config.py +2 -1
- claude_mpm/cli/commands/configure.py +2 -29
- claude_mpm/cli/commands/doctor.py +44 -5
- claude_mpm/cli/commands/mpm_init.py +117 -63
- claude_mpm/cli/parsers/configure_parser.py +6 -15
- claude_mpm/cli/startup_logging.py +1 -3
- claude_mpm/config/agent_config.py +1 -1
- claude_mpm/config/paths.py +2 -1
- claude_mpm/core/agent_name_normalizer.py +1 -0
- claude_mpm/core/config.py +2 -1
- claude_mpm/core/config_aliases.py +2 -1
- claude_mpm/core/file_utils.py +0 -1
- claude_mpm/core/framework/__init__.py +38 -0
- claude_mpm/core/framework/formatters/__init__.py +11 -0
- claude_mpm/core/framework/formatters/capability_generator.py +367 -0
- claude_mpm/core/framework/formatters/content_formatter.py +288 -0
- claude_mpm/core/framework/formatters/context_generator.py +184 -0
- claude_mpm/core/framework/loaders/__init__.py +13 -0
- claude_mpm/core/framework/loaders/agent_loader.py +206 -0
- claude_mpm/core/framework/loaders/file_loader.py +223 -0
- claude_mpm/core/framework/loaders/instruction_loader.py +161 -0
- claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
- claude_mpm/core/framework/processors/__init__.py +11 -0
- claude_mpm/core/framework/processors/memory_processor.py +230 -0
- claude_mpm/core/framework/processors/metadata_processor.py +146 -0
- claude_mpm/core/framework/processors/template_processor.py +244 -0
- claude_mpm/core/framework_loader.py +298 -1795
- claude_mpm/core/log_manager.py +2 -1
- claude_mpm/core/tool_access_control.py +1 -0
- claude_mpm/core/unified_agent_registry.py +2 -1
- claude_mpm/core/unified_paths.py +1 -0
- claude_mpm/experimental/cli_enhancements.py +1 -0
- claude_mpm/hooks/__init__.py +9 -1
- claude_mpm/hooks/base_hook.py +1 -0
- claude_mpm/hooks/instruction_reinforcement.py +1 -0
- claude_mpm/hooks/kuzu_memory_hook.py +359 -0
- claude_mpm/hooks/validation_hooks.py +1 -1
- claude_mpm/scripts/mpm_doctor.py +1 -0
- claude_mpm/services/agents/loading/agent_profile_loader.py +1 -1
- claude_mpm/services/agents/loading/base_agent_manager.py +1 -1
- claude_mpm/services/agents/loading/framework_agent_loader.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -0
- claude_mpm/services/agents/management/agent_management_service.py +1 -1
- claude_mpm/services/agents/memory/memory_categorization_service.py +0 -1
- claude_mpm/services/agents/memory/memory_file_service.py +6 -2
- claude_mpm/services/agents/memory/memory_format_service.py +0 -1
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
- claude_mpm/services/async_session_logger.py +1 -1
- claude_mpm/services/claude_session_logger.py +1 -0
- claude_mpm/services/core/path_resolver.py +2 -0
- claude_mpm/services/diagnostics/checks/__init__.py +2 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +126 -25
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +399 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +4 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +259 -32
- claude_mpm/services/event_bus/direct_relay.py +2 -1
- claude_mpm/services/event_bus/event_bus.py +1 -0
- claude_mpm/services/event_bus/relay.py +3 -2
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +1 -1
- claude_mpm/services/infrastructure/daemon_manager.py +1 -1
- claude_mpm/services/mcp_config_manager.py +67 -4
- claude_mpm/services/mcp_gateway/core/process_pool.py +320 -0
- claude_mpm/services/mcp_gateway/core/startup_verification.py +2 -2
- claude_mpm/services/mcp_gateway/main.py +3 -13
- claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -10
- claude_mpm/services/mcp_gateway/tools/__init__.py +14 -2
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +38 -6
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +527 -0
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/project/archive_manager.py +159 -96
- claude_mpm/services/project/documentation_manager.py +64 -45
- claude_mpm/services/project/enhanced_analyzer.py +132 -89
- claude_mpm/services/project/project_organizer.py +225 -131
- claude_mpm/services/response_tracker.py +1 -1
- claude_mpm/services/shared/__init__.py +2 -1
- claude_mpm/services/shared/service_factory.py +8 -5
- claude_mpm/services/socketio/server/eventbus_integration.py +1 -1
- claude_mpm/services/unified/__init__.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/__init__.py +3 -3
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +97 -53
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +81 -40
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +277 -178
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +196 -112
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +83 -49
- claude_mpm/services/unified/config_strategies/__init__.py +175 -0
- claude_mpm/services/unified/config_strategies/config_schema.py +735 -0
- claude_mpm/services/unified/config_strategies/context_strategy.py +750 -0
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1009 -0
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +879 -0
- claude_mpm/services/unified/config_strategies/unified_config_service.py +814 -0
- claude_mpm/services/unified/config_strategies/validation_strategy.py +1144 -0
- claude_mpm/services/unified/deployment_strategies/__init__.py +7 -7
- claude_mpm/services/unified/deployment_strategies/base.py +24 -28
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +168 -88
- claude_mpm/services/unified/deployment_strategies/local.py +49 -34
- claude_mpm/services/unified/deployment_strategies/utils.py +39 -43
- claude_mpm/services/unified/deployment_strategies/vercel.py +30 -24
- claude_mpm/services/unified/interfaces.py +0 -26
- claude_mpm/services/unified/migration.py +17 -40
- claude_mpm/services/unified/strategies.py +9 -26
- claude_mpm/services/unified/unified_analyzer.py +48 -44
- claude_mpm/services/unified/unified_config.py +21 -19
- claude_mpm/services/unified/unified_deployment.py +21 -26
- claude_mpm/storage/state_storage.py +1 -0
- claude_mpm/utils/agent_dependency_loader.py +18 -6
- claude_mpm/utils/common.py +14 -12
- claude_mpm/utils/database_connector.py +15 -12
- claude_mpm/utils/error_handler.py +1 -0
- claude_mpm/utils/log_cleanup.py +1 -0
- claude_mpm/utils/path_operations.py +1 -0
- claude_mpm/utils/session_logging.py +1 -1
- claude_mpm/utils/subprocess_utils.py +1 -0
- claude_mpm/validation/agent_validator.py +1 -1
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/METADATA +23 -17
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/RECORD +126 -105
- claude_mpm/cli/commands/configure_tui.py +0 -1927
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/WHEEL +0 -0
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.4.0.dist-info → claude_mpm-4.4.4.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
247
|
-
|
248
|
-
#
|
249
|
-
print("
|
250
|
-
print(
|
251
|
-
|
252
|
-
|
253
|
-
print(f"
|
254
|
-
print(
|
255
|
-
|
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
|
-
#
|
259
|
-
print("##
|
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
|
-
|
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
|
-
#
|
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"
|
324
|
+
print(f"# Fix: {category}")
|
289
325
|
if description:
|
290
|
-
print(f"
|
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: "",
|
480
|
+
DiagnosticStatus.WARNING: "",
|
481
|
+
DiagnosticStatus.ERROR: "",
|
482
|
+
DiagnosticStatus.SKIPPED: "",
|
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
|
|
@@ -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.
|
57
|
-
2.
|
58
|
-
3.
|
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.
|
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"] = []
|