claude-mpm 4.4.6__py3-none-any.whl → 4.4.7__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 CHANGED
@@ -1 +1 @@
1
- 4.4.6
1
+ 4.4.7
@@ -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
@@ -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
  )
@@ -0,0 +1,690 @@
1
+ """
2
+ MCP Service Verifier
3
+ ====================
4
+
5
+ Comprehensive verification system for MCP services that checks installation,
6
+ configuration, and runtime functionality. Provides detailed diagnostics and
7
+ automated fixes for common issues.
8
+ """
9
+
10
+ import json
11
+ import os
12
+ import shutil
13
+ import subprocess
14
+ import sys
15
+ import time
16
+ from dataclasses import dataclass
17
+ from enum import Enum
18
+ from pathlib import Path
19
+ from typing import Dict, List, Optional, Tuple
20
+
21
+ from ..core.logger import get_logger
22
+
23
+
24
+ class ServiceStatus(Enum):
25
+ """MCP service health status levels."""
26
+
27
+ WORKING = "✅" # Fully operational
28
+ MISCONFIGURED = "⚠️" # Installed but configuration issues
29
+ NOT_INSTALLED = "❌" # Not installed at all
30
+ PERMISSION_DENIED = "🔒" # Permissions issue
31
+ VERSION_MISMATCH = "🔄" # Needs upgrade
32
+ UNKNOWN = "❓" # Unknown status
33
+
34
+
35
+ @dataclass
36
+ class ServiceDiagnostic:
37
+ """Detailed diagnostic information for a service."""
38
+
39
+ name: str
40
+ status: ServiceStatus
41
+ message: str
42
+ installed_path: Optional[str] = None
43
+ configured_command: Optional[str] = None
44
+ fix_command: Optional[str] = None
45
+ details: Optional[Dict] = None
46
+
47
+
48
+ class MCPServiceVerifier:
49
+ """
50
+ Comprehensive MCP service verification and auto-fix system.
51
+
52
+ This verifier performs deep health checks on MCP services including:
53
+ - Installation verification (pipx, uvx, system)
54
+ - Configuration validation in ~/.claude.json
55
+ - Permission checks on executables
56
+ - Command format verification
57
+ - Runtime functionality testing
58
+ - Auto-fix capabilities for common issues
59
+ """
60
+
61
+ # Known MCP services and their requirements
62
+ SERVICE_REQUIREMENTS = {
63
+ "mcp-vector-search": {
64
+ "pipx_package": "mcp-vector-search",
65
+ "test_args": ["--version"],
66
+ "required_args": ["-m", "mcp_vector_search.mcp.server"],
67
+ "needs_project_path": True,
68
+ },
69
+ "mcp-browser": {
70
+ "pipx_package": "mcp-browser",
71
+ "test_args": ["--version"],
72
+ "required_args": ["mcp"],
73
+ "env_vars": {"MCP_BROWSER_HOME": "~/.mcp-browser"},
74
+ },
75
+ "mcp-ticketer": {
76
+ "pipx_package": "mcp-ticketer",
77
+ "test_args": ["--version"],
78
+ "required_args": ["mcp"],
79
+ },
80
+ "kuzu-memory": {
81
+ "pipx_package": "kuzu-memory",
82
+ "test_args": ["--help"], # kuzu-memory uses --help not --version
83
+ "required_args": ["mcp", "serve"], # Modern format
84
+ "min_version": "1.1.0", # Minimum version for MCP support
85
+ "version_check_pattern": ["mcp", "serve", "claude"], # Pattern to check in help
86
+ },
87
+ }
88
+
89
+ def __init__(self):
90
+ """Initialize the MCP service verifier."""
91
+ self.logger = get_logger(__name__)
92
+ self.project_root = Path.cwd()
93
+ self.claude_config_path = Path.home() / ".claude.json"
94
+ self.diagnostics: Dict[str, ServiceDiagnostic] = {}
95
+
96
+ def verify_all_services(self, auto_fix: bool = False) -> Dict[str, ServiceDiagnostic]:
97
+ """
98
+ Perform comprehensive verification of all MCP services.
99
+
100
+ Args:
101
+ auto_fix: Whether to attempt automatic fixes for issues
102
+
103
+ Returns:
104
+ Dictionary mapping service names to diagnostic results
105
+ """
106
+ self.logger.info("Starting MCP service verification...")
107
+
108
+ for service_name in self.SERVICE_REQUIREMENTS:
109
+ diagnostic = self._verify_service(service_name)
110
+ self.diagnostics[service_name] = diagnostic
111
+
112
+ # Attempt auto-fix if requested and fixable
113
+ if auto_fix and diagnostic.fix_command and diagnostic.status != ServiceStatus.WORKING:
114
+ self._attempt_auto_fix(service_name, diagnostic)
115
+ # Re-verify after fix
116
+ self.diagnostics[service_name] = self._verify_service(service_name)
117
+
118
+ return self.diagnostics
119
+
120
+ def _verify_service(self, service_name: str) -> ServiceDiagnostic:
121
+ """
122
+ Perform deep verification of a single MCP service.
123
+
124
+ Args:
125
+ service_name: Name of the service to verify
126
+
127
+ Returns:
128
+ Diagnostic result for the service
129
+ """
130
+ requirements = self.SERVICE_REQUIREMENTS[service_name]
131
+
132
+ # Step 1: Check if service is installed
133
+ installed_path = self._find_service_installation(service_name)
134
+
135
+ if not installed_path:
136
+ return ServiceDiagnostic(
137
+ name=service_name,
138
+ status=ServiceStatus.NOT_INSTALLED,
139
+ message=f"{service_name} is not installed",
140
+ fix_command=f"pipx install {requirements['pipx_package']}"
141
+ )
142
+
143
+ # Step 2: Check executable permissions
144
+ if not self._check_permissions(installed_path):
145
+ return ServiceDiagnostic(
146
+ name=service_name,
147
+ status=ServiceStatus.PERMISSION_DENIED,
148
+ message=f"Permission denied for {service_name}",
149
+ installed_path=installed_path,
150
+ fix_command=f"chmod +x {installed_path}"
151
+ )
152
+
153
+ # Step 3: Test basic functionality
154
+ if not self._test_service_functionality(service_name, installed_path):
155
+ # Check if it's a version issue for kuzu-memory
156
+ if service_name == "kuzu-memory":
157
+ version_info = self._check_kuzu_version(installed_path)
158
+ if not version_info["has_mcp_support"]:
159
+ return ServiceDiagnostic(
160
+ name=service_name,
161
+ status=ServiceStatus.VERSION_MISMATCH,
162
+ message=f"kuzu-memory needs upgrade to v1.1.0+ for MCP support",
163
+ installed_path=installed_path,
164
+ fix_command="pipx upgrade kuzu-memory",
165
+ details=version_info
166
+ )
167
+
168
+ return ServiceDiagnostic(
169
+ name=service_name,
170
+ status=ServiceStatus.MISCONFIGURED,
171
+ message=f"{service_name} installed but not functioning",
172
+ installed_path=installed_path,
173
+ fix_command=f"pipx reinstall {requirements['pipx_package']}"
174
+ )
175
+
176
+ # Step 4: Verify configuration in ~/.claude.json
177
+ config_status = self._verify_configuration(service_name, installed_path)
178
+
179
+ if not config_status["configured"]:
180
+ return ServiceDiagnostic(
181
+ name=service_name,
182
+ status=ServiceStatus.MISCONFIGURED,
183
+ message=f"{service_name} not configured in ~/.claude.json",
184
+ installed_path=installed_path,
185
+ configured_command=None,
186
+ fix_command="Run 'claude-mpm configure' to update configuration"
187
+ )
188
+
189
+ if not config_status["correct"]:
190
+ return ServiceDiagnostic(
191
+ name=service_name,
192
+ status=ServiceStatus.MISCONFIGURED,
193
+ message=f"{service_name} configuration needs update",
194
+ installed_path=installed_path,
195
+ configured_command=config_status.get("command"),
196
+ fix_command="Run 'claude-mpm configure' to fix configuration",
197
+ details={"config_issue": config_status.get("issue")}
198
+ )
199
+
200
+ # Step 5: Test actual MCP command execution
201
+ if not self._test_mcp_command(service_name, config_status.get("command"), config_status.get("args", [])):
202
+ return ServiceDiagnostic(
203
+ name=service_name,
204
+ status=ServiceStatus.MISCONFIGURED,
205
+ message=f"{service_name} command format issue",
206
+ installed_path=installed_path,
207
+ configured_command=config_status.get("command"),
208
+ fix_command="Run 'claude-mpm configure' to update command format",
209
+ details={"command": config_status.get("command"), "args": config_status.get("args")}
210
+ )
211
+
212
+ # All checks passed!
213
+ return ServiceDiagnostic(
214
+ name=service_name,
215
+ status=ServiceStatus.WORKING,
216
+ message=f"{service_name} is fully operational",
217
+ installed_path=installed_path,
218
+ configured_command=config_status.get("command")
219
+ )
220
+
221
+ def _find_service_installation(self, service_name: str) -> Optional[str]:
222
+ """
223
+ Find where a service is installed.
224
+
225
+ Checks in order:
226
+ 1. pipx installation
227
+ 2. uvx installation
228
+ 3. System PATH
229
+ 4. User pip installation
230
+
231
+ Args:
232
+ service_name: Name of the service
233
+
234
+ Returns:
235
+ Path to the service executable or None
236
+ """
237
+ # Check pipx
238
+ pipx_path = Path.home() / ".local" / "pipx" / "venvs" / service_name / "bin" / service_name
239
+ if pipx_path.exists():
240
+ return str(pipx_path)
241
+
242
+ # Special case for mcp-vector-search (uses Python interpreter)
243
+ if service_name == "mcp-vector-search":
244
+ pipx_python = pipx_path.parent / "python"
245
+ if pipx_python.exists():
246
+ return str(pipx_python)
247
+
248
+ # Check system PATH
249
+ system_path = shutil.which(service_name)
250
+ if system_path:
251
+ return system_path
252
+
253
+ # Check user pip installation
254
+ user_bin = Path.home() / ".local" / "bin" / service_name
255
+ if user_bin.exists():
256
+ return str(user_bin)
257
+
258
+ return None
259
+
260
+ def _check_permissions(self, path: str) -> bool:
261
+ """
262
+ Check if a file has execute permissions.
263
+
264
+ Args:
265
+ path: Path to the executable
266
+
267
+ Returns:
268
+ True if executable, False otherwise
269
+ """
270
+ try:
271
+ return os.access(path, os.X_OK)
272
+ except Exception as e:
273
+ self.logger.debug(f"Permission check failed for {path}: {e}")
274
+ return False
275
+
276
+ def _test_service_functionality(self, service_name: str, path: str) -> bool:
277
+ """
278
+ Test if a service can execute basic commands.
279
+
280
+ Args:
281
+ service_name: Name of the service
282
+ path: Path to the executable
283
+
284
+ Returns:
285
+ True if service is functional, False otherwise
286
+ """
287
+ requirements = self.SERVICE_REQUIREMENTS[service_name]
288
+ test_args = requirements.get("test_args", ["--help"])
289
+
290
+ try:
291
+ # First try direct execution
292
+ result = subprocess.run(
293
+ [path] + test_args,
294
+ capture_output=True,
295
+ text=True,
296
+ timeout=10,
297
+ check=False
298
+ )
299
+
300
+ output = (result.stdout + result.stderr).lower()
301
+
302
+ # Check for success indicators
303
+ if result.returncode == 0:
304
+ return True
305
+
306
+ # Some tools return non-zero but still work
307
+ if any(word in output for word in ["version", "usage", "help", service_name.lower()]):
308
+ # Make sure it's not an error
309
+ if not any(error in output for error in ["error", "not found", "traceback", "no module"]):
310
+ return True
311
+
312
+ # Try pipx run as fallback
313
+ if shutil.which("pipx"):
314
+ result = subprocess.run(
315
+ ["pipx", "run", service_name] + test_args,
316
+ capture_output=True,
317
+ text=True,
318
+ timeout=10,
319
+ check=False
320
+ )
321
+ if result.returncode == 0 or "version" in result.stdout.lower():
322
+ return True
323
+
324
+ except subprocess.TimeoutExpired:
325
+ self.logger.warning(f"Service {service_name} timed out during functionality test")
326
+ except Exception as e:
327
+ self.logger.debug(f"Functionality test failed for {service_name}: {e}")
328
+
329
+ return False
330
+
331
+ def _check_kuzu_version(self, path: str) -> Dict:
332
+ """
333
+ Check kuzu-memory version and MCP support.
334
+
335
+ Args:
336
+ path: Path to kuzu-memory executable
337
+
338
+ Returns:
339
+ Dictionary with version information
340
+ """
341
+ version_info = {
342
+ "has_mcp_support": False,
343
+ "version": "unknown",
344
+ "command_format": None
345
+ }
346
+
347
+ try:
348
+ # Check help output for MCP support
349
+ result = subprocess.run(
350
+ [path, "--help"],
351
+ capture_output=True,
352
+ text=True,
353
+ timeout=10,
354
+ check=False
355
+ )
356
+
357
+ help_text = (result.stdout + result.stderr).lower()
358
+
359
+ # Check for modern "mcp serve" command
360
+ if "mcp serve" in help_text or ("mcp" in help_text and "serve" in help_text):
361
+ version_info["has_mcp_support"] = True
362
+ version_info["command_format"] = "mcp serve"
363
+ # Check for legacy "serve" only
364
+ elif "serve" in help_text and "mcp" not in help_text:
365
+ version_info["has_mcp_support"] = False
366
+ version_info["command_format"] = "serve"
367
+
368
+ # Try to extract version
369
+ version_result = subprocess.run(
370
+ [path, "--version"],
371
+ capture_output=True,
372
+ text=True,
373
+ timeout=5,
374
+ check=False
375
+ )
376
+ if version_result.returncode == 0:
377
+ version_info["version"] = version_result.stdout.strip()
378
+
379
+ except Exception as e:
380
+ self.logger.debug(f"Failed to check kuzu-memory version: {e}")
381
+
382
+ return version_info
383
+
384
+ def _verify_configuration(self, service_name: str, installed_path: str) -> Dict:
385
+ """
386
+ Verify service configuration in ~/.claude.json.
387
+
388
+ Args:
389
+ service_name: Name of the service
390
+ installed_path: Path where service is installed
391
+
392
+ Returns:
393
+ Dictionary with configuration status
394
+ """
395
+ project_key = str(self.project_root)
396
+
397
+ if not self.claude_config_path.exists():
398
+ return {"configured": False, "correct": False}
399
+
400
+ try:
401
+ with open(self.claude_config_path) as f:
402
+ config = json.load(f)
403
+
404
+ # Check if project is configured
405
+ if "projects" not in config or project_key not in config["projects"]:
406
+ return {"configured": False, "correct": False}
407
+
408
+ project_config = config["projects"][project_key]
409
+ mcp_servers = project_config.get("mcpServers", {})
410
+
411
+ # Check if service is configured
412
+ if service_name not in mcp_servers:
413
+ return {"configured": False, "correct": False}
414
+
415
+ service_config = mcp_servers[service_name]
416
+ command = service_config.get("command", "")
417
+ args = service_config.get("args", [])
418
+
419
+ # Validate command configuration
420
+ requirements = self.SERVICE_REQUIREMENTS[service_name]
421
+ required_args = requirements.get("required_args", [])
422
+
423
+ # Check if using pipx run or direct execution
424
+ if command == "pipx" and args and args[0] == "run":
425
+ # pipx run format
426
+ if service_name not in args:
427
+ return {
428
+ "configured": True,
429
+ "correct": False,
430
+ "command": command,
431
+ "args": args,
432
+ "issue": "Service name missing in pipx run command"
433
+ }
434
+ # Check required args are present
435
+ for req_arg in required_args:
436
+ if req_arg not in args[2:]: # Skip "run" and service name
437
+ return {
438
+ "configured": True,
439
+ "correct": False,
440
+ "command": command,
441
+ "args": args,
442
+ "issue": f"Missing required argument: {req_arg}"
443
+ }
444
+ elif command == "uvx" and args and args[0] == service_name:
445
+ # uvx format - similar validation
446
+ for req_arg in required_args:
447
+ if req_arg not in args[1:]:
448
+ return {
449
+ "configured": True,
450
+ "correct": False,
451
+ "command": command,
452
+ "args": args,
453
+ "issue": f"Missing required argument: {req_arg}"
454
+ }
455
+ else:
456
+ # Direct execution - command should be a valid path
457
+ if not Path(command).exists() and command != installed_path:
458
+ # Allow for relative paths that might resolve differently
459
+ if not shutil.which(command):
460
+ return {
461
+ "configured": True,
462
+ "correct": False,
463
+ "command": command,
464
+ "args": args,
465
+ "issue": f"Command path does not exist: {command}"
466
+ }
467
+
468
+ # Check required args
469
+ for req_arg in required_args:
470
+ if req_arg not in args:
471
+ return {
472
+ "configured": True,
473
+ "correct": False,
474
+ "command": command,
475
+ "args": args,
476
+ "issue": f"Missing required argument: {req_arg}"
477
+ }
478
+
479
+ # Special validation for kuzu-memory command format
480
+ if service_name == "kuzu-memory":
481
+ # Should use "mcp serve" format for modern versions
482
+ if args and "serve" in args and "mcp" not in args:
483
+ return {
484
+ "configured": True,
485
+ "correct": False,
486
+ "command": command,
487
+ "args": args,
488
+ "issue": "Using legacy 'serve' format, should use 'mcp serve'"
489
+ }
490
+
491
+ return {
492
+ "configured": True,
493
+ "correct": True,
494
+ "command": command,
495
+ "args": args
496
+ }
497
+
498
+ except Exception as e:
499
+ self.logger.error(f"Failed to verify configuration: {e}")
500
+ return {"configured": False, "correct": False, "error": str(e)}
501
+
502
+ def _test_mcp_command(self, service_name: str, command: str, args: List[str]) -> bool:
503
+ """
504
+ Test if the configured MCP command actually works.
505
+
506
+ Args:
507
+ service_name: Name of the service
508
+ command: Configured command
509
+ args: Configured arguments
510
+
511
+ Returns:
512
+ True if command executes successfully
513
+ """
514
+ if not command:
515
+ return False
516
+
517
+ try:
518
+ # Build test command - add --help to test without side effects
519
+ test_cmd = [command] + args[:2] if args else [command] # Include base args
520
+ test_cmd.append("--help")
521
+
522
+ result = subprocess.run(
523
+ test_cmd,
524
+ capture_output=True,
525
+ text=True,
526
+ timeout=10,
527
+ check=False,
528
+ cwd=str(self.project_root) # Run in project context
529
+ )
530
+
531
+ # Check for success or expected output
532
+ output = (result.stdout + result.stderr).lower()
533
+ if result.returncode == 0:
534
+ return True
535
+
536
+ # Check for expected patterns
537
+ if service_name == "kuzu-memory" and "mcp" in output and "serve" in output:
538
+ return True
539
+ if service_name in output or "usage" in output or "help" in output:
540
+ if not any(error in output for error in ["error", "not found", "traceback"]):
541
+ return True
542
+
543
+ except subprocess.TimeoutExpired:
544
+ self.logger.warning(f"Command test timed out for {service_name}")
545
+ except Exception as e:
546
+ self.logger.debug(f"Command test failed for {service_name}: {e}")
547
+
548
+ return False
549
+
550
+ def _attempt_auto_fix(self, service_name: str, diagnostic: ServiceDiagnostic) -> bool:
551
+ """
552
+ Attempt to automatically fix a service issue.
553
+
554
+ Args:
555
+ service_name: Name of the service
556
+ diagnostic: Current diagnostic information
557
+
558
+ Returns:
559
+ True if fix was successful
560
+ """
561
+ if not diagnostic.fix_command:
562
+ return False
563
+
564
+ self.logger.info(f"Attempting auto-fix for {service_name}: {diagnostic.fix_command}")
565
+
566
+ try:
567
+ # Handle different types of fix commands
568
+ if diagnostic.fix_command.startswith("pipx "):
569
+ # Execute pipx command
570
+ cmd_parts = diagnostic.fix_command.split()
571
+ result = subprocess.run(
572
+ cmd_parts,
573
+ capture_output=True,
574
+ text=True,
575
+ timeout=120,
576
+ check=False
577
+ )
578
+ return result.returncode == 0
579
+
580
+ elif diagnostic.fix_command.startswith("chmod "):
581
+ # Fix permissions
582
+ path = diagnostic.fix_command.replace("chmod +x ", "")
583
+ os.chmod(path, 0o755)
584
+ return True
585
+
586
+ elif "claude-mpm configure" in diagnostic.fix_command:
587
+ # Trigger configuration update
588
+ from .mcp_config_manager import MCPConfigManager
589
+ manager = MCPConfigManager()
590
+ success, _ = manager.ensure_mcp_services_configured()
591
+ return success
592
+
593
+ except Exception as e:
594
+ self.logger.error(f"Auto-fix failed for {service_name}: {e}")
595
+
596
+ return False
597
+
598
+ def print_diagnostics(self, diagnostics: Optional[Dict[str, ServiceDiagnostic]] = None) -> None:
599
+ """
600
+ Print formatted diagnostic results to console.
601
+
602
+ Args:
603
+ diagnostics: Diagnostic results to print (uses self.diagnostics if None)
604
+ """
605
+ if diagnostics is None:
606
+ diagnostics = self.diagnostics
607
+
608
+ if not diagnostics:
609
+ print("\n📋 No services verified yet")
610
+ return
611
+
612
+ print("\n" + "=" * 60)
613
+ print("📋 MCP Service Verification Report")
614
+ print("=" * 60)
615
+
616
+ # Group by status
617
+ working = []
618
+ issues = []
619
+
620
+ for name, diag in diagnostics.items():
621
+ if diag.status == ServiceStatus.WORKING:
622
+ working.append(diag)
623
+ else:
624
+ issues.append(diag)
625
+
626
+ # Print working services
627
+ if working:
628
+ print("\n✅ Fully Operational Services:")
629
+ for diag in working:
630
+ print(f" • {diag.name}: {diag.message}")
631
+ if diag.configured_command:
632
+ print(f" Command: {diag.configured_command}")
633
+
634
+ # Print services with issues
635
+ if issues:
636
+ print("\n⚠️ Services Requiring Attention:")
637
+ for diag in issues:
638
+ print(f"\n {diag.status.value} {diag.name}:")
639
+ print(f" Issue: {diag.message}")
640
+ if diag.installed_path:
641
+ print(f" Path: {diag.installed_path}")
642
+ if diag.fix_command:
643
+ print(f" Fix: {diag.fix_command}")
644
+ if diag.details:
645
+ print(f" Details: {json.dumps(diag.details, indent=6)}")
646
+
647
+ # Summary
648
+ print("\n" + "=" * 60)
649
+ print(f"Summary: {len(working)}/{len(diagnostics)} services operational")
650
+
651
+ if issues:
652
+ print("\n💡 Quick Fix Commands:")
653
+ seen_fixes = set()
654
+ for diag in issues:
655
+ if diag.fix_command and diag.fix_command not in seen_fixes:
656
+ print(f" {diag.fix_command}")
657
+ seen_fixes.add(diag.fix_command)
658
+
659
+ print("\nOr run: claude-mpm verify --fix")
660
+
661
+ print("=" * 60 + "\n")
662
+
663
+
664
+ def verify_mcp_services_on_startup() -> Tuple[bool, str]:
665
+ """
666
+ Quick verification check for MCP services during startup.
667
+
668
+ This is a lightweight check that runs during CLI initialization
669
+ to warn users of potential issues without blocking startup.
670
+
671
+ Returns:
672
+ Tuple of (all_working, summary_message)
673
+ """
674
+ verifier = MCPServiceVerifier()
675
+ logger = get_logger(__name__)
676
+
677
+ # Do quick checks only (don't block startup)
678
+ issues = []
679
+ for service_name in MCPServiceVerifier.SERVICE_REQUIREMENTS:
680
+ path = verifier._find_service_installation(service_name)
681
+ if not path:
682
+ issues.append(f"{service_name} not installed")
683
+ elif not verifier._check_permissions(path):
684
+ issues.append(f"{service_name} permission issue")
685
+
686
+ if issues:
687
+ message = f"MCP service issues detected: {', '.join(issues)}. Run 'claude-mpm verify' for details."
688
+ return False, message
689
+
690
+ return True, "All MCP services appear operational"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.4.6
3
+ Version: 4.4.7
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team
@@ -230,6 +230,18 @@ claude-mpm doctor --checks installation configuration agents mcp
230
230
  # Check MCP service status specifically
231
231
  claude-mpm doctor --checks mcp --verbose
232
232
 
233
+ # Verify MCP services installation and configuration
234
+ claude-mpm verify
235
+
236
+ # Auto-fix MCP service issues
237
+ claude-mpm verify --fix
238
+
239
+ # Verify specific service
240
+ claude-mpm verify --service kuzu-memory
241
+
242
+ # Get JSON output for automation
243
+ claude-mpm verify --json
244
+
233
245
  # Manage memory for large conversation histories
234
246
  claude-mpm cleanup-memory
235
247
  ```
@@ -1,5 +1,5 @@
1
1
  claude_mpm/BUILD_NUMBER,sha256=toytnNjkIKPgQaGwDqQdC1rpNTAdSEc6Vja50d7Ovug,4
2
- claude_mpm/VERSION,sha256=M-cFSdn4NoMwZN-6G3jqIuaWG2LiBtAkXTZdmRNAyc8,6
2
+ claude_mpm/VERSION,sha256=R8T1NAm61Ztbc_VglNJtvUE8VEkNwCNRHjh4rXfFP_M,6
3
3
  claude_mpm/__init__.py,sha256=lyTZAYGH4DTaFGLRNWJKk5Q5oTjzN5I6AXmfVX-Jff0,1512
4
4
  claude_mpm/__main__.py,sha256=Ro5UBWBoQaSAIoSqWAr7zkbLyvi4sSy28WShqAhKJG0,723
5
5
  claude_mpm/constants.py,sha256=cChN3myrAcF3jC-6DvHnBFTEnwlDk-TAsIXPvUZr_yw,5953
@@ -38,6 +38,7 @@ claude_mpm/agents/templates/documentation.json,sha256=Hp9GADw0Wttmxe2pxTCg40DT1A
38
38
  claude_mpm/agents/templates/engineer.json,sha256=tAWKqt35OyL0RUQgTSeX9nVtcjF94ND-WbflXStAXHA,8222
39
39
  claude_mpm/agents/templates/gcp_ops_agent.json,sha256=v2exIGCzPLBDu5M4CCxZ1k3EQfrV0jc6T9C2ecPjScY,10812
40
40
  claude_mpm/agents/templates/imagemagick.json,sha256=6Zy4W_q6BYkJxd_KqDT2B3GBkwhn7VKT9ZVj-O_tj0Q,17747
41
+ claude_mpm/agents/templates/local_ops_agent.json,sha256=50i0Ic2zkxR19VRw8kAadkdR3-sq03SASj1e8TgLIZo,8203
41
42
  claude_mpm/agents/templates/memory_manager.json,sha256=b6bTMLFShY4-884pgjc6wsfLICcVx17ZrRj7y-NH61w,12613
42
43
  claude_mpm/agents/templates/nextjs_engineer.json,sha256=Y2NUxJ3D6FFkDdk83kTqbJ70IZKAVJZkePbyEX_hESo,18786
43
44
  claude_mpm/agents/templates/ops.json,sha256=zp1uBfxdp7Atja0oLcNr8TAv-CQuK4mAnbfnLQMFIF4,10904
@@ -60,7 +61,7 @@ claude_mpm/agents/templates/.claude-mpm/memories/README.md,sha256=vEiG7cPjHRZfwX
60
61
  claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md,sha256=KMZSJrQi-wHOwfl2C0m3A4PpC4QuBtDolAtVybGahKc,77
61
62
  claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md,sha256=UBm4BycXtdaa-_l1VCh0alTGGOUSsnCbpKwbFuI-mUY,2219
62
63
  claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md,sha256=oPvFSYFnmJ4TkbTe4AZnNHWaJMJ-xqZP2WM6scUKQKo,13089
63
- claude_mpm/cli/__init__.py,sha256=U_ZoiMocO4sOT1aBF2CH1OiB5-88PFKIUfnUPDaM0_c,18615
64
+ claude_mpm/cli/__init__.py,sha256=TTtZNHx70miCIk-6ekKZiawOA9a0q1-HmVDecljZ3ZA,19317
64
65
  claude_mpm/cli/__main__.py,sha256=WnVGBwe10InxuZjJRFdwuMF6Gh16aXox6zFgxr0sRXk,847
65
66
  claude_mpm/cli/parser.py,sha256=Vqx9n-6Xo1uNhXR4rThmgWpZXTr0nOtkgDf3oMS9b0g,5855
66
67
  claude_mpm/cli/startup_logging.py,sha256=xtgAmTirhpk2B-dIS9YKcesPprXTukfu24gJSmGt8y8,29357
@@ -98,6 +99,7 @@ claude_mpm/cli/commands/run.py,sha256=_MpX-Eh4OVaUuS_cX8UZFGPbtMwZq0kFfstI6V4VA3
98
99
  claude_mpm/cli/commands/search.py,sha256=_0qbUnop8v758MHsB0fAop8FVxwygD59tec_-iN7pLE,9806
99
100
  claude_mpm/cli/commands/tickets.py,sha256=kl2dklTBnG3Y4jUUJ_PcEVsTx4CtVJfkGWboWBx_mQM,21234
100
101
  claude_mpm/cli/commands/uninstall.py,sha256=KGlVG6veEs1efLVjrZ3wSty7e1zVR9wpt-VXQA1RzWw,5945
102
+ claude_mpm/cli/commands/verify.py,sha256=KhtykUj5hodz0vUQSMCFxe3rGQdqerMVH6J8WlCIWX4,3694
101
103
  claude_mpm/cli/interactive/__init__.py,sha256=vQqUCgPFvLYA1Vkq-5pnY7Ow3A-IgdM0SByfNL1ZLTk,433
102
104
  claude_mpm/cli/interactive/agent_wizard.py,sha256=PMSG6F3Jngb0Gm4nBA6X2PK9Iuuj-AuJd35-g4iE4tE,36202
103
105
  claude_mpm/cli/parsers/__init__.py,sha256=f0Fm1DDXorlVOZPLxUpjC-GIvLh01G-FZOK7TEV1L3I,1005
@@ -105,7 +107,7 @@ claude_mpm/cli/parsers/agent_manager_parser.py,sha256=TQEIm638ELM4X_AAGcn6WrJxlt
105
107
  claude_mpm/cli/parsers/agents_parser.py,sha256=R-9ESNXdjqr5iCEIcmbb2EPvcswW9UfJzMj5bAkgI4U,9042
106
108
  claude_mpm/cli/parsers/analyze_code_parser.py,sha256=cpJSMFbc3mqB4qrMBIEZiikzPekC2IQX-cjt9U2fHW4,5356
107
109
  claude_mpm/cli/parsers/analyze_parser.py,sha256=E00Ao0zwzbJPchs_AJt-aoQ7LQEtJPXRCNQ6Piivb4o,3908
108
- claude_mpm/cli/parsers/base_parser.py,sha256=0iz_EzdlUHya2peMdq_R0OifzAeEaEiV5JCBbUSjW1E,14001
110
+ claude_mpm/cli/parsers/base_parser.py,sha256=Wejn4lAo-rMUQVP13PAehE6NoqmH2AD50HLKDf3QAKM,14169
109
111
  claude_mpm/cli/parsers/config_parser.py,sha256=wp6NbV8_p9txP28MXFcQrri0JDIfGFM7u4aJbYJXcYQ,2699
110
112
  claude_mpm/cli/parsers/configure_parser.py,sha256=xE77C9yMGGmXFuYmSrWBAeKl1xxBaYqrlI9NDSvrjmk,4244
111
113
  claude_mpm/cli/parsers/dashboard_parser.py,sha256=JBCM6v_iZhADr_Fwtk_d3up9AOod1avMab-vkNE61gE,3460
@@ -410,6 +412,7 @@ claude_mpm/services/exceptions.py,sha256=5lVZETr_6-xk0ItH7BTfYUiX5RlckS1e8ah_Ual
410
412
  claude_mpm/services/hook_installer_service.py,sha256=z3kKeriEY1Y9bFesuGlHBxhCtc0Wzd3Zv02k2_rEyGo,19727
411
413
  claude_mpm/services/hook_service.py,sha256=rZnMn_4qxX5g9KAn0IQdoG50WmySNfsTmfG0XHuRHXk,15737
412
414
  claude_mpm/services/mcp_config_manager.py,sha256=bMV3vkDahRjH94Ht91sUg1Ha8H1Sz63Q1AM9SddfvBY,28957
415
+ claude_mpm/services/mcp_service_verifier.py,sha256=ngiegCngX18AFehfyJdvqQAvscoIBvFN_DeOoGTjxj0,25164
413
416
  claude_mpm/services/memory_hook_service.py,sha256=pRlTClkRcw30Jhwbha4BC8IMdzKZxF8aWqf52JlntgY,11600
414
417
  claude_mpm/services/monitor_build_service.py,sha256=8gWR9CaqgXdG6-OjOFXGpk28GCcJTlHhojkUYnMCebI,12160
415
418
  claude_mpm/services/port_manager.py,sha256=CYqLh8Ss_-aoYEXV3G6uZkGexpsRK_XTBL0bV4P3tSI,22838
@@ -431,7 +434,7 @@ claude_mpm/services/agents/deployment/__init__.py,sha256=iprW-Ww3LBtWu9pVFjAX45_
431
434
  claude_mpm/services/agents/deployment/agent_config_provider.py,sha256=gtQcbGr0GspZYplbeRkGXd3BAXl3_pWhKSsbfiSVTww,15234
432
435
  claude_mpm/services/agents/deployment/agent_configuration_manager.py,sha256=5nf69hfo7lUa3_55sDcU5WfpzBtOZCMSTPYGr2dlIdY,12173
433
436
  claude_mpm/services/agents/deployment/agent_definition_factory.py,sha256=DaJ__b3-ADinfd-qNnW6LKWfclOaZbkBBcfuHgqlUic,2697
434
- claude_mpm/services/agents/deployment/agent_deployment.py,sha256=6ntX6T66otpxR7zeKZDGnIzn1uB1Hb_zUxFq6Av3hSg,36423
437
+ claude_mpm/services/agents/deployment/agent_deployment.py,sha256=wcicglXOv4tiJsDUSUJyEgJJryPmXbgGyK7kuiflq7Y,36860
435
438
  claude_mpm/services/agents/deployment/agent_discovery_service.py,sha256=-Iw_gIA6yTdt2eHGDLVJtz9wIQiSUH20WXTapqxd8_Q,18551
436
439
  claude_mpm/services/agents/deployment/agent_environment_manager.py,sha256=kjMiLyZYHs-s9pVdtj4av4hJW0gNXnD7lZz2CJpxmZI,9863
437
440
  claude_mpm/services/agents/deployment/agent_filesystem_manager.py,sha256=F58zMgJYISbi8eqcVlEq6Nd5Q4oLg4Zj4wll4gwRL64,12965
@@ -770,9 +773,9 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
770
773
  claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
771
774
  claude_mpm/validation/agent_validator.py,sha256=Nm2WmcbCb0EwOG4nFcikc3wVdiiAfjGBBI3YoR6ainQ,20915
772
775
  claude_mpm/validation/frontmatter_validator.py,sha256=IDBOCBweO6umydSnUJjBh81sKk3cy9hRFYm61DCiXbI,7020
773
- claude_mpm-4.4.6.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
774
- claude_mpm-4.4.6.dist-info/METADATA,sha256=31bVYfdqk4nEHGwBEE4wdir7O7A2MVEjtKyJiNr-Sew,17264
775
- claude_mpm-4.4.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
776
- claude_mpm-4.4.6.dist-info/entry_points.txt,sha256=FDPZgz8JOvD-6iuXY2l9Zbo9zYVRuE4uz4Qr0vLeGOk,471
777
- claude_mpm-4.4.6.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
778
- claude_mpm-4.4.6.dist-info/RECORD,,
776
+ claude_mpm-4.4.7.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
777
+ claude_mpm-4.4.7.dist-info/METADATA,sha256=dxh7pWMT-QL9jjSQ4oI4tYrYfjuYfJAMucrSK30Jn70,17517
778
+ claude_mpm-4.4.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
779
+ claude_mpm-4.4.7.dist-info/entry_points.txt,sha256=FDPZgz8JOvD-6iuXY2l9Zbo9zYVRuE4uz4Qr0vLeGOk,471
780
+ claude_mpm-4.4.7.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
781
+ claude_mpm-4.4.7.dist-info/RECORD,,