claude-mpm 4.4.6__py3-none-any.whl → 4.4.8__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 (30) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/templates/local_ops_agent.json +273 -0
  3. claude_mpm/cli/__init__.py +21 -0
  4. claude_mpm/cli/commands/verify.py +118 -0
  5. claude_mpm/cli/parsers/base_parser.py +5 -0
  6. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  7. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  8. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  9. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-313.pyc +0 -0
  10. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  11. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  12. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  13. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  14. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-313.pyc +0 -0
  15. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  16. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  17. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  18. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  19. claude_mpm/scripts/mcp_server.py +0 -0
  20. claude_mpm/scripts/start_activity_logging.py +0 -0
  21. claude_mpm/services/agents/deployment/agent_deployment.py +10 -6
  22. claude_mpm/services/diagnostics/checks/mcp_services_check.py +122 -0
  23. claude_mpm/services/diagnostics/diagnostic_runner.py +3 -0
  24. claude_mpm/services/mcp_service_verifier.py +690 -0
  25. {claude_mpm-4.4.6.dist-info → claude_mpm-4.4.8.dist-info}/METADATA +13 -1
  26. {claude_mpm-4.4.6.dist-info → claude_mpm-4.4.8.dist-info}/RECORD +28 -12
  27. {claude_mpm-4.4.6.dist-info → claude_mpm-4.4.8.dist-info}/WHEEL +0 -0
  28. {claude_mpm-4.4.6.dist-info → claude_mpm-4.4.8.dist-info}/entry_points.txt +0 -0
  29. {claude_mpm-4.4.6.dist-info → claude_mpm-4.4.8.dist-info}/licenses/LICENSE +0 -0
  30. {claude_mpm-4.4.6.dist-info → claude_mpm-4.4.8.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 4.4.6
1
+ 4.4.8
@@ -0,0 +1,273 @@
1
+ {
2
+ "name": "local-ops",
3
+ "display_name": "Local Operations Agent",
4
+ "description": "Specialized agent for managing local development deployments with authority over PM2, Docker, and native processes",
5
+ "version": "1.0.0",
6
+ "author": "Claude MPM",
7
+ "authority": {
8
+ "level": "deployment_manager",
9
+ "domains": [
10
+ "local_deployments",
11
+ "process_management",
12
+ "port_allocation",
13
+ "resource_monitoring",
14
+ "log_management"
15
+ ]
16
+ },
17
+ "capabilities": {
18
+ "frameworks": {
19
+ "javascript": ["next.js", "react", "vue", "angular", "svelte", "nuxt", "gatsby", "vite"],
20
+ "python": ["django", "flask", "fastapi", "streamlit", "gradio"],
21
+ "ruby": ["rails", "sinatra"],
22
+ "php": ["laravel", "symfony"],
23
+ "static": ["hugo", "jekyll", "eleventy"]
24
+ },
25
+ "deployment_methods": {
26
+ "pm2": {
27
+ "description": "Node.js process manager for production deployments",
28
+ "commands": ["start", "stop", "restart", "status", "logs", "monit"],
29
+ "features": ["auto-restart", "clustering", "log-rotation", "monitoring"]
30
+ },
31
+ "docker": {
32
+ "description": "Container-based deployment for isolation",
33
+ "commands": ["build", "run", "stop", "logs", "exec"],
34
+ "features": ["isolation", "reproducibility", "multi-service"]
35
+ },
36
+ "native": {
37
+ "description": "Direct process management for simple cases",
38
+ "commands": ["start", "stop", "status"],
39
+ "features": ["lightweight", "direct-control"]
40
+ },
41
+ "systemd": {
42
+ "description": "Linux system service management",
43
+ "commands": ["start", "stop", "enable", "status"],
44
+ "features": ["boot-persistence", "system-integration"]
45
+ }
46
+ },
47
+ "monitoring": {
48
+ "health_checks": ["http", "tcp", "process"],
49
+ "metrics": ["cpu", "memory", "response_time", "error_rate"],
50
+ "alerts": ["crash", "high_memory", "port_conflict", "unhealthy"]
51
+ }
52
+ },
53
+ "metadata": {
54
+ "category": "operations",
55
+ "tags": ["deployment", "devops", "local", "process-management", "monitoring"],
56
+ "requirements": {
57
+ "optional": ["pm2", "docker", "nginx"],
58
+ "auto_install": ["pm2"]
59
+ }
60
+ },
61
+ "configuration": {
62
+ "default_port_range": [3000, 9999],
63
+ "deployment_directory": ".claude-mpm/deployments",
64
+ "log_directory": ".claude-mpm/logs",
65
+ "state_file": ".claude-mpm/deployment-state.json",
66
+ "health_check_interval": 30,
67
+ "auto_restart_attempts": 3,
68
+ "cleanup_on_exit": false
69
+ },
70
+ "commands": {
71
+ "deploy": {
72
+ "description": "Deploy application with optimal method",
73
+ "examples": [
74
+ "Deploy this Next.js app in production mode",
75
+ "Start the development server with hot reload",
76
+ "Deploy with PM2 for stability"
77
+ ],
78
+ "workflow": [
79
+ "detect_framework",
80
+ "check_existing_deployments",
81
+ "allocate_port",
82
+ "build_if_needed",
83
+ "start_process",
84
+ "monitor_health",
85
+ "report_status"
86
+ ]
87
+ },
88
+ "status": {
89
+ "description": "Check deployment status",
90
+ "provides": ["process_info", "port_mapping", "health_status", "resource_usage"]
91
+ },
92
+ "logs": {
93
+ "description": "Stream or fetch deployment logs",
94
+ "options": ["tail", "follow", "filter", "since"]
95
+ },
96
+ "stop": {
97
+ "description": "Gracefully stop deployments",
98
+ "options": ["force", "timeout", "cleanup"]
99
+ },
100
+ "scale": {
101
+ "description": "Scale deployments (PM2 cluster mode)",
102
+ "options": ["instances", "auto"]
103
+ }
104
+ },
105
+ "detection_patterns": {
106
+ "nextjs": {
107
+ "files": ["next.config.js", "next.config.mjs", "next.config.ts"],
108
+ "package_json": ["next"],
109
+ "commands": {
110
+ "dev": "next dev",
111
+ "build": "next build",
112
+ "start": "next start",
113
+ "export": "next export"
114
+ }
115
+ },
116
+ "react": {
117
+ "files": ["react-scripts", "vite.config.js", "webpack.config.js"],
118
+ "package_json": ["react", "react-dom"],
119
+ "commands": {
120
+ "dev": "npm start",
121
+ "build": "npm run build",
122
+ "serve": "serve -s build"
123
+ }
124
+ },
125
+ "vue": {
126
+ "files": ["vue.config.js", "vite.config.js"],
127
+ "package_json": ["vue", "@vue/cli-service"],
128
+ "commands": {
129
+ "dev": "npm run serve",
130
+ "build": "npm run build",
131
+ "preview": "npm run preview"
132
+ }
133
+ },
134
+ "python_django": {
135
+ "files": ["manage.py", "wsgi.py"],
136
+ "requirements": ["django"],
137
+ "commands": {
138
+ "dev": "python manage.py runserver",
139
+ "prod": "gunicorn wsgi:application"
140
+ }
141
+ },
142
+ "python_flask": {
143
+ "files": ["app.py", "wsgi.py"],
144
+ "requirements": ["flask"],
145
+ "commands": {
146
+ "dev": "flask run",
147
+ "prod": "gunicorn app:app"
148
+ }
149
+ }
150
+ },
151
+ "deployment_strategies": {
152
+ "production": {
153
+ "nextjs": {
154
+ "method": "pm2",
155
+ "steps": [
156
+ "npm install --production",
157
+ "npm run build",
158
+ "pm2 start npm --name '{app_name}' -- start"
159
+ ],
160
+ "health_check": "http://localhost:{port}",
161
+ "environment": {
162
+ "NODE_ENV": "production"
163
+ }
164
+ },
165
+ "react": {
166
+ "method": "static",
167
+ "steps": [
168
+ "npm install",
169
+ "npm run build",
170
+ "pm2 serve build {port} --name '{app_name}'"
171
+ ],
172
+ "health_check": "http://localhost:{port}"
173
+ },
174
+ "python": {
175
+ "method": "pm2",
176
+ "steps": [
177
+ "pip install -r requirements.txt",
178
+ "pm2 start gunicorn --name '{app_name}' -- app:app --bind 0.0.0.0:{port}"
179
+ ],
180
+ "health_check": "http://localhost:{port}/health"
181
+ }
182
+ },
183
+ "development": {
184
+ "nextjs": {
185
+ "method": "pm2",
186
+ "steps": [
187
+ "npm install",
188
+ "pm2 start npm --name '{app_name}-dev' -- run dev"
189
+ ],
190
+ "environment": {
191
+ "NODE_ENV": "development"
192
+ }
193
+ },
194
+ "react": {
195
+ "method": "pm2",
196
+ "steps": [
197
+ "npm install",
198
+ "pm2 start npm --name '{app_name}-dev' -- start"
199
+ ]
200
+ }
201
+ },
202
+ "docker": {
203
+ "default": {
204
+ "method": "docker",
205
+ "steps": [
206
+ "docker build -t {app_name} .",
207
+ "docker run -d -p {port}:{container_port} --name {app_name} {app_name}"
208
+ ],
209
+ "health_check": "docker exec {app_name} echo 'OK'"
210
+ }
211
+ }
212
+ },
213
+ "error_recovery": {
214
+ "port_conflict": {
215
+ "detection": "EADDRINUSE",
216
+ "action": "allocate_next_available_port"
217
+ },
218
+ "build_failure": {
219
+ "detection": "npm ERR!|ERROR|Failed",
220
+ "action": "report_error_and_suggest_fixes"
221
+ },
222
+ "crash_loop": {
223
+ "detection": "restart_count > 5",
224
+ "action": "stop_and_investigate_logs"
225
+ },
226
+ "out_of_memory": {
227
+ "detection": "JavaScript heap out of memory",
228
+ "action": "increase_memory_limit"
229
+ }
230
+ },
231
+ "security": {
232
+ "port_exposure": "localhost_only",
233
+ "process_isolation": "user_level",
234
+ "log_sanitization": true,
235
+ "secrets_handling": "environment_variables"
236
+ },
237
+ "integration": {
238
+ "hooks": {
239
+ "pre_deploy": "validate_requirements",
240
+ "post_deploy": "notify_status",
241
+ "pre_stop": "graceful_shutdown",
242
+ "on_crash": "auto_restart_with_backoff"
243
+ },
244
+ "monitoring": {
245
+ "export_metrics": true,
246
+ "prometheus_endpoint": "/metrics",
247
+ "health_endpoint": "/health"
248
+ }
249
+ },
250
+ "tools": [
251
+ "Bash",
252
+ "Read",
253
+ "Write",
254
+ "Edit"
255
+ ],
256
+ "examples": [
257
+ {
258
+ "user": "Deploy my Next.js app",
259
+ "response": "I'll deploy your Next.js application using PM2 for stability. Let me detect your configuration and set it up...",
260
+ "actions": ["detect_framework", "build_production", "deploy_with_pm2", "monitor_health"]
261
+ },
262
+ {
263
+ "user": "Show me the status of all deployments",
264
+ "response": "Here's the status of all active deployments...",
265
+ "actions": ["list_pm2_processes", "check_docker_containers", "aggregate_status"]
266
+ },
267
+ {
268
+ "user": "The app keeps crashing, help me debug",
269
+ "response": "Let me check the logs and identify the issue...",
270
+ "actions": ["fetch_error_logs", "analyze_crash_pattern", "suggest_fixes"]
271
+ }
272
+ ]
273
+ }
@@ -234,6 +234,19 @@ def _verify_mcp_gateway_startup():
234
234
  DESIGN DECISION: This is non-blocking - failures are logged but don't prevent
235
235
  startup to ensure claude-mpm remains functional even if MCP gateway has issues.
236
236
  """
237
+ # Quick verification of MCP services installation
238
+ try:
239
+ from ..services.mcp_service_verifier import verify_mcp_services_on_startup
240
+ from ..core.logger import get_logger
241
+
242
+ logger = get_logger("mcp_verify")
243
+ all_ok, message = verify_mcp_services_on_startup()
244
+ if not all_ok:
245
+ logger.warning(message)
246
+ except Exception:
247
+ # Non-critical - continue with startup
248
+ pass
249
+
237
250
  try:
238
251
  import asyncio
239
252
  import time
@@ -449,6 +462,14 @@ def _execute_command(command: str, args) -> int:
449
462
  # Convert CommandResult to exit code
450
463
  return result.exit_code if result else 0
451
464
 
465
+ # Handle verify command with lazy import
466
+ if command == "verify":
467
+ # Lazy import to avoid loading unless needed
468
+ from .commands.verify import handle_verify
469
+
470
+ result = handle_verify(args)
471
+ return result if result is not None else 0
472
+
452
473
  # Map stable commands to their implementations
453
474
  command_map = {
454
475
  CLICommands.RUN.value: run_session,
@@ -0,0 +1,118 @@
1
+ """
2
+ Verify command for MCP service health checks.
3
+ """
4
+
5
+ import argparse
6
+ import sys
7
+
8
+ from ...core.logger import get_logger
9
+ from ...services.mcp_service_verifier import MCPServiceVerifier, ServiceStatus
10
+
11
+
12
+ def add_parser(subparsers) -> None:
13
+ """Add the verify command parser."""
14
+ parser = subparsers.add_parser(
15
+ "verify",
16
+ help="Verify MCP services installation and configuration",
17
+ description="Performs comprehensive health checks on MCP services",
18
+ )
19
+
20
+ parser.add_argument(
21
+ "--fix",
22
+ action="store_true",
23
+ help="Attempt to automatically fix detected issues",
24
+ )
25
+
26
+ parser.add_argument(
27
+ "--service",
28
+ type=str,
29
+ help="Verify a specific service only",
30
+ choices=["mcp-vector-search", "mcp-browser", "mcp-ticketer", "kuzu-memory"],
31
+ )
32
+
33
+ parser.add_argument(
34
+ "--json",
35
+ action="store_true",
36
+ help="Output results in JSON format",
37
+ )
38
+
39
+ parser.set_defaults(func=handle_verify)
40
+
41
+
42
+ def handle_verify(args: argparse.Namespace) -> int:
43
+ """
44
+ Handle the verify command.
45
+
46
+ Args:
47
+ args: Parsed command-line arguments
48
+
49
+ Returns:
50
+ Exit code (0 for success, non-zero for issues found)
51
+ """
52
+ logger = get_logger(__name__)
53
+ verifier = MCPServiceVerifier()
54
+
55
+ try:
56
+ # Run verification
57
+ if args.service:
58
+ # Verify single service
59
+ logger.info(f"Verifying {args.service}...")
60
+ diagnostic = verifier._verify_service(args.service)
61
+ diagnostics = {args.service: diagnostic}
62
+
63
+ # Auto-fix if requested
64
+ if args.fix and diagnostic.fix_command and diagnostic.status != ServiceStatus.WORKING:
65
+ logger.info(f"Attempting to fix {args.service}...")
66
+ if verifier._attempt_auto_fix(args.service, diagnostic):
67
+ # Re-verify after fix
68
+ diagnostic = verifier._verify_service(args.service)
69
+ diagnostics = {args.service: diagnostic}
70
+ else:
71
+ # Verify all services
72
+ logger.info("Verifying all MCP services...")
73
+ diagnostics = verifier.verify_all_services(auto_fix=args.fix)
74
+
75
+ # Output results
76
+ if args.json:
77
+ import json
78
+
79
+ # Convert to JSON-serializable format
80
+ json_output = {}
81
+ for name, diag in diagnostics.items():
82
+ json_output[name] = {
83
+ "status": diag.status.value,
84
+ "message": diag.message,
85
+ "installed_path": diag.installed_path,
86
+ "configured_command": diag.configured_command,
87
+ "fix_command": diag.fix_command,
88
+ "details": diag.details,
89
+ }
90
+ print(json.dumps(json_output, indent=2))
91
+ else:
92
+ verifier.print_diagnostics(diagnostics)
93
+
94
+ # Determine exit code
95
+ all_working = all(
96
+ d.status == ServiceStatus.WORKING
97
+ for d in diagnostics.values()
98
+ )
99
+
100
+ if all_working:
101
+ logger.info("✅ All verified services are fully operational")
102
+ return 0
103
+ else:
104
+ issues_count = sum(
105
+ 1 for d in diagnostics.values()
106
+ if d.status != ServiceStatus.WORKING
107
+ )
108
+ logger.warning(f"⚠️ {issues_count} service(s) have issues")
109
+ return 1
110
+
111
+ except Exception as e:
112
+ logger.error(f"Verification failed: {e}")
113
+ if args.json:
114
+ import json
115
+ print(json.dumps({"error": str(e)}, indent=2))
116
+ else:
117
+ print(f"\n❌ Verification failed: {e}")
118
+ return 2
@@ -422,6 +422,11 @@ def create_parser(
422
422
  from ..commands.doctor import add_doctor_parser
423
423
 
424
424
  add_doctor_parser(subparsers)
425
+
426
+ # Add verify command for MCP service verification
427
+ from ..commands.verify import add_parser as add_verify_parser
428
+
429
+ add_verify_parser(subparsers)
425
430
  except ImportError:
426
431
  # Commands module may not be available during testing or refactoring
427
432
  pass
File without changes
File without changes
@@ -369,12 +369,18 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
369
369
  else "single"
370
370
  )
371
371
 
372
+ # When using multi-source deployment, we've already determined which
373
+ # agents need updates. Don't re-check versions in single_agent_deployer.
374
+ # This prevents the issue where multi-source says "deploying 9 agents"
375
+ # but then all get skipped due to redundant version checks.
376
+ skip_version_check = use_multi_source and not force_rebuild
377
+
372
378
  self.single_agent_deployer.deploy_single_agent(
373
379
  template_file=template_file_path,
374
380
  agents_dir=agents_dir,
375
381
  base_agent_data=base_agent_data,
376
382
  base_agent_version=base_agent_version,
377
- force_rebuild=force_rebuild,
383
+ force_rebuild=force_rebuild or skip_version_check,
378
384
  deployment_mode=deployment_mode,
379
385
  results=results,
380
386
  source_info=source_info,
@@ -817,11 +823,9 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
817
823
 
818
824
  agents_to_deploy = filtered_agents
819
825
 
820
- if agents_to_deploy:
821
- self.logger.info(
822
- f"Deploying {len(agents_to_deploy)} agents that need updates"
823
- )
824
- else:
826
+ # Don't log this redundant message - we already logged the upgrades above
827
+ # The "Deploying X agent upgrade(s)" message is sufficient
828
+ if not agents_to_deploy:
825
829
  self.logger.debug(
826
830
  f"All {len(comparison_results.get('up_to_date', []))} agents are up to date"
827
831
  )
@@ -10,6 +10,7 @@ import subprocess
10
10
  from pathlib import Path
11
11
  from typing import Dict, List, Optional, Tuple
12
12
 
13
+ from claude_mpm.core.logger import get_logger
13
14
  from ..models import DiagnosticResult, DiagnosticStatus
14
15
  from .base_check import BaseDiagnosticCheck
15
16
 
@@ -17,6 +18,11 @@ from .base_check import BaseDiagnosticCheck
17
18
  class MCPServicesCheck(BaseDiagnosticCheck):
18
19
  """Check MCP external services installation and health."""
19
20
 
21
+ def __init__(self, verbose: bool = False):
22
+ """Initialize the MCP services check."""
23
+ super().__init__(verbose)
24
+ self.logger = get_logger(self.__class__.__name__)
25
+
20
26
  # Define MCP services to check
21
27
  MCP_SERVICES = {
22
28
  "mcp-vector-search": {
@@ -71,6 +77,11 @@ class MCPServicesCheck(BaseDiagnosticCheck):
71
77
  sub_results = []
72
78
  services_status = {}
73
79
 
80
+ # Check for kuzu-memory configuration issues and offer auto-fix
81
+ kuzu_config_result = self._check_and_fix_kuzu_memory_config()
82
+ if kuzu_config_result:
83
+ sub_results.append(kuzu_config_result)
84
+
74
85
  # Check each MCP service
75
86
  for service_name, service_config in self.MCP_SERVICES.items():
76
87
  service_result = self._check_service(service_name, service_config)
@@ -391,6 +402,117 @@ class MCPServicesCheck(BaseDiagnosticCheck):
391
402
 
392
403
  return None
393
404
 
405
+ def _check_and_fix_kuzu_memory_config(self) -> Optional[DiagnosticResult]:
406
+ """Check for incorrect kuzu-memory configuration in .claude.json and offer auto-fix."""
407
+ claude_config_path = Path.home() / ".claude.json"
408
+
409
+ if not claude_config_path.exists():
410
+ return None
411
+
412
+ try:
413
+ with open(claude_config_path) as f:
414
+ config = json.load(f)
415
+
416
+ mcp_servers = config.get("mcpServers", {})
417
+ kuzu_config = mcp_servers.get("kuzu-memory")
418
+
419
+ if not kuzu_config:
420
+ return None
421
+
422
+ # Check if kuzu-memory has incorrect args
423
+ args = kuzu_config.get("args", [])
424
+ needs_fix = False
425
+ fix_reason = ""
426
+ new_args = None
427
+
428
+ # Check for outdated configurations
429
+ if args == ["claude", "mcp-server"]:
430
+ needs_fix = True
431
+ fix_reason = "Outdated 'claude mcp-server' format"
432
+ new_args = ["mcp", "serve"]
433
+ elif args == ["serve"]:
434
+ needs_fix = True
435
+ fix_reason = "Legacy 'serve' format"
436
+ new_args = ["mcp", "serve"]
437
+ elif args == ["mcp-server"]:
438
+ needs_fix = True
439
+ fix_reason = "Incorrect 'mcp-server' format"
440
+ new_args = ["mcp", "serve"]
441
+
442
+ if needs_fix:
443
+ # Offer to auto-fix
444
+ self.logger.warning(
445
+ f"Found incorrect kuzu-memory configuration: {fix_reason}. "
446
+ f"Current args: {args}"
447
+ )
448
+
449
+ # Auto-fix the configuration
450
+ fixed = self._fix_kuzu_memory_args(claude_config_path, config, new_args)
451
+
452
+ if fixed:
453
+ return DiagnosticResult(
454
+ category="kuzu-memory Configuration Fix",
455
+ status=DiagnosticStatus.OK,
456
+ message="Fixed kuzu-memory configuration",
457
+ details={
458
+ "old_args": args,
459
+ "new_args": new_args,
460
+ "reason": fix_reason,
461
+ "auto_fixed": True,
462
+ },
463
+ )
464
+ else:
465
+ return DiagnosticResult(
466
+ category="kuzu-memory Configuration",
467
+ status=DiagnosticStatus.WARNING,
468
+ message="kuzu-memory has incorrect configuration",
469
+ details={
470
+ "current_args": args,
471
+ "correct_args": new_args,
472
+ "reason": fix_reason,
473
+ "auto_fix_failed": True,
474
+ },
475
+ fix_command="claude-mpm configure --mcp --fix-kuzu",
476
+ fix_description="Fix kuzu-memory configuration manually",
477
+ )
478
+
479
+ # Configuration is correct
480
+ return None
481
+
482
+ except (json.JSONDecodeError, Exception) as e:
483
+ self.logger.debug(f"Could not check kuzu-memory config: {e}")
484
+ return None
485
+
486
+ def _fix_kuzu_memory_args(self, config_path: Path, config: Dict, new_args: List[str]) -> bool:
487
+ """Fix kuzu-memory args in the configuration."""
488
+ try:
489
+ # Save old args before updating
490
+ old_args = config["mcpServers"]["kuzu-memory"].get("args", [])
491
+
492
+ # Create backup
493
+ backup_path = config_path.with_suffix(".json.backup")
494
+ with open(backup_path, "w") as f:
495
+ json.dump(config, f, indent=2)
496
+
497
+ # Update the configuration
498
+ config["mcpServers"]["kuzu-memory"]["args"] = new_args
499
+
500
+ # Write updated configuration
501
+ with open(config_path, "w") as f:
502
+ json.dump(config, f, indent=2)
503
+
504
+ self.logger.info(
505
+ f"✅ Fixed kuzu-memory configuration in {config_path}\n"
506
+ f" Changed args from {old_args} to {new_args}\n"
507
+ f" Backup saved to {backup_path}"
508
+ )
509
+
510
+ return True
511
+
512
+ except Exception as e:
513
+ self.logger.error(f"Failed to fix kuzu-memory configuration: {e}")
514
+ return False
515
+
394
516
  def _check_gateway_configuration(self) -> DiagnosticResult:
395
517
  """Check if MCP services are configured in the gateway."""
396
518
  try:
@@ -214,6 +214,9 @@ class DiagnosticRunner:
214
214
  "agents": AgentCheck,
215
215
  "agent": AgentCheck,
216
216
  "mcp": MCPCheck,
217
+ "mcp_services": MCPServicesCheck,
218
+ "mcp-services": MCPServicesCheck,
219
+ "external": MCPServicesCheck,
217
220
  "monitor": MonitorCheck,
218
221
  "monitoring": MonitorCheck,
219
222
  "common": CommonIssuesCheck,