claude-mpm 4.4.5__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 +1 -1
- claude_mpm/agents/templates/local_ops_agent.json +273 -0
- claude_mpm/cli/__init__.py +21 -0
- claude_mpm/cli/commands/mcp_external_commands.py +7 -7
- claude_mpm/cli/commands/mcp_install_commands.py +9 -9
- claude_mpm/cli/commands/mcp_setup_external.py +6 -6
- claude_mpm/cli/commands/verify.py +118 -0
- claude_mpm/cli/parsers/base_parser.py +5 -0
- claude_mpm/hooks/kuzu_memory_hook.py +4 -2
- claude_mpm/services/agents/deployment/agent_deployment.py +10 -6
- claude_mpm/services/diagnostics/checks/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/{claude_desktop_check.py → claude_code_check.py} +95 -112
- claude_mpm/services/diagnostics/checks/mcp_check.py +6 -6
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +29 -6
- claude_mpm/services/diagnostics/diagnostic_runner.py +5 -5
- claude_mpm/services/diagnostics/doctor_reporter.py +4 -4
- claude_mpm/services/mcp_config_manager.py +46 -26
- claude_mpm/services/mcp_gateway/core/process_pool.py +11 -8
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +4 -4
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +8 -4
- claude_mpm/services/mcp_service_verifier.py +690 -0
- claude_mpm/services/project/project_organizer.py +8 -1
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +1 -2
- claude_mpm/services/unified/config_strategies/context_strategy.py +1 -3
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +3 -1
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.4.5.dist-info → claude_mpm-4.4.7.dist-info}/METADATA +20 -5
- {claude_mpm-4.4.5.dist-info → claude_mpm-4.4.7.dist-info}/RECORD +32 -29
- {claude_mpm-4.4.5.dist-info → claude_mpm-4.4.7.dist-info}/WHEEL +0 -0
- {claude_mpm-4.4.5.dist-info → claude_mpm-4.4.7.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.4.5.dist-info → claude_mpm-4.4.7.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.4.5.dist-info → claude_mpm-4.4.7.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.4.
|
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
|
+
}
|
claude_mpm/cli/__init__.py
CHANGED
@@ -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,
|
@@ -45,7 +45,7 @@ class MCPExternalCommands:
|
|
45
45
|
return 1
|
46
46
|
|
47
47
|
def _setup_external(self, args):
|
48
|
-
"""Setup external MCP services in Claude
|
48
|
+
"""Setup external MCP services in Claude Code.
|
49
49
|
|
50
50
|
Args:
|
51
51
|
args: Command line arguments
|
@@ -67,13 +67,13 @@ class MCPExternalCommands:
|
|
67
67
|
print(" You may need to install them manually:")
|
68
68
|
print(" pip install mcp-vector-search mcp-browser")
|
69
69
|
|
70
|
-
# Then configure in Claude
|
71
|
-
print("\n2️⃣ Configuring Claude
|
70
|
+
# Then configure in Claude Code
|
71
|
+
print("\n2️⃣ Configuring Claude Code...")
|
72
72
|
force = getattr(args, "force", False)
|
73
73
|
if setup.setup_external_services(force=force):
|
74
74
|
print("\n✅ External services setup completed successfully!")
|
75
75
|
print("\nNext steps:")
|
76
|
-
print("1. Restart Claude
|
76
|
+
print("1. Restart Claude Code to load the new services")
|
77
77
|
print("2. Check status with: claude-mpm mcp external list")
|
78
78
|
print("3. The services will be available in Claude as separate MCP servers")
|
79
79
|
return 0
|
@@ -111,7 +111,7 @@ class MCPExternalCommands:
|
|
111
111
|
import json
|
112
112
|
from pathlib import Path
|
113
113
|
|
114
|
-
# Check Claude
|
114
|
+
# Check Claude Code configuration
|
115
115
|
config_paths = [
|
116
116
|
Path.home()
|
117
117
|
/ "Library"
|
@@ -157,7 +157,7 @@ class MCPExternalCommands:
|
|
157
157
|
break
|
158
158
|
|
159
159
|
if not config_found:
|
160
|
-
print("❌ No Claude
|
160
|
+
print("❌ No Claude Code configuration found")
|
161
161
|
print(" Please run: claude-mpm mcp install")
|
162
162
|
|
163
163
|
# Check Python packages
|
@@ -215,7 +215,7 @@ class MCPExternalCommands:
|
|
215
215
|
print("\n✅ Configuration updated successfully!")
|
216
216
|
print("\nNext steps:")
|
217
217
|
print("1. Review the .mcp.json file to verify the configuration")
|
218
|
-
print("2. Restart Claude
|
218
|
+
print("2. Restart Claude Code to load the updated services")
|
219
219
|
return 0
|
220
220
|
print("\n❌ Failed to update configuration")
|
221
221
|
return 1
|
@@ -46,8 +46,8 @@ class MCPInstallCommands:
|
|
46
46
|
print("\nPlease install manually with: pip install mcp")
|
47
47
|
return 1
|
48
48
|
|
49
|
-
# Step 2: Configure Claude
|
50
|
-
print("\n2️⃣ Configuring Claude
|
49
|
+
# Step 2: Configure Claude Code with the new CLI command
|
50
|
+
print("\n2️⃣ Configuring Claude Code...")
|
51
51
|
try:
|
52
52
|
success = self._configure_claude_desktop(args.force)
|
53
53
|
if not success:
|
@@ -72,7 +72,7 @@ class MCPInstallCommands:
|
|
72
72
|
# Install Python packages for external services
|
73
73
|
external_setup.check_and_install_pip_packages()
|
74
74
|
|
75
|
-
# Setup external services in Claude
|
75
|
+
# Setup external services in Claude Code config
|
76
76
|
if external_setup.setup_external_services(force=args.force):
|
77
77
|
print("✅ External services configured successfully")
|
78
78
|
else:
|
@@ -86,7 +86,7 @@ class MCPInstallCommands:
|
|
86
86
|
print("\n✅ Configuration completed successfully")
|
87
87
|
print("\n🎉 MCP Gateway is ready to use!")
|
88
88
|
print("\nNext steps:")
|
89
|
-
print("1. Restart Claude
|
89
|
+
print("1. Restart Claude Code (if running)")
|
90
90
|
print("2. Test the server: claude-mpm mcp server --test")
|
91
91
|
print("3. Check status: claude-mpm mcp status")
|
92
92
|
print("4. List external services: claude-mpm mcp external list")
|
@@ -97,9 +97,9 @@ class MCPInstallCommands:
|
|
97
97
|
return 1
|
98
98
|
|
99
99
|
def _configure_claude_desktop(self, force=False):
|
100
|
-
"""Configure Claude
|
100
|
+
"""Configure Claude Code to use the MCP gateway via CLI command.
|
101
101
|
|
102
|
-
WHY: Claude
|
102
|
+
WHY: Claude Code reads MCP server configurations from a platform-specific
|
103
103
|
configuration file. This method updates that file to include the claude-mpm-gateway
|
104
104
|
server configuration.
|
105
105
|
|
@@ -166,14 +166,14 @@ class MCPInstallCommands:
|
|
166
166
|
return self._save_config(config, config_path)
|
167
167
|
|
168
168
|
def _get_claude_config_path(self):
|
169
|
-
"""Get the Claude
|
169
|
+
"""Get the Claude Code configuration file path.
|
170
170
|
|
171
171
|
Returns:
|
172
|
-
Path or None: Path to Claude
|
172
|
+
Path or None: Path to Claude Code config file
|
173
173
|
"""
|
174
174
|
import platform
|
175
175
|
|
176
|
-
# Try multiple possible locations for Claude
|
176
|
+
# Try multiple possible locations for Claude Code config
|
177
177
|
possible_paths = [
|
178
178
|
Path.home()
|
179
179
|
/ "Library"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
"""MCP external services setup module.
|
2
2
|
|
3
3
|
This module handles the registration of external MCP services
|
4
|
-
(mcp-vector-search, mcp-browser) as separate MCP servers in Claude
|
4
|
+
(mcp-vector-search, mcp-browser) as separate MCP servers in Claude Code.
|
5
5
|
"""
|
6
6
|
|
7
7
|
import json
|
@@ -13,7 +13,7 @@ from typing import Dict, Optional, Tuple
|
|
13
13
|
|
14
14
|
|
15
15
|
class MCPExternalServicesSetup:
|
16
|
-
"""Handles setup of external MCP services in Claude
|
16
|
+
"""Handles setup of external MCP services in Claude Code configuration."""
|
17
17
|
|
18
18
|
def get_project_services(self, project_path: Path) -> Dict:
|
19
19
|
"""Get external services configuration for the current project.
|
@@ -472,9 +472,9 @@ class MCPExternalServicesSetup:
|
|
472
472
|
f"\n✅ Successfully configured {success_count} external services in .mcp.json"
|
473
473
|
)
|
474
474
|
print(
|
475
|
-
"\n📌 Note: Claude
|
475
|
+
"\n📌 Note: Claude Code will automatically load these services"
|
476
476
|
)
|
477
|
-
print(" when you open this project directory in Claude
|
477
|
+
print(" when you open this project directory in Claude Code.")
|
478
478
|
return True
|
479
479
|
print("❌ Failed to save configuration")
|
480
480
|
return False
|
@@ -487,7 +487,7 @@ class MCPExternalServicesSetup:
|
|
487
487
|
"""Setup a single external MCP service.
|
488
488
|
|
489
489
|
Args:
|
490
|
-
config: The Claude
|
490
|
+
config: The Claude Code configuration
|
491
491
|
service_name: Name of the service to setup
|
492
492
|
service_info: Service configuration information
|
493
493
|
force: Whether to overwrite existing configuration
|
@@ -814,7 +814,7 @@ class MCPExternalServicesSetup:
|
|
814
814
|
print("✅ Successfully updated mcp-browser configuration in .mcp.json")
|
815
815
|
print(f" Command: {browser_config['command']}")
|
816
816
|
print(f" Args: {browser_config['args']}")
|
817
|
-
print("\n📌 Note: Claude
|
817
|
+
print("\n📌 Note: Claude Code will automatically use this configuration")
|
818
818
|
print(" when you open this project directory.")
|
819
819
|
return True
|
820
820
|
print("❌ Failed to save configuration")
|
@@ -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
|
@@ -163,7 +163,8 @@ class KuzuMemoryHook(SubmitHook):
|
|
163
163
|
capture_output=True,
|
164
164
|
text=True,
|
165
165
|
timeout=5,
|
166
|
-
cwd=str(self.project_path),
|
166
|
+
cwd=str(self.project_path),
|
167
|
+
check=False,
|
167
168
|
)
|
168
169
|
|
169
170
|
if result.returncode == 0 and result.stdout:
|
@@ -267,7 +268,8 @@ Note: Use the memories above to provide more informed and contextual responses.
|
|
267
268
|
capture_output=True,
|
268
269
|
text=True,
|
269
270
|
timeout=5,
|
270
|
-
cwd=str(self.project_path),
|
271
|
+
cwd=str(self.project_path),
|
272
|
+
check=False,
|
271
273
|
)
|
272
274
|
|
273
275
|
if result.returncode == 0:
|
@@ -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
|
-
|
821
|
-
|
822
|
-
|
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
|
)
|
@@ -7,7 +7,7 @@ diagnostic components.
|
|
7
7
|
|
8
8
|
from .agent_check import AgentCheck
|
9
9
|
from .base_check import BaseDiagnosticCheck
|
10
|
-
from .
|
10
|
+
from .claude_code_check import ClaudeCodeCheck
|
11
11
|
from .common_issues_check import CommonIssuesCheck
|
12
12
|
from .configuration_check import ConfigurationCheck
|
13
13
|
from .filesystem_check import FilesystemCheck
|
@@ -21,7 +21,7 @@ from .startup_log_check import StartupLogCheck
|
|
21
21
|
__all__ = [
|
22
22
|
"AgentCheck",
|
23
23
|
"BaseDiagnosticCheck",
|
24
|
-
"
|
24
|
+
"ClaudeCodeCheck",
|
25
25
|
"CommonIssuesCheck",
|
26
26
|
"ConfigurationCheck",
|
27
27
|
"FilesystemCheck",
|