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
@@ -1,7 +1,7 @@
|
|
1
1
|
"""
|
2
|
-
Check Claude
|
2
|
+
Check Claude Code (CLI) integration.
|
3
3
|
|
4
|
-
WHY: Verify that Claude
|
4
|
+
WHY: Verify that Claude Code CLI is installed, properly configured,
|
5
5
|
and integrated with claude-mpm.
|
6
6
|
"""
|
7
7
|
|
@@ -13,24 +13,24 @@ from ..models import DiagnosticResult, DiagnosticStatus
|
|
13
13
|
from .base_check import BaseDiagnosticCheck
|
14
14
|
|
15
15
|
|
16
|
-
class
|
17
|
-
"""Check Claude
|
16
|
+
class ClaudeCodeCheck(BaseDiagnosticCheck):
|
17
|
+
"""Check Claude Code CLI installation and integration."""
|
18
18
|
|
19
19
|
@property
|
20
20
|
def name(self) -> str:
|
21
|
-
return "
|
21
|
+
return "claude_code_check"
|
22
22
|
|
23
23
|
@property
|
24
24
|
def category(self) -> str:
|
25
|
-
return "Claude
|
25
|
+
return "Claude Code"
|
26
26
|
|
27
27
|
def run(self) -> DiagnosticResult:
|
28
|
-
"""Run Claude
|
28
|
+
"""Run Claude Code CLI diagnostics."""
|
29
29
|
try:
|
30
30
|
sub_results = []
|
31
31
|
details = {}
|
32
32
|
|
33
|
-
# Check if Claude
|
33
|
+
# Check if Claude Code CLI is installed
|
34
34
|
install_result = self._check_installation()
|
35
35
|
sub_results.append(install_result)
|
36
36
|
details["installed"] = install_result.status == DiagnosticStatus.OK
|
@@ -54,13 +54,13 @@ class ClaudeDesktopCheck(BaseDiagnosticCheck):
|
|
54
54
|
# Determine overall status
|
55
55
|
if any(r.status == DiagnosticStatus.ERROR for r in sub_results):
|
56
56
|
status = DiagnosticStatus.ERROR
|
57
|
-
message = "Claude
|
57
|
+
message = "Claude Code CLI has critical issues"
|
58
58
|
elif any(r.status == DiagnosticStatus.WARNING for r in sub_results):
|
59
59
|
status = DiagnosticStatus.WARNING
|
60
|
-
message = "Claude
|
60
|
+
message = "Claude Code CLI needs configuration"
|
61
61
|
else:
|
62
62
|
status = DiagnosticStatus.OK
|
63
|
-
message = "Claude
|
63
|
+
message = "Claude Code CLI properly configured"
|
64
64
|
|
65
65
|
return DiagnosticResult(
|
66
66
|
category=self.category,
|
@@ -74,109 +74,102 @@ class ClaudeDesktopCheck(BaseDiagnosticCheck):
|
|
74
74
|
return DiagnosticResult(
|
75
75
|
category=self.category,
|
76
76
|
status=DiagnosticStatus.ERROR,
|
77
|
-
message=f"Claude
|
77
|
+
message=f"Claude Code CLI check failed: {e!s}",
|
78
78
|
details={"error": str(e)},
|
79
79
|
)
|
80
80
|
|
81
81
|
def _check_installation(self) -> DiagnosticResult:
|
82
|
-
"""Check if Claude
|
83
|
-
# Check
|
84
|
-
mac_path = Path("/Applications/Claude.app")
|
85
|
-
linux_paths = [
|
86
|
-
Path.home() / ".local/share/applications/claude.desktop",
|
87
|
-
Path("/usr/share/applications/claude.desktop"),
|
88
|
-
Path("/opt/Claude"),
|
89
|
-
]
|
90
|
-
windows_paths = [
|
91
|
-
Path("C:/Program Files/Claude/Claude.exe"),
|
92
|
-
Path.home() / "AppData/Local/Claude/Claude.exe",
|
93
|
-
]
|
94
|
-
|
95
|
-
# Check for Claude process
|
82
|
+
"""Check if Claude Code CLI is installed."""
|
83
|
+
# Check if claude command is available
|
96
84
|
try:
|
97
85
|
result = subprocess.run(
|
98
|
-
["
|
86
|
+
["claude", "--version"],
|
87
|
+
capture_output=True,
|
88
|
+
timeout=5,
|
89
|
+
check=False,
|
90
|
+
text=True
|
99
91
|
)
|
100
92
|
if result.returncode == 0:
|
101
93
|
return DiagnosticResult(
|
102
|
-
category="Claude
|
94
|
+
category="Claude Code CLI Installation",
|
103
95
|
status=DiagnosticStatus.OK,
|
104
|
-
message="Claude
|
105
|
-
details={
|
96
|
+
message="Claude Code CLI is installed and accessible",
|
97
|
+
details={
|
98
|
+
"installed": True,
|
99
|
+
"path": "claude",
|
100
|
+
"version_output": result.stdout.strip()
|
101
|
+
},
|
106
102
|
)
|
107
103
|
except (subprocess.SubprocessError, FileNotFoundError):
|
108
104
|
pass
|
109
105
|
|
110
|
-
# Check installation paths
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
)
|
118
|
-
|
119
|
-
for path in linux_paths:
|
120
|
-
if path.exists():
|
121
|
-
return DiagnosticResult(
|
122
|
-
category="Claude Desktop Installation",
|
123
|
-
status=DiagnosticStatus.OK,
|
124
|
-
message="Claude Desktop installed (Linux)",
|
125
|
-
details={"path": str(path), "platform": "linux"},
|
126
|
-
)
|
106
|
+
# Check common installation paths
|
107
|
+
possible_paths = [
|
108
|
+
Path("/usr/local/bin/claude"),
|
109
|
+
Path.home() / ".local/bin/claude",
|
110
|
+
Path("/opt/homebrew/bin/claude"),
|
111
|
+
Path("/usr/bin/claude"),
|
112
|
+
]
|
127
113
|
|
128
|
-
for path in
|
129
|
-
if path.exists():
|
114
|
+
for path in possible_paths:
|
115
|
+
if path.exists() and path.is_file():
|
130
116
|
return DiagnosticResult(
|
131
|
-
category="Claude
|
117
|
+
category="Claude Code CLI Installation",
|
132
118
|
status=DiagnosticStatus.OK,
|
133
|
-
message="Claude
|
134
|
-
details={"
|
119
|
+
message=f"Claude Code CLI found at {path}",
|
120
|
+
details={"installed": True, "path": str(path)},
|
135
121
|
)
|
136
122
|
|
137
123
|
return DiagnosticResult(
|
138
|
-
category="Claude
|
139
|
-
status=DiagnosticStatus.
|
140
|
-
message="Claude
|
124
|
+
category="Claude Code CLI Installation",
|
125
|
+
status=DiagnosticStatus.ERROR,
|
126
|
+
message="Claude Code CLI not found",
|
141
127
|
details={"installed": False},
|
142
|
-
fix_description="Install Claude
|
128
|
+
fix_description="Install Claude Code CLI from https://claude.ai/code",
|
143
129
|
)
|
144
130
|
|
145
131
|
def _check_version(self) -> DiagnosticResult:
|
146
|
-
"""Check Claude
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
132
|
+
"""Check Claude Code CLI version compatibility."""
|
133
|
+
try:
|
134
|
+
result = subprocess.run(
|
135
|
+
["claude", "--version"],
|
136
|
+
capture_output=True,
|
137
|
+
timeout=5,
|
138
|
+
check=True,
|
139
|
+
text=True
|
140
|
+
)
|
141
|
+
version_output = result.stdout.strip()
|
153
142
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
return DiagnosticResult(
|
163
|
-
category="Claude Desktop Version",
|
164
|
-
status=DiagnosticStatus.OK,
|
165
|
-
message=f"Version: {version}",
|
166
|
-
details={
|
167
|
-
"version": version,
|
168
|
-
"config_path": str(config_path),
|
169
|
-
},
|
170
|
-
)
|
171
|
-
except Exception:
|
172
|
-
pass
|
143
|
+
# Extract version number (basic parsing)
|
144
|
+
version = "unknown"
|
145
|
+
if "version" in version_output.lower():
|
146
|
+
parts = version_output.split()
|
147
|
+
for i, part in enumerate(parts):
|
148
|
+
if "version" in part.lower() and i + 1 < len(parts):
|
149
|
+
version = parts[i + 1]
|
150
|
+
break
|
173
151
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
152
|
+
# Check minimum version requirement (1.0.60+)
|
153
|
+
status = DiagnosticStatus.OK
|
154
|
+
message = f"Version: {version}"
|
155
|
+
|
156
|
+
return DiagnosticResult(
|
157
|
+
category="Claude Code CLI Version",
|
158
|
+
status=status,
|
159
|
+
message=message,
|
160
|
+
details={
|
161
|
+
"version": version,
|
162
|
+
"version_output": version_output,
|
163
|
+
},
|
164
|
+
)
|
165
|
+
|
166
|
+
except subprocess.SubprocessError as e:
|
167
|
+
return DiagnosticResult(
|
168
|
+
category="Claude Code CLI Version",
|
169
|
+
status=DiagnosticStatus.WARNING,
|
170
|
+
message=f"Could not determine version: {e}",
|
171
|
+
details={"version": "unknown", "error": str(e)},
|
172
|
+
)
|
180
173
|
|
181
174
|
def _check_output_style(self) -> DiagnosticResult:
|
182
175
|
"""Check if output style is deployed."""
|
@@ -224,36 +217,26 @@ class ClaudeDesktopCheck(BaseDiagnosticCheck):
|
|
224
217
|
)
|
225
218
|
|
226
219
|
def _check_mcp_integration(self) -> DiagnosticResult:
|
227
|
-
"""Check MCP server integration with Claude
|
228
|
-
|
220
|
+
"""Check MCP server integration with Claude Code CLI."""
|
221
|
+
# Claude Code CLI uses ~/.claude.json for configuration
|
222
|
+
config_path = Path.home() / ".claude.json"
|
229
223
|
|
230
224
|
if not config_path.exists():
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
config_path = alt_path
|
240
|
-
break
|
241
|
-
else:
|
242
|
-
return DiagnosticResult(
|
243
|
-
category="MCP Integration",
|
244
|
-
status=DiagnosticStatus.WARNING,
|
245
|
-
message="Claude Desktop config not found",
|
246
|
-
details={"configured": False},
|
247
|
-
fix_command="claude-mpm mcp install",
|
248
|
-
fix_description="Install MCP server integration",
|
249
|
-
)
|
225
|
+
return DiagnosticResult(
|
226
|
+
category="MCP Integration",
|
227
|
+
status=DiagnosticStatus.WARNING,
|
228
|
+
message="Claude Code CLI config not found",
|
229
|
+
details={"configured": False, "config_path": str(config_path)},
|
230
|
+
fix_command="claude-mpm mcp install",
|
231
|
+
fix_description="Install MCP server integration for Claude Code CLI",
|
232
|
+
)
|
250
233
|
|
251
234
|
try:
|
252
235
|
with open(config_path) as f:
|
253
236
|
config = json.load(f)
|
254
237
|
|
255
238
|
mcp_servers = config.get("mcpServers", {})
|
256
|
-
if "claude-mpm-gateway" in mcp_servers:
|
239
|
+
if "claude-mpm-gateway" in mcp_servers or "claude-mpm" in mcp_servers:
|
257
240
|
return DiagnosticResult(
|
258
241
|
category="MCP Integration",
|
259
242
|
status=DiagnosticStatus.OK,
|
@@ -274,7 +257,7 @@ class ClaudeDesktopCheck(BaseDiagnosticCheck):
|
|
274
257
|
"config_path": str(config_path),
|
275
258
|
},
|
276
259
|
fix_command="claude-mpm mcp install",
|
277
|
-
fix_description="Configure MCP server for Claude
|
260
|
+
fix_description="Configure MCP server for Claude Code CLI",
|
278
261
|
)
|
279
262
|
|
280
263
|
except Exception as e:
|
@@ -283,4 +266,4 @@ class ClaudeDesktopCheck(BaseDiagnosticCheck):
|
|
283
266
|
status=DiagnosticStatus.WARNING,
|
284
267
|
message=f"Could not check MCP configuration: {e!s}",
|
285
268
|
details={"error": str(e)},
|
286
|
-
)
|
269
|
+
)
|
@@ -2,7 +2,7 @@
|
|
2
2
|
Check MCP (Model Context Protocol) server status.
|
3
3
|
|
4
4
|
WHY: Verify that the MCP gateway is properly installed, configured,
|
5
|
-
and functioning for enhanced Claude
|
5
|
+
and functioning for enhanced Claude Code capabilities.
|
6
6
|
"""
|
7
7
|
|
8
8
|
import json
|
@@ -129,7 +129,7 @@ class MCPCheck(BaseDiagnosticCheck):
|
|
129
129
|
)
|
130
130
|
|
131
131
|
def _check_configuration(self) -> DiagnosticResult:
|
132
|
-
"""Check MCP configuration in Claude
|
132
|
+
"""Check MCP configuration in Claude Code."""
|
133
133
|
config_paths = [
|
134
134
|
Path.home() / ".config/claude/claude_desktop_config.json",
|
135
135
|
Path.home()
|
@@ -147,10 +147,10 @@ class MCPCheck(BaseDiagnosticCheck):
|
|
147
147
|
return DiagnosticResult(
|
148
148
|
category="MCP Configuration",
|
149
149
|
status=DiagnosticStatus.WARNING,
|
150
|
-
message="Claude
|
150
|
+
message="Claude Code config not found",
|
151
151
|
details={"configured": False},
|
152
152
|
fix_command="claude-mpm mcp config",
|
153
|
-
fix_description="Configure MCP server in Claude
|
153
|
+
fix_description="Configure MCP server in Claude Code",
|
154
154
|
)
|
155
155
|
|
156
156
|
try:
|
@@ -167,7 +167,7 @@ class MCPCheck(BaseDiagnosticCheck):
|
|
167
167
|
message="MCP gateway not configured",
|
168
168
|
details={"configured": False, "config_path": str(config_path)},
|
169
169
|
fix_command="claude-mpm mcp config",
|
170
|
-
fix_description="Add MCP gateway to Claude
|
170
|
+
fix_description="Add MCP gateway to Claude Code configuration",
|
171
171
|
)
|
172
172
|
|
173
173
|
# Check configuration validity
|
@@ -203,7 +203,7 @@ class MCPCheck(BaseDiagnosticCheck):
|
|
203
203
|
status=DiagnosticStatus.ERROR,
|
204
204
|
message="Invalid JSON in config file",
|
205
205
|
details={"error": str(e), "config_path": str(config_path)},
|
206
|
-
fix_description="Fix JSON syntax in Claude
|
206
|
+
fix_description="Fix JSON syntax in Claude Code config",
|
207
207
|
)
|
208
208
|
except Exception as e:
|
209
209
|
return DiagnosticResult(
|
@@ -2,7 +2,7 @@
|
|
2
2
|
Check MCP external services installation and health.
|
3
3
|
|
4
4
|
WHY: Verify that MCP services (mcp-vector-search, mcp-browser, mcp-ticketer, kuzu-memory)
|
5
|
-
are properly installed and accessible for enhanced Claude
|
5
|
+
are properly installed and accessible for enhanced Claude Code capabilities.
|
6
6
|
"""
|
7
7
|
|
8
8
|
import json
|
@@ -21,7 +21,10 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
21
21
|
MCP_SERVICES = {
|
22
22
|
"mcp-vector-search": {
|
23
23
|
"package": "mcp-vector-search",
|
24
|
-
"command": [
|
24
|
+
"command": [
|
25
|
+
"mcp-vector-search",
|
26
|
+
"--version",
|
27
|
+
], # Use --version for proper check
|
25
28
|
"description": "Vector search for semantic code navigation",
|
26
29
|
"check_health": True,
|
27
30
|
"health_command": ["mcp-vector-search", "--version"],
|
@@ -305,17 +308,37 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
305
308
|
# Look for actual version information
|
306
309
|
output = (result.stdout + result.stderr).lower()
|
307
310
|
# Check for version indicators
|
308
|
-
if any(
|
311
|
+
if any(
|
312
|
+
keyword in output
|
313
|
+
for keyword in ["version", "v1.", "v0.", "1.", "0."]
|
314
|
+
):
|
309
315
|
# But reject if it's an error message
|
310
|
-
if not any(
|
316
|
+
if not any(
|
317
|
+
error in output
|
318
|
+
for error in [
|
319
|
+
"error",
|
320
|
+
"not found",
|
321
|
+
"no such",
|
322
|
+
"command not found",
|
323
|
+
]
|
324
|
+
):
|
311
325
|
return True
|
312
326
|
|
313
327
|
# For some tools, non-zero return code is OK if version is shown
|
314
328
|
elif "--version" in command or "--help" in command:
|
315
329
|
output = (result.stdout + result.stderr).lower()
|
316
330
|
# Must have version info and no error indicators
|
317
|
-
if
|
318
|
-
if not any(
|
331
|
+
if "version" in output or "v1." in output or "v0." in output:
|
332
|
+
if not any(
|
333
|
+
error in output
|
334
|
+
for error in [
|
335
|
+
"error",
|
336
|
+
"not found",
|
337
|
+
"no such",
|
338
|
+
"command not found",
|
339
|
+
"traceback",
|
340
|
+
]
|
341
|
+
):
|
319
342
|
return True
|
320
343
|
|
321
344
|
except (subprocess.SubprocessError, FileNotFoundError, OSError):
|
@@ -14,7 +14,7 @@ from claude_mpm.core.logging_utils import get_logger
|
|
14
14
|
from .checks import (
|
15
15
|
AgentCheck,
|
16
16
|
BaseDiagnosticCheck,
|
17
|
-
|
17
|
+
ClaudeCodeCheck,
|
18
18
|
CommonIssuesCheck,
|
19
19
|
ConfigurationCheck,
|
20
20
|
FilesystemCheck,
|
@@ -53,7 +53,7 @@ class DiagnosticRunner:
|
|
53
53
|
ConfigurationCheck,
|
54
54
|
FilesystemCheck,
|
55
55
|
InstructionsCheck, # Check instruction files early
|
56
|
-
|
56
|
+
ClaudeCodeCheck,
|
57
57
|
AgentCheck,
|
58
58
|
MCPCheck,
|
59
59
|
MCPServicesCheck, # Check external MCP services
|
@@ -121,7 +121,7 @@ class DiagnosticRunner:
|
|
121
121
|
]
|
122
122
|
# Level 2: May depend on level 1
|
123
123
|
level2 = [
|
124
|
-
|
124
|
+
ClaudeCodeCheck,
|
125
125
|
AgentCheck,
|
126
126
|
MCPCheck,
|
127
127
|
MCPServicesCheck,
|
@@ -209,8 +209,8 @@ class DiagnosticRunner:
|
|
209
209
|
"config": ConfigurationCheck,
|
210
210
|
"filesystem": FilesystemCheck,
|
211
211
|
"fs": FilesystemCheck,
|
212
|
-
"claude":
|
213
|
-
"
|
212
|
+
"claude": ClaudeCodeCheck,
|
213
|
+
"claude_code": ClaudeCodeCheck,
|
214
214
|
"agents": AgentCheck,
|
215
215
|
"agent": AgentCheck,
|
216
216
|
"mcp": MCPCheck,
|
@@ -385,9 +385,9 @@ class DoctorReporter:
|
|
385
385
|
print(
|
386
386
|
f"| Installation Method | {result.details['installation_method']} |"
|
387
387
|
)
|
388
|
-
elif result.category == "Claude
|
388
|
+
elif result.category == "Claude Code":
|
389
389
|
if result.details.get("version"):
|
390
|
-
print(f"| Claude
|
390
|
+
print(f"| Claude Code (CLI) | {result.details['version']} |")
|
391
391
|
|
392
392
|
def _print_mcp_services_markdown(self, summary: DiagnosticSummary):
|
393
393
|
"""Print MCP services status table in markdown."""
|
@@ -533,11 +533,11 @@ class DoctorReporter:
|
|
533
533
|
)
|
534
534
|
|
535
535
|
if (
|
536
|
-
result.category == "Claude
|
536
|
+
result.category == "Claude Code"
|
537
537
|
and result.status == DiagnosticStatus.WARNING
|
538
538
|
):
|
539
539
|
recommendations.append(
|
540
|
-
"Update Claude
|
540
|
+
"Update Claude Code (CLI) to the latest version for best compatibility"
|
541
541
|
)
|
542
542
|
|
543
543
|
if recommendations:
|
@@ -86,7 +86,11 @@ class MCPConfigManager:
|
|
86
86
|
for path in candidates:
|
87
87
|
try:
|
88
88
|
result = subprocess.run(
|
89
|
-
[path, "--help"],
|
89
|
+
[path, "--help"],
|
90
|
+
capture_output=True,
|
91
|
+
text=True,
|
92
|
+
timeout=5,
|
93
|
+
check=False,
|
90
94
|
)
|
91
95
|
# Check if this version has MCP support
|
92
96
|
if "claude" in result.stdout or "mcp" in result.stdout:
|
@@ -304,7 +308,7 @@ class MCPConfigManager:
|
|
304
308
|
|
305
309
|
elif service_name == "kuzu-memory":
|
306
310
|
# Determine kuzu-memory command version
|
307
|
-
kuzu_args = []
|
311
|
+
kuzu_args = ["mcp", "serve"] # Default to the correct modern format
|
308
312
|
test_cmd = None
|
309
313
|
|
310
314
|
if use_pipx_run:
|
@@ -317,17 +321,30 @@ class MCPConfigManager:
|
|
317
321
|
if test_cmd:
|
318
322
|
try:
|
319
323
|
result = subprocess.run(
|
320
|
-
test_cmd,
|
324
|
+
test_cmd,
|
325
|
+
capture_output=True,
|
326
|
+
text=True,
|
327
|
+
timeout=10,
|
328
|
+
check=False,
|
321
329
|
)
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
330
|
+
# Check for MCP support in help output
|
331
|
+
help_output = result.stdout.lower() + result.stderr.lower()
|
332
|
+
|
333
|
+
# Modern version detection - look for "mcp serve" command
|
334
|
+
if "mcp serve" in help_output or ("mcp" in help_output and "serve" in help_output):
|
335
|
+
# Modern version with mcp serve command
|
336
|
+
kuzu_args = ["mcp", "serve"]
|
337
|
+
# Legacy version detection - only "serve" without "mcp"
|
338
|
+
elif "serve" in help_output and "mcp" not in help_output:
|
339
|
+
# Very old version that only has serve command
|
327
340
|
kuzu_args = ["serve"]
|
328
|
-
|
329
|
-
|
330
|
-
|
341
|
+
# Note: "claude mcp-server" format is deprecated and not used
|
342
|
+
else:
|
343
|
+
# Default to the correct modern format
|
344
|
+
kuzu_args = ["mcp", "serve"]
|
345
|
+
except Exception:
|
346
|
+
# Default to the correct mcp serve command on any error
|
347
|
+
kuzu_args = ["mcp", "serve"]
|
331
348
|
|
332
349
|
if use_pipx_run:
|
333
350
|
config["command"] = "pipx"
|
@@ -339,17 +356,16 @@ class MCPConfigManager:
|
|
339
356
|
config["command"] = service_path
|
340
357
|
config["args"] = kuzu_args
|
341
358
|
|
359
|
+
# Generic config for unknown services
|
360
|
+
elif use_pipx_run:
|
361
|
+
config["command"] = "pipx"
|
362
|
+
config["args"] = ["run", service_name]
|
363
|
+
elif use_uvx:
|
364
|
+
config["command"] = "uvx"
|
365
|
+
config["args"] = [service_name]
|
342
366
|
else:
|
343
|
-
|
344
|
-
|
345
|
-
config["command"] = "pipx"
|
346
|
-
config["args"] = ["run", service_name]
|
347
|
-
elif use_uvx:
|
348
|
-
config["command"] = "uvx"
|
349
|
-
config["args"] = [service_name]
|
350
|
-
else:
|
351
|
-
config["command"] = service_path
|
352
|
-
config["args"] = []
|
367
|
+
config["command"] = service_path
|
368
|
+
config["args"] = []
|
353
369
|
|
354
370
|
return config
|
355
371
|
|
@@ -632,9 +648,7 @@ class MCPConfigManager:
|
|
632
648
|
f"pipx install succeeded but verification failed for {service_name}"
|
633
649
|
)
|
634
650
|
else:
|
635
|
-
self.logger.debug(
|
636
|
-
f"pipx install failed: {result.stderr}"
|
637
|
-
)
|
651
|
+
self.logger.debug(f"pipx install failed: {result.stderr}")
|
638
652
|
except subprocess.TimeoutExpired:
|
639
653
|
self.logger.warning(f"pipx install timed out for {service_name}")
|
640
654
|
except Exception as e:
|
@@ -739,9 +753,15 @@ class MCPConfigManager:
|
|
739
753
|
if result.returncode == 0:
|
740
754
|
return True
|
741
755
|
# Some tools return non-zero but still work
|
742
|
-
|
756
|
+
if any(
|
757
|
+
indicator in output
|
758
|
+
for indicator in ["version", "usage", "help", service_name.lower()]
|
759
|
+
):
|
743
760
|
# Make sure it's not an error message
|
744
|
-
if not any(
|
761
|
+
if not any(
|
762
|
+
error in output
|
763
|
+
for error in ["error", "not found", "traceback", "no such"]
|
764
|
+
):
|
745
765
|
return True
|
746
766
|
except Exception as e:
|
747
767
|
self.logger.debug(f"Verification error for {service_name}: {e}")
|
@@ -423,7 +423,8 @@ async def auto_initialize_vector_search():
|
|
423
423
|
["pipx", "install", "mcp-vector-search"],
|
424
424
|
capture_output=True,
|
425
425
|
text=True,
|
426
|
-
timeout=60,
|
426
|
+
timeout=60,
|
427
|
+
check=False, # 1 minute timeout for installation
|
427
428
|
)
|
428
429
|
|
429
430
|
if result.returncode == 0:
|
@@ -492,9 +493,7 @@ async def auto_initialize_vector_search():
|
|
492
493
|
if chroma_db.exists() and chroma_db.stat().st_size > 0:
|
493
494
|
logger.info("✓ Vector search index is healthy and ready")
|
494
495
|
return
|
495
|
-
logger.info(
|
496
|
-
"⚠️ Vector search index may be corrupted, rebuilding..."
|
497
|
-
)
|
496
|
+
logger.info("⚠️ Vector search index may be corrupted, rebuilding...")
|
498
497
|
except Exception as e:
|
499
498
|
logger.debug(
|
500
499
|
f"Vector search health check failed: {e}, will attempt to rebuild"
|
@@ -512,7 +511,8 @@ async def auto_initialize_vector_search():
|
|
512
511
|
capture_output=True,
|
513
512
|
text=True,
|
514
513
|
timeout=30,
|
515
|
-
cwd=str(current_dir),
|
514
|
+
cwd=str(current_dir),
|
515
|
+
check=False, # Run in the project directory
|
516
516
|
)
|
517
517
|
|
518
518
|
if proc.returncode == 0:
|
@@ -527,7 +527,8 @@ async def auto_initialize_vector_search():
|
|
527
527
|
capture_output=True,
|
528
528
|
text=True,
|
529
529
|
timeout=300, # 5 minute timeout for indexing
|
530
|
-
cwd=str(current_dir),
|
530
|
+
cwd=str(current_dir),
|
531
|
+
check=False, # Run in the project directory
|
531
532
|
)
|
532
533
|
if index_proc.returncode == 0:
|
533
534
|
logger.info("✅ Project indexing completed successfully")
|
@@ -610,7 +611,8 @@ async def auto_initialize_kuzu_memory():
|
|
610
611
|
["pipx", "install", "kuzu-memory"],
|
611
612
|
capture_output=True,
|
612
613
|
text=True,
|
613
|
-
timeout=60,
|
614
|
+
timeout=60,
|
615
|
+
check=False, # 1 minute timeout for installation
|
614
616
|
)
|
615
617
|
|
616
618
|
if result.returncode == 0:
|
@@ -679,7 +681,8 @@ async def auto_initialize_kuzu_memory():
|
|
679
681
|
capture_output=True,
|
680
682
|
text=True,
|
681
683
|
timeout=30,
|
682
|
-
cwd=str(current_dir),
|
684
|
+
cwd=str(current_dir),
|
685
|
+
check=False,
|
683
686
|
)
|
684
687
|
|
685
688
|
if proc.returncode == 0:
|