claude-mpm 4.4.12__py3-none-any.whl → 4.5.1__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/web_qa.json +85 -6
- claude_mpm/cli/__init__.py +2 -2
- claude_mpm/cli/commands/mcp_setup_external.py +1 -3
- claude_mpm/cli/commands/verify.py +13 -12
- claude_mpm/services/diagnostics/checks/claude_code_check.py +4 -4
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +114 -57
- claude_mpm/services/mcp_config_manager.py +134 -50
- claude_mpm/services/mcp_service_verifier.py +84 -46
- {claude_mpm-4.4.12.dist-info → claude_mpm-4.5.1.dist-info}/METADATA +1 -1
- {claude_mpm-4.4.12.dist-info → claude_mpm-4.5.1.dist-info}/RECORD +15 -15
- {claude_mpm-4.4.12.dist-info → claude_mpm-4.5.1.dist-info}/WHEEL +0 -0
- {claude_mpm-4.4.12.dist-info → claude_mpm-4.5.1.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.4.12.dist-info → claude_mpm-4.5.1.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.4.12.dist-info → claude_mpm-4.5.1.dist-info}/top_level.txt +0 -0
@@ -48,26 +48,26 @@ class MCPConfigManager:
|
|
48
48
|
"kuzu-memory": {
|
49
49
|
"type": "stdio",
|
50
50
|
"command": "kuzu-memory", # Will be resolved to full path
|
51
|
-
"args": ["mcp", "serve"] # v1.1.0+ uses 'mcp serve' command
|
51
|
+
"args": ["mcp", "serve"], # v1.1.0+ uses 'mcp serve' command
|
52
52
|
},
|
53
53
|
"mcp-ticketer": {
|
54
54
|
"type": "stdio",
|
55
55
|
"command": "mcp-ticketer", # Will be resolved to full path
|
56
|
-
"args": ["mcp"]
|
56
|
+
"args": ["mcp"],
|
57
57
|
},
|
58
58
|
"mcp-browser": {
|
59
59
|
"type": "stdio",
|
60
60
|
"command": "mcp-browser", # Will be resolved to full path
|
61
61
|
"args": ["mcp"],
|
62
|
-
"env": {"MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")}
|
62
|
+
"env": {"MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")},
|
63
63
|
},
|
64
64
|
"mcp-vector-search": {
|
65
65
|
"type": "stdio",
|
66
66
|
# Special handling: needs Python interpreter from pipx venv
|
67
67
|
"command": "python", # Will be resolved to pipx venv Python
|
68
68
|
"args": ["-m", "mcp_vector_search.mcp.server", "{project_root}"],
|
69
|
-
"env": {}
|
70
|
-
}
|
69
|
+
"env": {},
|
70
|
+
},
|
71
71
|
}
|
72
72
|
|
73
73
|
def __init__(self):
|
@@ -265,7 +265,11 @@ class MCPConfigManager:
|
|
265
265
|
test_args = config["args"].copy()
|
266
266
|
# Replace project root placeholder for testing
|
267
267
|
test_args = [
|
268
|
-
|
268
|
+
(
|
269
|
+
arg.replace("{project_root}", str(self.project_root))
|
270
|
+
if "{project_root}" in arg
|
271
|
+
else arg
|
272
|
+
)
|
269
273
|
for arg in test_args
|
270
274
|
]
|
271
275
|
|
@@ -287,13 +291,16 @@ class MCPConfigManager:
|
|
287
291
|
text=True,
|
288
292
|
timeout=5,
|
289
293
|
check=False,
|
290
|
-
env=config.get("env", {})
|
294
|
+
env=config.get("env", {}),
|
291
295
|
)
|
292
296
|
|
293
297
|
# Check if command executed (exit code 0 or 1 for help)
|
294
298
|
if result.returncode in [0, 1]:
|
295
299
|
# Additional check for import errors in stderr
|
296
|
-
if
|
300
|
+
if (
|
301
|
+
"ModuleNotFoundError" in result.stderr
|
302
|
+
or "ImportError" in result.stderr
|
303
|
+
):
|
297
304
|
self.logger.debug(f"Service {service_name} has import errors")
|
298
305
|
return False
|
299
306
|
return True
|
@@ -306,7 +313,9 @@ class MCPConfigManager:
|
|
306
313
|
|
307
314
|
return False
|
308
315
|
|
309
|
-
def get_static_service_config(
|
316
|
+
def get_static_service_config(
|
317
|
+
self, service_name: str, project_path: Optional[str] = None
|
318
|
+
) -> Optional[Dict]:
|
310
319
|
"""
|
311
320
|
Get the static, known-good configuration for an MCP service.
|
312
321
|
|
@@ -329,7 +338,15 @@ class MCPConfigManager:
|
|
329
338
|
binary_name = config["command"]
|
330
339
|
|
331
340
|
# First check pipx location
|
332
|
-
pipx_bin =
|
341
|
+
pipx_bin = (
|
342
|
+
Path.home()
|
343
|
+
/ ".local"
|
344
|
+
/ "pipx"
|
345
|
+
/ "venvs"
|
346
|
+
/ service_name
|
347
|
+
/ "bin"
|
348
|
+
/ binary_name
|
349
|
+
)
|
333
350
|
if pipx_bin.exists():
|
334
351
|
binary_path = str(pipx_bin)
|
335
352
|
else:
|
@@ -352,7 +369,9 @@ class MCPConfigManager:
|
|
352
369
|
config["command"] = binary_path
|
353
370
|
else:
|
354
371
|
# Fall back to pipx run method if binary not found
|
355
|
-
self.logger.debug(
|
372
|
+
self.logger.debug(
|
373
|
+
f"Could not find {binary_name}, using pipx run fallback"
|
374
|
+
)
|
356
375
|
config["command"] = "pipx"
|
357
376
|
config["args"] = ["run", service_name] + config["args"]
|
358
377
|
|
@@ -377,7 +396,15 @@ class MCPConfigManager:
|
|
377
396
|
if service_name == "mcp-vector-search":
|
378
397
|
# Get the correct pipx venv path for the current user
|
379
398
|
home = Path.home()
|
380
|
-
python_path =
|
399
|
+
python_path = (
|
400
|
+
home
|
401
|
+
/ ".local"
|
402
|
+
/ "pipx"
|
403
|
+
/ "venvs"
|
404
|
+
/ "mcp-vector-search"
|
405
|
+
/ "bin"
|
406
|
+
/ "python"
|
407
|
+
)
|
381
408
|
|
382
409
|
# Check if the Python interpreter exists
|
383
410
|
if python_path.exists():
|
@@ -403,12 +430,24 @@ class MCPConfigManager:
|
|
403
430
|
config["command"] = "pipx" # Hope it's in PATH
|
404
431
|
|
405
432
|
# Use pipx run with the spec argument
|
406
|
-
config["args"] = [
|
433
|
+
config["args"] = [
|
434
|
+
"run",
|
435
|
+
"--spec",
|
436
|
+
"mcp-vector-search",
|
437
|
+
"python",
|
438
|
+
"-m",
|
439
|
+
"mcp_vector_search.mcp.server",
|
440
|
+
"{project_root}",
|
441
|
+
]
|
407
442
|
|
408
443
|
# Use provided project path or current project
|
409
444
|
project_root = project_path if project_path else str(self.project_root)
|
410
445
|
config["args"] = [
|
411
|
-
|
446
|
+
(
|
447
|
+
arg.replace("{project_root}", project_root)
|
448
|
+
if "{project_root}" in arg
|
449
|
+
else arg
|
450
|
+
)
|
412
451
|
for arg in config["args"]
|
413
452
|
]
|
414
453
|
|
@@ -432,10 +471,13 @@ class MCPConfigManager:
|
|
432
471
|
if static_config:
|
433
472
|
# Validate that the static config actually works
|
434
473
|
if self.test_service_command(service_name, static_config):
|
435
|
-
self.logger.debug(
|
474
|
+
self.logger.debug(
|
475
|
+
f"Static config for {service_name} validated successfully"
|
476
|
+
)
|
436
477
|
return static_config
|
437
|
-
|
438
|
-
|
478
|
+
self.logger.warning(
|
479
|
+
f"Static config for {service_name} failed validation, trying fallback"
|
480
|
+
)
|
439
481
|
|
440
482
|
# Fall back to detection-based configuration for unknown services
|
441
483
|
import shutil
|
@@ -563,7 +605,9 @@ class MCPConfigManager:
|
|
563
605
|
|
564
606
|
# Standard version detection - look for "mcp serve" command (v1.1.0+)
|
565
607
|
# This is the correct format for kuzu-memory v1.1.0 and later
|
566
|
-
if "mcp serve" in help_output or (
|
608
|
+
if "mcp serve" in help_output or (
|
609
|
+
"mcp" in help_output and "serve" in help_output
|
610
|
+
):
|
567
611
|
# Standard v1.1.0+ version with mcp serve command
|
568
612
|
kuzu_args = ["mcp", "serve"]
|
569
613
|
# Legacy version detection - only "serve" without "mcp"
|
@@ -672,10 +716,14 @@ class MCPConfigManager:
|
|
672
716
|
# Check and fix each service configuration
|
673
717
|
for service_name in self.PIPX_SERVICES:
|
674
718
|
# Get the correct static configuration with project-specific paths
|
675
|
-
correct_config = self.get_static_service_config(
|
719
|
+
correct_config = self.get_static_service_config(
|
720
|
+
service_name, project_key
|
721
|
+
)
|
676
722
|
|
677
723
|
if not correct_config:
|
678
|
-
self.logger.warning(
|
724
|
+
self.logger.warning(
|
725
|
+
f"No static config available for {service_name}"
|
726
|
+
)
|
679
727
|
continue
|
680
728
|
|
681
729
|
# Check if service exists and has correct configuration
|
@@ -687,13 +735,15 @@ class MCPConfigManager:
|
|
687
735
|
# Service is missing
|
688
736
|
needs_update = True
|
689
737
|
added_services.append(f"{service_name} in {Path(project_key).name}")
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
738
|
+
# Service exists, check if configuration is correct
|
739
|
+
# Compare command and args (the most critical parts)
|
740
|
+
elif existing_config.get("command") != correct_config.get(
|
741
|
+
"command"
|
742
|
+
) or existing_config.get("args") != correct_config.get("args"):
|
743
|
+
needs_update = True
|
744
|
+
fixed_services.append(
|
745
|
+
f"{service_name} in {Path(project_key).name}"
|
746
|
+
)
|
697
747
|
|
698
748
|
# Update configuration if needed
|
699
749
|
if needs_update:
|
@@ -714,6 +764,7 @@ class MCPConfigManager:
|
|
714
764
|
f".backup.{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}.json"
|
715
765
|
)
|
716
766
|
import shutil
|
767
|
+
|
717
768
|
shutil.copy2(self.claude_config_path, backup_path)
|
718
769
|
self.logger.debug(f"Created backup: {backup_path}")
|
719
770
|
|
@@ -723,9 +774,13 @@ class MCPConfigManager:
|
|
723
774
|
|
724
775
|
messages = []
|
725
776
|
if added_services:
|
726
|
-
messages.append(
|
777
|
+
messages.append(
|
778
|
+
f"Added MCP services: {', '.join(added_services[:3])}"
|
779
|
+
)
|
727
780
|
if fixed_services:
|
728
|
-
messages.append(
|
781
|
+
messages.append(
|
782
|
+
f"Fixed MCP services: {', '.join(fixed_services[:3])}"
|
783
|
+
)
|
729
784
|
|
730
785
|
if messages:
|
731
786
|
return True, "; ".join(messages)
|
@@ -993,11 +1048,12 @@ class MCPConfigManager:
|
|
993
1048
|
)
|
994
1049
|
|
995
1050
|
if inject_result.returncode == 0:
|
996
|
-
self.logger.info(
|
1051
|
+
self.logger.info(
|
1052
|
+
"✅ Successfully injected gql dependency into mcp-ticketer"
|
1053
|
+
)
|
997
1054
|
return True
|
998
|
-
|
999
|
-
|
1000
|
-
return False
|
1055
|
+
self.logger.warning(f"Failed to inject gql: {inject_result.stderr}")
|
1056
|
+
return False
|
1001
1057
|
|
1002
1058
|
return False
|
1003
1059
|
|
@@ -1048,7 +1104,9 @@ class MCPConfigManager:
|
|
1048
1104
|
|
1049
1105
|
elif issue_type == "import_error":
|
1050
1106
|
# Reinstall to fix corrupted installation
|
1051
|
-
self.logger.info(
|
1107
|
+
self.logger.info(
|
1108
|
+
f" Reinstalling {service_name} to fix import errors..."
|
1109
|
+
)
|
1052
1110
|
success = self._reinstall_service(service_name)
|
1053
1111
|
if success:
|
1054
1112
|
# Special handling for mcp-ticketer - inject missing gql dependency
|
@@ -1064,13 +1122,17 @@ class MCPConfigManager:
|
|
1064
1122
|
if self._check_and_fix_mcp_ticketer_dependencies():
|
1065
1123
|
fixed_services.append(f"{service_name} (dependency fixed)")
|
1066
1124
|
else:
|
1067
|
-
failed_services.append(
|
1125
|
+
failed_services.append(
|
1126
|
+
f"{service_name} (dependency fix failed)"
|
1127
|
+
)
|
1068
1128
|
else:
|
1069
1129
|
failed_services.append(f"{service_name} (unknown dependency issue)")
|
1070
1130
|
|
1071
1131
|
elif issue_type == "path_issue":
|
1072
1132
|
# Path issues are handled by config updates
|
1073
|
-
self.logger.info(
|
1133
|
+
self.logger.info(
|
1134
|
+
f" Path issue for {service_name} will be fixed by config update"
|
1135
|
+
)
|
1074
1136
|
fixed_services.append(f"{service_name} (config updated)")
|
1075
1137
|
|
1076
1138
|
# Build result message
|
@@ -1114,7 +1176,7 @@ class MCPConfigManager:
|
|
1114
1176
|
capture_output=True,
|
1115
1177
|
text=True,
|
1116
1178
|
timeout=10,
|
1117
|
-
check=False
|
1179
|
+
check=False,
|
1118
1180
|
)
|
1119
1181
|
|
1120
1182
|
# Check for specific error patterns
|
@@ -1123,11 +1185,17 @@ class MCPConfigManager:
|
|
1123
1185
|
combined_output = stderr_lower + stdout_lower
|
1124
1186
|
|
1125
1187
|
# Not installed
|
1126
|
-
if
|
1188
|
+
if (
|
1189
|
+
"no apps associated" in combined_output
|
1190
|
+
or "not found" in combined_output
|
1191
|
+
):
|
1127
1192
|
return "not_installed"
|
1128
1193
|
|
1129
1194
|
# Import errors (like mcp-ticketer's corrupted state)
|
1130
|
-
if
|
1195
|
+
if (
|
1196
|
+
"modulenotfounderror" in combined_output
|
1197
|
+
or "importerror" in combined_output
|
1198
|
+
):
|
1131
1199
|
# Check if it's specifically the gql dependency for mcp-ticketer
|
1132
1200
|
if service_name == "mcp-ticketer" and "gql" in combined_output:
|
1133
1201
|
return "missing_dependency"
|
@@ -1138,7 +1206,11 @@ class MCPConfigManager:
|
|
1138
1206
|
return "path_issue"
|
1139
1207
|
|
1140
1208
|
# If help text appears, service is working
|
1141
|
-
if
|
1209
|
+
if (
|
1210
|
+
"usage:" in combined_output
|
1211
|
+
or "help" in combined_output
|
1212
|
+
or result.returncode in [0, 1]
|
1213
|
+
):
|
1142
1214
|
return None # Service is working
|
1143
1215
|
|
1144
1216
|
# Unknown issue
|
@@ -1173,7 +1245,7 @@ class MCPConfigManager:
|
|
1173
1245
|
capture_output=True,
|
1174
1246
|
text=True,
|
1175
1247
|
timeout=30,
|
1176
|
-
check=False
|
1248
|
+
check=False,
|
1177
1249
|
)
|
1178
1250
|
|
1179
1251
|
# Don't check return code - uninstall might fail if partially corrupted
|
@@ -1186,7 +1258,7 @@ class MCPConfigManager:
|
|
1186
1258
|
capture_output=True,
|
1187
1259
|
text=True,
|
1188
1260
|
timeout=120,
|
1189
|
-
check=False
|
1261
|
+
check=False,
|
1190
1262
|
)
|
1191
1263
|
|
1192
1264
|
if install_result.returncode == 0:
|
@@ -1195,12 +1267,14 @@ class MCPConfigManager:
|
|
1195
1267
|
if issue is None:
|
1196
1268
|
self.logger.info(f"✅ Successfully reinstalled {service_name}")
|
1197
1269
|
return True
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
else:
|
1202
|
-
self.logger.error(f"Failed to reinstall {service_name}: {install_result.stderr}")
|
1270
|
+
self.logger.warning(
|
1271
|
+
f"Reinstalled {service_name} but still has issue: {issue}"
|
1272
|
+
)
|
1203
1273
|
return False
|
1274
|
+
self.logger.error(
|
1275
|
+
f"Failed to reinstall {service_name}: {install_result.stderr}"
|
1276
|
+
)
|
1277
|
+
return False
|
1204
1278
|
|
1205
1279
|
except Exception as e:
|
1206
1280
|
self.logger.error(f"Error reinstalling {service_name}: {e}")
|
@@ -1282,7 +1356,9 @@ class MCPConfigManager:
|
|
1282
1356
|
|
1283
1357
|
return False
|
1284
1358
|
|
1285
|
-
def _get_fallback_config(
|
1359
|
+
def _get_fallback_config(
|
1360
|
+
self, service_name: str, project_path: str
|
1361
|
+
) -> Optional[Dict]:
|
1286
1362
|
"""
|
1287
1363
|
Get a fallback configuration for a service if the primary config fails.
|
1288
1364
|
|
@@ -1298,8 +1374,16 @@ class MCPConfigManager:
|
|
1298
1374
|
return {
|
1299
1375
|
"type": "stdio",
|
1300
1376
|
"command": "pipx",
|
1301
|
-
"args": [
|
1302
|
-
|
1377
|
+
"args": [
|
1378
|
+
"run",
|
1379
|
+
"--spec",
|
1380
|
+
"mcp-vector-search",
|
1381
|
+
"python",
|
1382
|
+
"-m",
|
1383
|
+
"mcp_vector_search.mcp.server",
|
1384
|
+
project_path,
|
1385
|
+
],
|
1386
|
+
"env": {},
|
1303
1387
|
}
|
1304
1388
|
|
1305
1389
|
# For other services, try pipx run
|