claude-mpm 4.4.8__py3-none-any.whl → 4.4.9__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/scripts/mcp_server.py +0 -0
- claude_mpm/scripts/start_activity_logging.py +0 -0
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +393 -27
- claude_mpm/services/mcp_config_manager.py +187 -42
- {claude_mpm-4.4.8.dist-info → claude_mpm-4.4.9.dist-info}/METADATA +1 -1
- {claude_mpm-4.4.8.dist-info → claude_mpm-4.4.9.dist-info}/RECORD +9 -22
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- {claude_mpm-4.4.8.dist-info → claude_mpm-4.4.9.dist-info}/WHEEL +0 -0
- {claude_mpm-4.4.8.dist-info → claude_mpm-4.4.9.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.4.8.dist-info → claude_mpm-4.4.9.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.4.8.dist-info → claude_mpm-4.4.9.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
4.4.
|
1
|
+
4.4.9
|
claude_mpm/scripts/mcp_server.py
CHANGED
File without changes
|
File without changes
|
@@ -5,8 +5,10 @@ WHY: Verify that MCP services (mcp-vector-search, mcp-browser, mcp-ticketer, kuz
|
|
5
5
|
are properly installed and accessible for enhanced Claude Code capabilities.
|
6
6
|
"""
|
7
7
|
|
8
|
+
import asyncio
|
8
9
|
import json
|
9
10
|
import subprocess
|
11
|
+
import time
|
10
12
|
from pathlib import Path
|
11
13
|
from typing import Dict, List, Optional, Tuple
|
12
14
|
|
@@ -35,6 +37,8 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
35
37
|
"check_health": True,
|
36
38
|
"health_command": ["mcp-vector-search", "--version"],
|
37
39
|
"pipx_run_command": ["pipx", "run", "mcp-vector-search", "--version"],
|
40
|
+
"mcp_command": ["python", "-m", "mcp_vector_search.mcp.server"], # Command to run as MCP server
|
41
|
+
"pipx_mcp_command": ["pipx", "run", "--spec", "mcp-vector-search", "python", "-m", "mcp_vector_search.mcp.server"],
|
38
42
|
},
|
39
43
|
"mcp-browser": {
|
40
44
|
"package": "mcp-browser",
|
@@ -43,6 +47,7 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
43
47
|
"check_health": True,
|
44
48
|
"health_command": ["mcp-browser", "--version"],
|
45
49
|
"pipx_run_command": ["pipx", "run", "mcp-browser", "--version"],
|
50
|
+
"mcp_command": ["mcp-browser", "mcp"], # Command to run as MCP server
|
46
51
|
},
|
47
52
|
"mcp-ticketer": {
|
48
53
|
"package": "mcp-ticketer",
|
@@ -51,6 +56,7 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
51
56
|
"check_health": True,
|
52
57
|
"health_command": ["mcp-ticketer", "--version"],
|
53
58
|
"pipx_run_command": ["pipx", "run", "mcp-ticketer", "--version"],
|
59
|
+
"mcp_command": ["mcp-ticketer", "mcp"], # Command to run as MCP server
|
54
60
|
},
|
55
61
|
"kuzu-memory": {
|
56
62
|
"package": "kuzu-memory",
|
@@ -59,6 +65,7 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
59
65
|
"check_health": True, # v1.1.0+ has version command
|
60
66
|
"health_command": ["kuzu-memory", "--version"],
|
61
67
|
"pipx_run_command": ["pipx", "run", "kuzu-memory", "--version"],
|
68
|
+
"mcp_command": ["kuzu-memory", "mcp", "serve"], # v1.1.0+ uses 'mcp serve' args
|
62
69
|
},
|
63
70
|
}
|
64
71
|
|
@@ -86,11 +93,20 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
86
93
|
for service_name, service_config in self.MCP_SERVICES.items():
|
87
94
|
service_result = self._check_service(service_name, service_config)
|
88
95
|
sub_results.append(service_result)
|
96
|
+
|
97
|
+
# Extract connection test info if available
|
98
|
+
connection_test = service_result.details.get("connection_test", {})
|
99
|
+
|
89
100
|
services_status[service_name] = {
|
90
101
|
"status": service_result.status.value,
|
91
102
|
"installed": service_result.details.get("installed", False),
|
92
103
|
"accessible": service_result.details.get("accessible", False),
|
93
104
|
"version": service_result.details.get("version"),
|
105
|
+
"connection_tested": bool(connection_test),
|
106
|
+
"connected": connection_test.get("connected", False),
|
107
|
+
"response_time_ms": connection_test.get("response_time_ms"),
|
108
|
+
"tools_discovered": connection_test.get("tools_discovered", 0),
|
109
|
+
"connection_error": connection_test.get("error"),
|
94
110
|
}
|
95
111
|
|
96
112
|
# Check MCP gateway configuration for services
|
@@ -102,12 +118,18 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
102
118
|
accessible_count = sum(
|
103
119
|
1 for s in services_status.values() if s["accessible"]
|
104
120
|
)
|
121
|
+
connected_count = sum(1 for s in services_status.values() if s["connected"])
|
105
122
|
total_services = len(self.MCP_SERVICES)
|
106
123
|
|
124
|
+
# Calculate total tools discovered
|
125
|
+
total_tools = sum(s.get("tools_discovered", 0) for s in services_status.values())
|
126
|
+
|
107
127
|
details["services"] = services_status
|
108
128
|
details["installed_count"] = installed_count
|
109
129
|
details["accessible_count"] = accessible_count
|
130
|
+
details["connected_count"] = connected_count
|
110
131
|
details["total_services"] = total_services
|
132
|
+
details["total_tools_discovered"] = total_tools
|
111
133
|
details["gateway_configured"] = gateway_result.status == DiagnosticStatus.OK
|
112
134
|
|
113
135
|
# Determine overall status
|
@@ -120,6 +142,12 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
120
142
|
elif installed_count == 0:
|
121
143
|
status = DiagnosticStatus.WARNING
|
122
144
|
message = "No MCP services installed"
|
145
|
+
elif connected_count == total_services:
|
146
|
+
status = DiagnosticStatus.OK
|
147
|
+
message = f"All {total_services} MCP services connected ({total_tools} tools available)"
|
148
|
+
elif connected_count > 0:
|
149
|
+
status = DiagnosticStatus.WARNING
|
150
|
+
message = f"{connected_count}/{total_services} MCP services connected, {installed_count} installed"
|
123
151
|
elif accessible_count < installed_count:
|
124
152
|
status = DiagnosticStatus.WARNING
|
125
153
|
message = f"{installed_count}/{total_services} services installed, {accessible_count} accessible"
|
@@ -127,8 +155,8 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
127
155
|
status = DiagnosticStatus.WARNING
|
128
156
|
message = f"{installed_count}/{total_services} MCP services installed"
|
129
157
|
else:
|
130
|
-
status = DiagnosticStatus.
|
131
|
-
message = f"All {total_services} MCP services installed
|
158
|
+
status = DiagnosticStatus.WARNING
|
159
|
+
message = f"All {total_services} MCP services installed but connections not tested"
|
132
160
|
|
133
161
|
return DiagnosticResult(
|
134
162
|
category=self.category,
|
@@ -146,6 +174,185 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
146
174
|
details={"error": str(e)},
|
147
175
|
)
|
148
176
|
|
177
|
+
async def _test_mcp_connection(
|
178
|
+
self, service_name: str, command: List[str]
|
179
|
+
) -> Dict:
|
180
|
+
"""Test MCP server connection by sending JSON-RPC requests."""
|
181
|
+
result = {
|
182
|
+
"connected": False,
|
183
|
+
"response_time": None,
|
184
|
+
"tools_count": 0,
|
185
|
+
"tools": [],
|
186
|
+
"error": None,
|
187
|
+
}
|
188
|
+
|
189
|
+
process = None
|
190
|
+
try:
|
191
|
+
# Start the MCP server process
|
192
|
+
start_time = time.time()
|
193
|
+
process = await asyncio.create_subprocess_exec(
|
194
|
+
*command,
|
195
|
+
stdin=asyncio.subprocess.PIPE,
|
196
|
+
stdout=asyncio.subprocess.PIPE,
|
197
|
+
stderr=asyncio.subprocess.PIPE,
|
198
|
+
)
|
199
|
+
|
200
|
+
# Give the server a moment to initialize
|
201
|
+
await asyncio.sleep(0.1)
|
202
|
+
|
203
|
+
# Prepare initialize request
|
204
|
+
init_request = {
|
205
|
+
"jsonrpc": "2.0",
|
206
|
+
"method": "initialize",
|
207
|
+
"params": {
|
208
|
+
"protocolVersion": "2024-11-05",
|
209
|
+
"capabilities": {},
|
210
|
+
"clientInfo": {
|
211
|
+
"name": "mpm-doctor",
|
212
|
+
"version": "1.0.0"
|
213
|
+
}
|
214
|
+
},
|
215
|
+
"id": 1
|
216
|
+
}
|
217
|
+
|
218
|
+
# Send initialize request
|
219
|
+
request_line = json.dumps(init_request) + "\n"
|
220
|
+
process.stdin.write(request_line.encode())
|
221
|
+
await process.stdin.drain()
|
222
|
+
|
223
|
+
# Read response with timeout
|
224
|
+
try:
|
225
|
+
response_line = await asyncio.wait_for(
|
226
|
+
process.stdout.readline(), timeout=5.0
|
227
|
+
)
|
228
|
+
response_time = time.time() - start_time
|
229
|
+
|
230
|
+
if response_line:
|
231
|
+
# Some MCP servers may output non-JSON before the actual response
|
232
|
+
# Try to find JSON in the response
|
233
|
+
response_text = response_line.decode().strip()
|
234
|
+
|
235
|
+
# Skip empty lines or non-JSON lines
|
236
|
+
while response_text and not response_text.startswith('{'):
|
237
|
+
# Try to read the next line
|
238
|
+
try:
|
239
|
+
response_line = await asyncio.wait_for(
|
240
|
+
process.stdout.readline(), timeout=1.0
|
241
|
+
)
|
242
|
+
if response_line:
|
243
|
+
response_text = response_line.decode().strip()
|
244
|
+
else:
|
245
|
+
break
|
246
|
+
except asyncio.TimeoutError:
|
247
|
+
break
|
248
|
+
|
249
|
+
if not response_text or not response_text.startswith('{'):
|
250
|
+
result["error"] = "No valid JSON response received"
|
251
|
+
return result
|
252
|
+
|
253
|
+
response = json.loads(response_text)
|
254
|
+
|
255
|
+
# Check for valid JSON-RPC response
|
256
|
+
if "result" in response and response.get("id") == 1:
|
257
|
+
result["connected"] = True
|
258
|
+
result["response_time"] = round(response_time * 1000, 2) # ms
|
259
|
+
|
260
|
+
# Send tools/list request
|
261
|
+
tools_request = {
|
262
|
+
"jsonrpc": "2.0",
|
263
|
+
"method": "tools/list",
|
264
|
+
"params": {},
|
265
|
+
"id": 2
|
266
|
+
}
|
267
|
+
|
268
|
+
request_line = json.dumps(tools_request) + "\n"
|
269
|
+
process.stdin.write(request_line.encode())
|
270
|
+
await process.stdin.drain()
|
271
|
+
|
272
|
+
# Read tools response
|
273
|
+
try:
|
274
|
+
tools_response_line = await asyncio.wait_for(
|
275
|
+
process.stdout.readline(), timeout=3.0
|
276
|
+
)
|
277
|
+
|
278
|
+
if tools_response_line:
|
279
|
+
tools_response = json.loads(tools_response_line.decode())
|
280
|
+
if "result" in tools_response:
|
281
|
+
tools = tools_response["result"].get("tools", [])
|
282
|
+
result["tools_count"] = len(tools)
|
283
|
+
# Store first 5 tool names for display
|
284
|
+
result["tools"] = [
|
285
|
+
tool.get("name", "unknown")
|
286
|
+
for tool in tools[:5]
|
287
|
+
]
|
288
|
+
except asyncio.TimeoutError:
|
289
|
+
# Connection successful but tools query timed out
|
290
|
+
pass
|
291
|
+
except (json.JSONDecodeError, KeyError):
|
292
|
+
# Connection successful but tools response invalid
|
293
|
+
pass
|
294
|
+
|
295
|
+
elif "error" in response:
|
296
|
+
result["error"] = f"MCP error: {response['error'].get('message', 'Unknown error')}"
|
297
|
+
else:
|
298
|
+
result["error"] = "Invalid JSON-RPC response format"
|
299
|
+
|
300
|
+
except asyncio.TimeoutError:
|
301
|
+
# Try to get any error output from stderr
|
302
|
+
stderr_output = ""
|
303
|
+
if process and process.stderr:
|
304
|
+
try:
|
305
|
+
stderr_data = await asyncio.wait_for(
|
306
|
+
process.stderr.read(1000), timeout=0.5
|
307
|
+
)
|
308
|
+
if stderr_data:
|
309
|
+
stderr_output = stderr_data.decode('utf-8', errors='ignore')[:200]
|
310
|
+
except:
|
311
|
+
pass
|
312
|
+
|
313
|
+
if stderr_output:
|
314
|
+
result["error"] = f"Connection timeout (5s). Server output: {stderr_output}"
|
315
|
+
else:
|
316
|
+
result["error"] = "Connection timeout (5s)"
|
317
|
+
|
318
|
+
except json.JSONDecodeError as e:
|
319
|
+
# Try to get stderr for more context
|
320
|
+
stderr_output = ""
|
321
|
+
if process and process.stderr:
|
322
|
+
try:
|
323
|
+
stderr_data = await asyncio.wait_for(
|
324
|
+
process.stderr.read(1000), timeout=0.5
|
325
|
+
)
|
326
|
+
if stderr_data:
|
327
|
+
stderr_output = stderr_data.decode('utf-8', errors='ignore')[:200]
|
328
|
+
except:
|
329
|
+
pass
|
330
|
+
|
331
|
+
if stderr_output:
|
332
|
+
result["error"] = f"Invalid JSON response: {str(e)}. Server error: {stderr_output}"
|
333
|
+
else:
|
334
|
+
result["error"] = f"Invalid JSON response: {str(e)}"
|
335
|
+
|
336
|
+
except FileNotFoundError:
|
337
|
+
result["error"] = f"Command not found: {command[0]}"
|
338
|
+
except PermissionError:
|
339
|
+
result["error"] = f"Permission denied: {command[0]}"
|
340
|
+
except Exception as e:
|
341
|
+
result["error"] = f"Connection failed: {str(e)}"
|
342
|
+
finally:
|
343
|
+
# Clean up process
|
344
|
+
if process:
|
345
|
+
try:
|
346
|
+
process.terminate()
|
347
|
+
await asyncio.wait_for(process.wait(), timeout=2.0)
|
348
|
+
except asyncio.TimeoutError:
|
349
|
+
process.kill()
|
350
|
+
await process.wait()
|
351
|
+
except Exception:
|
352
|
+
pass
|
353
|
+
|
354
|
+
return result
|
355
|
+
|
149
356
|
def _check_service(self, service_name: str, config: Dict) -> DiagnosticResult:
|
150
357
|
"""Check a specific MCP service."""
|
151
358
|
details = {"service": service_name}
|
@@ -156,6 +363,12 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
156
363
|
if pipx_path:
|
157
364
|
details["pipx_path"] = pipx_path
|
158
365
|
|
366
|
+
# Special check for mcp-ticketer: ensure gql dependency
|
367
|
+
if service_name == "mcp-ticketer" and pipx_installed:
|
368
|
+
gql_fixed = self._ensure_mcp_ticketer_gql_dependency()
|
369
|
+
if gql_fixed:
|
370
|
+
details["gql_dependency_fixed"] = True
|
371
|
+
|
159
372
|
# Check if accessible in PATH
|
160
373
|
accessible, command_path = self._check_command_accessible(config["command"])
|
161
374
|
details["accessible"] = accessible
|
@@ -197,6 +410,64 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
197
410
|
details["version"] = version
|
198
411
|
break
|
199
412
|
|
413
|
+
# Test MCP connection if installed (accessible or pipx) and has mcp_command
|
414
|
+
if (accessible or pipx_installed) and "mcp_command" in config:
|
415
|
+
# Determine which command to use for MCP connection test
|
416
|
+
mcp_command = None
|
417
|
+
if pipx_installed and not accessible:
|
418
|
+
# Service is installed via pipx but not in PATH
|
419
|
+
if "pipx_mcp_command" in config:
|
420
|
+
# Use special pipx MCP command if available (e.g., for mcp-vector-search)
|
421
|
+
mcp_command = config["pipx_mcp_command"]
|
422
|
+
else:
|
423
|
+
# Build pipx run command based on package
|
424
|
+
base_cmd = config["mcp_command"]
|
425
|
+
if len(base_cmd) > 0 and base_cmd[0] == config["package"]:
|
426
|
+
# Simple case where first command is the package name
|
427
|
+
mcp_command = ["pipx", "run", config["package"]] + base_cmd[1:]
|
428
|
+
else:
|
429
|
+
# Complex case - just try running the package with mcp arg
|
430
|
+
mcp_command = ["pipx", "run", config["package"], "mcp"]
|
431
|
+
elif details.get("accessible_via_pipx_run"):
|
432
|
+
# Use pipx run for the MCP command
|
433
|
+
if "pipx_mcp_command" in config:
|
434
|
+
# Use special pipx MCP command if available (e.g., for mcp-vector-search)
|
435
|
+
mcp_command = config["pipx_mcp_command"]
|
436
|
+
else:
|
437
|
+
# Build pipx run command
|
438
|
+
base_cmd = config["mcp_command"]
|
439
|
+
if service_name == "kuzu-memory":
|
440
|
+
# Special case for kuzu-memory with args
|
441
|
+
mcp_command = ["pipx", "run", base_cmd[0]] + base_cmd[1:]
|
442
|
+
else:
|
443
|
+
mcp_command = ["pipx", "run"] + base_cmd
|
444
|
+
else:
|
445
|
+
mcp_command = config["mcp_command"]
|
446
|
+
|
447
|
+
if mcp_command:
|
448
|
+
# Run async connection test
|
449
|
+
try:
|
450
|
+
loop = asyncio.new_event_loop()
|
451
|
+
asyncio.set_event_loop(loop)
|
452
|
+
connection_result = loop.run_until_complete(
|
453
|
+
self._test_mcp_connection(service_name, mcp_command)
|
454
|
+
)
|
455
|
+
loop.close()
|
456
|
+
|
457
|
+
# Add connection test results to details
|
458
|
+
details["connection_test"] = {
|
459
|
+
"connected": connection_result["connected"],
|
460
|
+
"response_time_ms": connection_result["response_time"],
|
461
|
+
"tools_discovered": connection_result["tools_count"],
|
462
|
+
"tools_sample": connection_result["tools"],
|
463
|
+
"error": connection_result["error"]
|
464
|
+
}
|
465
|
+
except Exception as e:
|
466
|
+
details["connection_test"] = {
|
467
|
+
"connected": False,
|
468
|
+
"error": f"Test failed: {str(e)}"
|
469
|
+
}
|
470
|
+
|
200
471
|
# Determine status
|
201
472
|
if not (pipx_installed or accessible):
|
202
473
|
return DiagnosticResult(
|
@@ -211,10 +482,19 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
211
482
|
if pipx_installed and not accessible:
|
212
483
|
# Check if pipx run works
|
213
484
|
if details.get("pipx_run_available"):
|
485
|
+
# Include connection test info if available
|
486
|
+
connection_info = details.get("connection_test", {})
|
487
|
+
if connection_info.get("connected"):
|
488
|
+
message = f"Installed via pipx, connection OK ({connection_info.get('tools_discovered', 0)} tools)"
|
489
|
+
elif connection_info.get("error"):
|
490
|
+
message = f"Installed via pipx, connection failed: {connection_info['error']}"
|
491
|
+
else:
|
492
|
+
message = "Installed via pipx (use 'pipx run' to execute)"
|
493
|
+
|
214
494
|
return DiagnosticResult(
|
215
495
|
category=f"MCP Service: {service_name}",
|
216
|
-
status=DiagnosticStatus.OK,
|
217
|
-
message=
|
496
|
+
status=DiagnosticStatus.OK if connection_info.get("connected") else DiagnosticStatus.WARNING,
|
497
|
+
message=message,
|
218
498
|
details=details,
|
219
499
|
)
|
220
500
|
return DiagnosticResult(
|
@@ -226,10 +506,26 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
226
506
|
fix_description="Ensure pipx bin directory is in PATH",
|
227
507
|
)
|
228
508
|
|
509
|
+
# Service is accessible - check connection test results
|
510
|
+
connection_info = details.get("connection_test", {})
|
511
|
+
if connection_info:
|
512
|
+
if connection_info.get("connected"):
|
513
|
+
response_time = connection_info.get("response_time_ms")
|
514
|
+
tools_count = connection_info.get("tools_discovered", 0)
|
515
|
+
message = f"Installed, accessible, connection OK ({tools_count} tools, {response_time}ms)"
|
516
|
+
status = DiagnosticStatus.OK
|
517
|
+
else:
|
518
|
+
error = connection_info.get("error", "Unknown error")
|
519
|
+
message = f"Installed but connection failed: {error}"
|
520
|
+
status = DiagnosticStatus.WARNING
|
521
|
+
else:
|
522
|
+
message = "Installed and accessible"
|
523
|
+
status = DiagnosticStatus.OK
|
524
|
+
|
229
525
|
return DiagnosticResult(
|
230
526
|
category=f"MCP Service: {service_name}",
|
231
|
-
status=
|
232
|
-
message=
|
527
|
+
status=status,
|
528
|
+
message=message,
|
233
529
|
details=details,
|
234
530
|
)
|
235
531
|
|
@@ -423,40 +719,42 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
423
719
|
args = kuzu_config.get("args", [])
|
424
720
|
needs_fix = False
|
425
721
|
fix_reason = ""
|
426
|
-
|
722
|
+
# The correct args for kuzu-memory v1.1.0+ are ["mcp", "serve"]
|
723
|
+
correct_args = ["mcp", "serve"]
|
427
724
|
|
428
|
-
# Check for
|
429
|
-
if args
|
430
|
-
needs_fix = True
|
431
|
-
fix_reason = "Outdated 'claude mcp-server' format"
|
432
|
-
new_args = ["mcp", "serve"]
|
433
|
-
elif args == ["serve"]:
|
725
|
+
# Check for any configuration that is NOT the correct one
|
726
|
+
if args != correct_args:
|
434
727
|
needs_fix = True
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
728
|
+
# Identify the specific issue
|
729
|
+
if args == ["claude", "mcp-server"]:
|
730
|
+
fix_reason = "Outdated 'claude mcp-server' format (pre-v1.1.0)"
|
731
|
+
elif args == ["serve"]:
|
732
|
+
fix_reason = "Legacy 'serve' format"
|
733
|
+
elif args == ["mcp-server"]:
|
734
|
+
fix_reason = "Incorrect 'mcp-server' format"
|
735
|
+
elif args == []:
|
736
|
+
fix_reason = "Empty args list"
|
737
|
+
else:
|
738
|
+
fix_reason = f"Incorrect args format: {args}"
|
441
739
|
|
442
740
|
if needs_fix:
|
443
|
-
#
|
741
|
+
# Log the issue for debugging
|
444
742
|
self.logger.warning(
|
445
743
|
f"Found incorrect kuzu-memory configuration: {fix_reason}. "
|
446
|
-
f"Current args: {args}"
|
744
|
+
f"Current args: {args}, should be: {correct_args}"
|
447
745
|
)
|
448
746
|
|
449
747
|
# Auto-fix the configuration
|
450
|
-
fixed = self._fix_kuzu_memory_args(claude_config_path, config,
|
748
|
+
fixed = self._fix_kuzu_memory_args(claude_config_path, config, correct_args)
|
451
749
|
|
452
750
|
if fixed:
|
453
751
|
return DiagnosticResult(
|
454
752
|
category="kuzu-memory Configuration Fix",
|
455
753
|
status=DiagnosticStatus.OK,
|
456
|
-
message="Fixed kuzu-memory configuration",
|
754
|
+
message=f"Fixed kuzu-memory configuration to use correct args",
|
457
755
|
details={
|
458
756
|
"old_args": args,
|
459
|
-
"new_args":
|
757
|
+
"new_args": correct_args,
|
460
758
|
"reason": fix_reason,
|
461
759
|
"auto_fixed": True,
|
462
760
|
},
|
@@ -468,7 +766,7 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
468
766
|
message="kuzu-memory has incorrect configuration",
|
469
767
|
details={
|
470
768
|
"current_args": args,
|
471
|
-
"correct_args":
|
769
|
+
"correct_args": correct_args,
|
472
770
|
"reason": fix_reason,
|
473
771
|
"auto_fix_failed": True,
|
474
772
|
},
|
@@ -476,7 +774,7 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
476
774
|
fix_description="Fix kuzu-memory configuration manually",
|
477
775
|
)
|
478
776
|
|
479
|
-
# Configuration is correct
|
777
|
+
# Configuration is correct - args match ["mcp", "serve"]
|
480
778
|
return None
|
481
779
|
|
482
780
|
except (json.JSONDecodeError, Exception) as e:
|
@@ -489,18 +787,48 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
489
787
|
# Save old args before updating
|
490
788
|
old_args = config["mcpServers"]["kuzu-memory"].get("args", [])
|
491
789
|
|
790
|
+
# Log the exact change we're about to make
|
791
|
+
self.logger.debug(
|
792
|
+
f"Fixing kuzu-memory args: old={old_args}, new={new_args}"
|
793
|
+
)
|
794
|
+
|
492
795
|
# Create backup
|
493
796
|
backup_path = config_path.with_suffix(".json.backup")
|
494
797
|
with open(backup_path, "w") as f:
|
495
798
|
json.dump(config, f, indent=2)
|
496
799
|
|
497
|
-
# Update the configuration
|
800
|
+
# Update the configuration - ensure we're setting the exact new_args
|
498
801
|
config["mcpServers"]["kuzu-memory"]["args"] = new_args
|
499
802
|
|
803
|
+
# Verify the update in memory before writing
|
804
|
+
if config["mcpServers"]["kuzu-memory"]["args"] != new_args:
|
805
|
+
self.logger.error(
|
806
|
+
f"Failed to update args in memory! "
|
807
|
+
f"Expected {new_args}, got {config['mcpServers']['kuzu-memory']['args']}"
|
808
|
+
)
|
809
|
+
return False
|
810
|
+
|
500
811
|
# Write updated configuration
|
501
812
|
with open(config_path, "w") as f:
|
502
813
|
json.dump(config, f, indent=2)
|
503
814
|
|
815
|
+
# Verify the file was written correctly
|
816
|
+
with open(config_path) as f:
|
817
|
+
verify_config = json.load(f)
|
818
|
+
verify_args = verify_config.get("mcpServers", {}).get("kuzu-memory", {}).get("args", [])
|
819
|
+
|
820
|
+
if verify_args != new_args:
|
821
|
+
self.logger.error(
|
822
|
+
f"Configuration write verification failed! "
|
823
|
+
f"Expected {new_args}, got {verify_args}"
|
824
|
+
)
|
825
|
+
# Restore backup
|
826
|
+
with open(backup_path) as bf:
|
827
|
+
backup_config = json.load(bf)
|
828
|
+
with open(config_path, "w") as f:
|
829
|
+
json.dump(backup_config, f, indent=2)
|
830
|
+
return False
|
831
|
+
|
504
832
|
self.logger.info(
|
505
833
|
f"✅ Fixed kuzu-memory configuration in {config_path}\n"
|
506
834
|
f" Changed args from {old_args} to {new_args}\n"
|
@@ -594,3 +922,41 @@ class MCPServicesCheck(BaseDiagnosticCheck):
|
|
594
922
|
message=f"Could not check configuration: {e!s}",
|
595
923
|
details={"error": str(e)},
|
596
924
|
)
|
925
|
+
|
926
|
+
def _ensure_mcp_ticketer_gql_dependency(self) -> bool:
|
927
|
+
"""Ensure mcp-ticketer has the gql dependency injected."""
|
928
|
+
try:
|
929
|
+
# First check if mcp-ticketer can import gql
|
930
|
+
result = subprocess.run(
|
931
|
+
["pipx", "run", "--spec", "mcp-ticketer", "python", "-c", "import gql"],
|
932
|
+
capture_output=True,
|
933
|
+
text=True,
|
934
|
+
timeout=5,
|
935
|
+
check=False,
|
936
|
+
)
|
937
|
+
|
938
|
+
# If import fails, inject the dependency
|
939
|
+
if result.returncode != 0:
|
940
|
+
self.logger.info("🔧 mcp-ticketer missing gql dependency, fixing...")
|
941
|
+
|
942
|
+
inject_result = subprocess.run(
|
943
|
+
["pipx", "inject", "mcp-ticketer", "gql"],
|
944
|
+
capture_output=True,
|
945
|
+
text=True,
|
946
|
+
timeout=30,
|
947
|
+
check=False,
|
948
|
+
)
|
949
|
+
|
950
|
+
if inject_result.returncode == 0:
|
951
|
+
self.logger.info("✅ Successfully injected gql dependency into mcp-ticketer")
|
952
|
+
return True
|
953
|
+
else:
|
954
|
+
self.logger.warning(f"Failed to inject gql dependency: {inject_result.stderr}")
|
955
|
+
return False
|
956
|
+
|
957
|
+
# Dependency already present
|
958
|
+
return False
|
959
|
+
|
960
|
+
except Exception as e:
|
961
|
+
self.logger.debug(f"Could not check/fix mcp-ticketer gql dependency: {e}")
|
962
|
+
return False
|
@@ -41,6 +41,33 @@ class MCPConfigManager:
|
|
41
41
|
"kuzu-memory",
|
42
42
|
}
|
43
43
|
|
44
|
+
# Static known-good MCP service configurations
|
45
|
+
# These are the correct, tested configurations that work reliably
|
46
|
+
STATIC_MCP_CONFIGS = {
|
47
|
+
"kuzu-memory": {
|
48
|
+
"type": "stdio",
|
49
|
+
"command": "pipx",
|
50
|
+
"args": ["run", "kuzu-memory", "mcp", "serve"]
|
51
|
+
},
|
52
|
+
"mcp-ticketer": {
|
53
|
+
"type": "stdio",
|
54
|
+
"command": "pipx",
|
55
|
+
"args": ["run", "mcp-ticketer", "mcp"]
|
56
|
+
},
|
57
|
+
"mcp-browser": {
|
58
|
+
"type": "stdio",
|
59
|
+
"command": "pipx",
|
60
|
+
"args": ["run", "mcp-browser", "mcp"],
|
61
|
+
"env": {"MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")}
|
62
|
+
},
|
63
|
+
"mcp-vector-search": {
|
64
|
+
"type": "stdio",
|
65
|
+
"command": "pipx",
|
66
|
+
"args": ["run", "mcp-vector-search", "-m", "mcp_vector_search.mcp.server", "{project_root}"],
|
67
|
+
"env": {}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
44
71
|
def __init__(self):
|
45
72
|
"""Initialize the MCP configuration manager."""
|
46
73
|
self.logger = get_logger(__name__)
|
@@ -195,11 +222,36 @@ class MCPConfigManager:
|
|
195
222
|
|
196
223
|
return None
|
197
224
|
|
225
|
+
def get_static_service_config(self, service_name: str) -> Optional[Dict]:
|
226
|
+
"""
|
227
|
+
Get the static, known-good configuration for an MCP service.
|
228
|
+
|
229
|
+
Args:
|
230
|
+
service_name: Name of the MCP service
|
231
|
+
|
232
|
+
Returns:
|
233
|
+
Static service configuration dict or None if service not known
|
234
|
+
"""
|
235
|
+
if service_name not in self.STATIC_MCP_CONFIGS:
|
236
|
+
return None
|
237
|
+
|
238
|
+
config = self.STATIC_MCP_CONFIGS[service_name].copy()
|
239
|
+
|
240
|
+
# Special handling for mcp-vector-search: replace {project_root} placeholder
|
241
|
+
if service_name == "mcp-vector-search":
|
242
|
+
config["args"] = [
|
243
|
+
arg.replace("{project_root}", str(self.project_root)) if "{project_root}" in arg else arg
|
244
|
+
for arg in config["args"]
|
245
|
+
]
|
246
|
+
|
247
|
+
return config
|
248
|
+
|
198
249
|
def generate_service_config(self, service_name: str) -> Optional[Dict]:
|
199
250
|
"""
|
200
251
|
Generate configuration for a specific MCP service.
|
201
252
|
|
202
|
-
Prefers
|
253
|
+
Prefers static configurations over detection. Falls back to detection
|
254
|
+
only for unknown services.
|
203
255
|
|
204
256
|
Args:
|
205
257
|
service_name: Name of the MCP service
|
@@ -207,6 +259,12 @@ class MCPConfigManager:
|
|
207
259
|
Returns:
|
208
260
|
Service configuration dict or None if service not found
|
209
261
|
"""
|
262
|
+
# First try to get static configuration
|
263
|
+
static_config = self.get_static_service_config(service_name)
|
264
|
+
if static_config:
|
265
|
+
return static_config
|
266
|
+
|
267
|
+
# Fall back to detection-based configuration for unknown services
|
210
268
|
import shutil
|
211
269
|
|
212
270
|
# Check for pipx run first (preferred for isolation)
|
@@ -308,7 +366,7 @@ class MCPConfigManager:
|
|
308
366
|
|
309
367
|
elif service_name == "kuzu-memory":
|
310
368
|
# Determine kuzu-memory command version
|
311
|
-
kuzu_args = ["mcp", "serve"] # Default to the
|
369
|
+
kuzu_args = ["mcp", "serve"] # Default to the standard v1.1.0+ format
|
312
370
|
test_cmd = None
|
313
371
|
|
314
372
|
if use_pipx_run:
|
@@ -330,20 +388,21 @@ class MCPConfigManager:
|
|
330
388
|
# Check for MCP support in help output
|
331
389
|
help_output = result.stdout.lower() + result.stderr.lower()
|
332
390
|
|
333
|
-
#
|
391
|
+
# Standard version detection - look for "mcp serve" command (v1.1.0+)
|
392
|
+
# This is the correct format for kuzu-memory v1.1.0 and later
|
334
393
|
if "mcp serve" in help_output or ("mcp" in help_output and "serve" in help_output):
|
335
|
-
#
|
394
|
+
# Standard v1.1.0+ version with mcp serve command
|
336
395
|
kuzu_args = ["mcp", "serve"]
|
337
396
|
# Legacy version detection - only "serve" without "mcp"
|
338
397
|
elif "serve" in help_output and "mcp" not in help_output:
|
339
398
|
# Very old version that only has serve command
|
340
399
|
kuzu_args = ["serve"]
|
341
|
-
# Note: "claude mcp-server" format is deprecated and not used
|
342
400
|
else:
|
343
|
-
# Default to the
|
401
|
+
# Default to the standard mcp serve format (v1.1.0+)
|
402
|
+
# Note: "claude mcp-server" format is deprecated and does not work
|
344
403
|
kuzu_args = ["mcp", "serve"]
|
345
404
|
except Exception:
|
346
|
-
# Default to the
|
405
|
+
# Default to the standard mcp serve command on any error
|
347
406
|
kuzu_args = ["mcp", "serve"]
|
348
407
|
|
349
408
|
if use_pipx_run:
|
@@ -371,17 +430,20 @@ class MCPConfigManager:
|
|
371
430
|
|
372
431
|
def ensure_mcp_services_configured(self) -> Tuple[bool, str]:
|
373
432
|
"""
|
374
|
-
Ensure MCP services are configured in ~/.claude.json on startup.
|
433
|
+
Ensure MCP services are configured correctly in ~/.claude.json on startup.
|
375
434
|
|
376
|
-
This method checks
|
377
|
-
|
435
|
+
This method checks ALL projects in ~/.claude.json and ensures each has
|
436
|
+
the correct, static MCP service configurations. It will:
|
437
|
+
1. Add missing services
|
438
|
+
2. Fix incorrect configurations
|
439
|
+
3. Update all projects, not just the current one
|
378
440
|
|
379
441
|
Returns:
|
380
442
|
Tuple of (success, message)
|
381
443
|
"""
|
382
444
|
updated = False
|
445
|
+
fixed_services = []
|
383
446
|
added_services = []
|
384
|
-
project_key = str(self.project_root)
|
385
447
|
|
386
448
|
# Load existing Claude config or create minimal structure
|
387
449
|
claude_config = {}
|
@@ -396,9 +458,23 @@ class MCPConfigManager:
|
|
396
458
|
# Ensure projects structure exists
|
397
459
|
if "projects" not in claude_config:
|
398
460
|
claude_config["projects"] = {}
|
461
|
+
updated = True
|
399
462
|
|
400
|
-
|
401
|
-
|
463
|
+
# Check and fix mcp-ticketer dependencies ONCE before processing projects
|
464
|
+
# This avoids running the same pipx inject command 100+ times
|
465
|
+
mcp_ticketer_fixed = False
|
466
|
+
if "mcp-ticketer" in self.PIPX_SERVICES:
|
467
|
+
mcp_ticketer_fixed = self._check_and_fix_mcp_ticketer_dependencies()
|
468
|
+
|
469
|
+
# Process ALL projects in the config, not just current one
|
470
|
+
projects_to_update = list(claude_config.get("projects", {}).keys())
|
471
|
+
|
472
|
+
# Also add the current project if not in list
|
473
|
+
current_project_key = str(self.project_root)
|
474
|
+
if current_project_key not in projects_to_update:
|
475
|
+
projects_to_update.append(current_project_key)
|
476
|
+
# Initialize new project structure
|
477
|
+
claude_config["projects"][current_project_key] = {
|
402
478
|
"allowedTools": [],
|
403
479
|
"history": [],
|
404
480
|
"mcpContextUris": [],
|
@@ -412,29 +488,51 @@ class MCPConfigManager:
|
|
412
488
|
}
|
413
489
|
updated = True
|
414
490
|
|
415
|
-
#
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
491
|
+
# Update each project's MCP configurations
|
492
|
+
for project_key in projects_to_update:
|
493
|
+
project_config = claude_config["projects"][project_key]
|
494
|
+
|
495
|
+
# Ensure mcpServers section exists
|
496
|
+
if "mcpServers" not in project_config:
|
497
|
+
project_config["mcpServers"] = {}
|
498
|
+
updated = True
|
499
|
+
|
500
|
+
# Check and fix each service configuration
|
501
|
+
for service_name in self.PIPX_SERVICES:
|
502
|
+
# Get the correct static configuration
|
503
|
+
correct_config = self.STATIC_MCP_CONFIGS[service_name].copy()
|
504
|
+
|
505
|
+
# Special handling for mcp-vector-search: replace {project_root} placeholder
|
506
|
+
if service_name == "mcp-vector-search":
|
507
|
+
# Use the project key as the project root for each project
|
508
|
+
correct_config["args"] = [
|
509
|
+
arg.replace("{project_root}", project_key) if "{project_root}" in arg else arg
|
510
|
+
for arg in correct_config["args"]
|
511
|
+
]
|
512
|
+
|
513
|
+
# Check if service exists and has correct configuration
|
514
|
+
existing_config = project_config["mcpServers"].get(service_name)
|
515
|
+
|
516
|
+
# Determine if we need to update
|
517
|
+
needs_update = False
|
518
|
+
if not existing_config:
|
519
|
+
# Service is missing
|
520
|
+
needs_update = True
|
521
|
+
added_services.append(f"{service_name} in {Path(project_key).name}")
|
435
522
|
else:
|
523
|
+
# Service exists, check if configuration is correct
|
524
|
+
# Compare command and args (the most critical parts)
|
525
|
+
if (existing_config.get("command") != correct_config.get("command") or
|
526
|
+
existing_config.get("args") != correct_config.get("args")):
|
527
|
+
needs_update = True
|
528
|
+
fixed_services.append(f"{service_name} in {Path(project_key).name}")
|
529
|
+
|
530
|
+
# Update configuration if needed
|
531
|
+
if needs_update:
|
532
|
+
project_config["mcpServers"][service_name] = correct_config
|
533
|
+
updated = True
|
436
534
|
self.logger.debug(
|
437
|
-
f"MCP service {service_name}
|
535
|
+
f"Updated MCP service config for {service_name} in project {Path(project_key).name}"
|
438
536
|
)
|
439
537
|
|
440
538
|
# Write updated config if changes were made
|
@@ -448,7 +546,6 @@ class MCPConfigManager:
|
|
448
546
|
f".backup.{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}.json"
|
449
547
|
)
|
450
548
|
import shutil
|
451
|
-
|
452
549
|
shutil.copy2(self.claude_config_path, backup_path)
|
453
550
|
self.logger.debug(f"Created backup: {backup_path}")
|
454
551
|
|
@@ -456,18 +553,20 @@ class MCPConfigManager:
|
|
456
553
|
with open(self.claude_config_path, "w") as f:
|
457
554
|
json.dump(claude_config, f, indent=2)
|
458
555
|
|
556
|
+
messages = []
|
459
557
|
if added_services:
|
460
|
-
|
461
|
-
|
462
|
-
)
|
463
|
-
|
464
|
-
|
465
|
-
|
558
|
+
messages.append(f"Added MCP services: {', '.join(added_services[:3])}")
|
559
|
+
if fixed_services:
|
560
|
+
messages.append(f"Fixed MCP services: {', '.join(fixed_services[:3])}")
|
561
|
+
|
562
|
+
if messages:
|
563
|
+
return True, "; ".join(messages)
|
564
|
+
return True, "All MCP services already configured correctly"
|
466
565
|
except Exception as e:
|
467
566
|
self.logger.error(f"Failed to write Claude config: {e}")
|
468
567
|
return False, f"Failed to write configuration: {e}"
|
469
568
|
|
470
|
-
return True, "All MCP services already configured"
|
569
|
+
return True, "All MCP services already configured correctly"
|
471
570
|
|
472
571
|
def update_mcp_config(self, force_pipx: bool = True) -> Tuple[bool, str]:
|
473
572
|
"""
|
@@ -695,6 +794,49 @@ class MCPConfigManager:
|
|
695
794
|
|
696
795
|
return False, "none"
|
697
796
|
|
797
|
+
def _check_and_fix_mcp_ticketer_dependencies(self) -> bool:
|
798
|
+
"""Check and fix mcp-ticketer missing gql dependency.
|
799
|
+
|
800
|
+
Note: This is a workaround for mcp-ticketer <= 0.1.8 which is missing
|
801
|
+
the gql dependency in its package metadata. Future versions (> 0.1.8)
|
802
|
+
should include 'gql[httpx]>=3.0.0' as a dependency, making this fix
|
803
|
+
unnecessary. We keep this for backward compatibility with older versions.
|
804
|
+
"""
|
805
|
+
try:
|
806
|
+
# Test if gql is available in mcp-ticketer's environment
|
807
|
+
test_result = subprocess.run(
|
808
|
+
["pipx", "run", "--spec", "mcp-ticketer", "python", "-c", "import gql"],
|
809
|
+
capture_output=True,
|
810
|
+
text=True,
|
811
|
+
timeout=5,
|
812
|
+
check=False,
|
813
|
+
)
|
814
|
+
|
815
|
+
# If import fails, inject the dependency
|
816
|
+
if test_result.returncode != 0:
|
817
|
+
self.logger.info("🔧 mcp-ticketer missing gql dependency, fixing...")
|
818
|
+
|
819
|
+
inject_result = subprocess.run(
|
820
|
+
["pipx", "inject", "mcp-ticketer", "gql"],
|
821
|
+
capture_output=True,
|
822
|
+
text=True,
|
823
|
+
timeout=30,
|
824
|
+
check=False,
|
825
|
+
)
|
826
|
+
|
827
|
+
if inject_result.returncode == 0:
|
828
|
+
self.logger.info("✅ Successfully injected gql dependency into mcp-ticketer")
|
829
|
+
return True
|
830
|
+
else:
|
831
|
+
self.logger.warning(f"Failed to inject gql: {inject_result.stderr}")
|
832
|
+
return False
|
833
|
+
|
834
|
+
return False
|
835
|
+
|
836
|
+
except Exception as e:
|
837
|
+
self.logger.debug(f"Could not check/fix mcp-ticketer dependencies: {e}")
|
838
|
+
return False
|
839
|
+
|
698
840
|
def _verify_service_installed(self, service_name: str, method: str) -> bool:
|
699
841
|
"""
|
700
842
|
Verify that a service was successfully installed and is functional.
|
@@ -711,6 +853,9 @@ class MCPConfigManager:
|
|
711
853
|
# Give the installation a moment to settle
|
712
854
|
time.sleep(1)
|
713
855
|
|
856
|
+
# Note: mcp-ticketer dependency fix is now handled once in ensure_mcp_services_configured()
|
857
|
+
# to avoid running the same pipx inject command multiple times
|
858
|
+
|
714
859
|
# Check if we can find the service
|
715
860
|
service_path = self.detect_service_path(service_name)
|
716
861
|
if not service_path:
|
@@ -1,5 +1,5 @@
|
|
1
1
|
claude_mpm/BUILD_NUMBER,sha256=toytnNjkIKPgQaGwDqQdC1rpNTAdSEc6Vja50d7Ovug,4
|
2
|
-
claude_mpm/VERSION,sha256=
|
2
|
+
claude_mpm/VERSION,sha256=k8-5xMoy2UlbzZa4MVGVy1j0Ym4rIg_47OvMJE5eNKg,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
|
@@ -383,25 +383,12 @@ claude_mpm/hooks/claude_hooks/installer.py,sha256=4QUZcnQWlQDH11BypvYs_JpQ-ojRF0
|
|
383
383
|
claude_mpm/hooks/claude_hooks/memory_integration.py,sha256=9PogijgklM7iSNRTK2Sdz3s9AOlxL8Rt5axtU71-J2M,8866
|
384
384
|
claude_mpm/hooks/claude_hooks/response_tracking.py,sha256=eMixPs2fOAqLn9WysTPgfIwwjwzZTdnAn0jpDjlOS6U,15024
|
385
385
|
claude_mpm/hooks/claude_hooks/tool_analysis.py,sha256=t4CFrLldjD-akBY52su6Cl0cBmZCKRZbGbIE-Yg2Hhk,7896
|
386
|
-
claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc,sha256=bRXmkaVByqCv8qmFpfSJOEeKUOzLNgFVgFc5GVZ1oGo,322
|
387
|
-
claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc,sha256=W3pUVNdaDSE0ndQmQUSnGlBWaxOVnvjvZxCcmjLag-0,28937
|
388
|
-
claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc,sha256=HTbwMv0BW8gMg9DxzH6UbEPRPZ8a0e_R7sNaRMJ6I1w,21336
|
389
|
-
claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-313.pyc,sha256=xUXfgAB_3qc52cTpL8UgsO_xaplQ0v-yhI4pJLUBDF8,29046
|
390
|
-
claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc,sha256=qhDYC403V_m8NG2LHMXtcK_SH3qMuPADSp0sJ9D6YTo,8895
|
391
|
-
claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc,sha256=MuqyPvXZuFph_xp1j1vtNLqLKRJT51oI2AmZ3SEn69c,14213
|
392
|
-
claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc,sha256=OsljgmGIgSmKTyVRRrJmKvmoHdQFq0kBBGTRUrAdnrI,9137
|
393
386
|
claude_mpm/hooks/claude_hooks/services/__init__.py,sha256=OIYOKsUNw1BHYawOCp-KFK5kmQKuj92cCqCEPO0nwo0,585
|
394
387
|
claude_mpm/hooks/claude_hooks/services/connection_manager.py,sha256=6GSZ6lB0j6u7jE-w9ay-57YX-VVBFGfK_wmZNNM6hxE,8280
|
395
388
|
claude_mpm/hooks/claude_hooks/services/connection_manager_http.py,sha256=sEIWyV-3pfS6VM6_jQgnrKiepD-6DLrk5rr_KU80kHo,8832
|
396
389
|
claude_mpm/hooks/claude_hooks/services/duplicate_detector.py,sha256=Fh9LmEMsVmQM9t0U1v2l_fuBwvNpVkl_0EF8Wu5KLHQ,3882
|
397
390
|
claude_mpm/hooks/claude_hooks/services/state_manager.py,sha256=l50dVFt6eafeLCjlu6TH3qqt8tTBEof971U1OlrUxZ8,11166
|
398
391
|
claude_mpm/hooks/claude_hooks/services/subagent_processor.py,sha256=f7a_vgo_kuG9MalDTka2UPXwDyCkqNgCvG8i1hp0oRo,15263
|
399
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc,sha256=bk04TMdGscqiVyfzkby3gPrW6DcSqzHJOCnclbO5Qrs,565
|
400
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-313.pyc,sha256=xEEOqJmCwu_rOaZTzfYdLQtamwrlvn_Uv4M9GcTJeIA,8713
|
401
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc,sha256=HvK-KUCBSg8J_0UTxNd98pMVa68_NYRkyoTgdATD_n4,9967
|
402
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc,sha256=87ROjkadSdZB1L24rVdjdOHggYRfaGZ2v0nnhLlUnJk,4722
|
403
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc,sha256=QoAQvuBn4xDlo_YXuHNgJ3vqXLhp4KzKunTOf9crJ70,11772
|
404
|
-
claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc,sha256=svC-kX-MYT5YIbWrY_aNf-Biz-JL49noI--1D-dSx_Q,13821
|
405
392
|
claude_mpm/models/__init__.py,sha256=GADyLAiF-1VVghYKI7Urz3zSnf2sjJUXlOEMuCOs7_g,468
|
406
393
|
claude_mpm/models/agent_definition.py,sha256=LC7EwihixF2Gw4QqOxiCNchsEzzyQJPR6AgPrcTrWTM,6674
|
407
394
|
claude_mpm/models/agent_session.py,sha256=BEI9RsCnnSVMF3oOzWKY3a_NEmWI33J2nU_2O-WEyJQ,20027
|
@@ -424,7 +411,7 @@ claude_mpm/services/event_aggregator.py,sha256=DDcehIZVpiEDzs9o18gDZyvjMBHCq2H8H
|
|
424
411
|
claude_mpm/services/exceptions.py,sha256=5lVZETr_6-xk0ItH7BTfYUiX5RlckS1e8ah_UalYG9c,26475
|
425
412
|
claude_mpm/services/hook_installer_service.py,sha256=z3kKeriEY1Y9bFesuGlHBxhCtc0Wzd3Zv02k2_rEyGo,19727
|
426
413
|
claude_mpm/services/hook_service.py,sha256=rZnMn_4qxX5g9KAn0IQdoG50WmySNfsTmfG0XHuRHXk,15737
|
427
|
-
claude_mpm/services/mcp_config_manager.py,sha256=
|
414
|
+
claude_mpm/services/mcp_config_manager.py,sha256=iEBnl9rPFR-PccOol8ZdufyCvhZvVN47wYtTteQVpBY,35112
|
428
415
|
claude_mpm/services/mcp_service_verifier.py,sha256=ngiegCngX18AFehfyJdvqQAvscoIBvFN_DeOoGTjxj0,25164
|
429
416
|
claude_mpm/services/memory_hook_service.py,sha256=pRlTClkRcw30Jhwbha4BC8IMdzKZxF8aWqf52JlntgY,11600
|
430
417
|
claude_mpm/services/monitor_build_service.py,sha256=8gWR9CaqgXdG6-OjOFXGpk28GCcJTlHhojkUYnMCebI,12160
|
@@ -573,7 +560,7 @@ claude_mpm/services/diagnostics/checks/filesystem_check.py,sha256=V5HoHDYlSuoK2l
|
|
573
560
|
claude_mpm/services/diagnostics/checks/installation_check.py,sha256=WoTt15R8Wg-6k2JZFAtmffFuih1AIyCX71QOHEFH-Ro,19562
|
574
561
|
claude_mpm/services/diagnostics/checks/instructions_check.py,sha256=VbgBorl0RpFvxKQ_SC1gibTmGSiXaKSp-vVZt6hbH1g,16290
|
575
562
|
claude_mpm/services/diagnostics/checks/mcp_check.py,sha256=SftuhP70abopyMD8GlLA_K3XHEYnBAeITggUQI0cYP4,12173
|
576
|
-
claude_mpm/services/diagnostics/checks/mcp_services_check.py,sha256=
|
563
|
+
claude_mpm/services/diagnostics/checks/mcp_services_check.py,sha256=SrHdpRbEc62e7mkfC_m8aGFtQIkhNOmiiCQZ78MME98,40800
|
577
564
|
claude_mpm/services/diagnostics/checks/monitor_check.py,sha256=NUx5G1yjHWlukZmwhUz4o8STRWgsQEx01YjIMReNC0A,10096
|
578
565
|
claude_mpm/services/diagnostics/checks/startup_log_check.py,sha256=DrXdml2rHvmhFBdb_sntE3xmwaP_DZIKjdVbCn8Dy7E,12258
|
579
566
|
claude_mpm/services/event_bus/__init__.py,sha256=ETCo4a6puIeyVWAv55uCDjjhzNyUwbVAHEcAVkVapx8,688
|
@@ -786,9 +773,9 @@ claude_mpm/utils/subprocess_utils.py,sha256=D0izRT8anjiUb_JG72zlJR_JAw1cDkb7kalN
|
|
786
773
|
claude_mpm/validation/__init__.py,sha256=YZhwE3mhit-lslvRLuwfX82xJ_k4haZeKmh4IWaVwtk,156
|
787
774
|
claude_mpm/validation/agent_validator.py,sha256=Nm2WmcbCb0EwOG4nFcikc3wVdiiAfjGBBI3YoR6ainQ,20915
|
788
775
|
claude_mpm/validation/frontmatter_validator.py,sha256=IDBOCBweO6umydSnUJjBh81sKk3cy9hRFYm61DCiXbI,7020
|
789
|
-
claude_mpm-4.4.
|
790
|
-
claude_mpm-4.4.
|
791
|
-
claude_mpm-4.4.
|
792
|
-
claude_mpm-4.4.
|
793
|
-
claude_mpm-4.4.
|
794
|
-
claude_mpm-4.4.
|
776
|
+
claude_mpm-4.4.9.dist-info/licenses/LICENSE,sha256=lpaivOlPuBZW1ds05uQLJJswy8Rp_HMNieJEbFlqvLk,1072
|
777
|
+
claude_mpm-4.4.9.dist-info/METADATA,sha256=RSN3ddmTCsiu9uTUoaSFYFeB7O56BR7awyIOpLkSVsA,17517
|
778
|
+
claude_mpm-4.4.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
779
|
+
claude_mpm-4.4.9.dist-info/entry_points.txt,sha256=FDPZgz8JOvD-6iuXY2l9Zbo9zYVRuE4uz4Qr0vLeGOk,471
|
780
|
+
claude_mpm-4.4.9.dist-info/top_level.txt,sha256=1nUg3FEaBySgm8t-s54jK5zoPnu3_eY6EP6IOlekyHA,11
|
781
|
+
claude_mpm-4.4.9.dist-info/RECORD,,
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|