claude-mpm 4.5.11__py3-none-any.whl → 4.5.13__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/BASE_ENGINEER.md +47 -0
- claude_mpm/agents/BASE_QA.md +60 -0
- claude_mpm/agents/frontmatter_validator.py +4 -4
- claude_mpm/agents/templates/nextjs_engineer.json +2 -2
- claude_mpm/agents/templates/qa.json +13 -3
- claude_mpm/agents/templates/react_engineer.json +2 -2
- claude_mpm/agents/templates/typescript_engineer.json +2 -2
- claude_mpm/agents/templates/web_qa.json +14 -3
- claude_mpm/cli/commands/agent_manager.py +3 -3
- claude_mpm/cli/commands/agents.py +6 -6
- claude_mpm/cli/commands/aggregate.py +4 -4
- claude_mpm/cli/commands/analyze.py +2 -2
- claude_mpm/cli/commands/analyze_code.py +1 -1
- claude_mpm/cli/commands/cleanup.py +3 -3
- claude_mpm/cli/commands/config.py +2 -2
- claude_mpm/cli/commands/configure.py +14 -14
- claude_mpm/cli/commands/dashboard.py +1 -1
- claude_mpm/cli/commands/debug.py +3 -3
- claude_mpm/cli/commands/doctor.py +1 -1
- claude_mpm/cli/commands/mcp.py +7 -7
- claude_mpm/cli/commands/mcp_command_router.py +1 -1
- claude_mpm/cli/commands/mcp_config.py +2 -2
- claude_mpm/cli/commands/mcp_external_commands.py +2 -2
- claude_mpm/cli/commands/mcp_install_commands.py +3 -3
- claude_mpm/cli/commands/mcp_pipx_config.py +2 -2
- claude_mpm/cli/commands/mcp_setup_external.py +3 -3
- claude_mpm/cli/commands/monitor.py +1 -1
- claude_mpm/cli/commands/mpm_init_handler.py +1 -1
- claude_mpm/cli/interactive/agent_wizard.py +1 -1
- claude_mpm/cli/parsers/search_parser.py +1 -1
- claude_mpm/cli/shared/argument_patterns.py +2 -2
- claude_mpm/cli/shared/base_command.py +1 -1
- claude_mpm/cli/startup_logging.py +6 -4
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/socketio_config.py +2 -2
- claude_mpm/core/agent_session_manager.py +2 -2
- claude_mpm/core/api_validator.py +3 -3
- claude_mpm/core/base_service.py +10 -1
- claude_mpm/core/cache.py +2 -2
- claude_mpm/core/config.py +4 -4
- claude_mpm/core/config_aliases.py +4 -4
- claude_mpm/core/config_constants.py +1 -1
- claude_mpm/core/error_handler.py +1 -1
- claude_mpm/core/file_utils.py +5 -5
- claude_mpm/core/framework/formatters/capability_generator.py +5 -5
- claude_mpm/core/framework/loaders/agent_loader.py +1 -1
- claude_mpm/core/framework/processors/metadata_processor.py +1 -1
- claude_mpm/core/framework/processors/template_processor.py +3 -3
- claude_mpm/core/framework_loader.py +2 -2
- claude_mpm/core/log_manager.py +4 -4
- claude_mpm/core/logger.py +2 -2
- claude_mpm/core/optimized_startup.py +1 -1
- claude_mpm/core/output_style_manager.py +1 -1
- claude_mpm/core/service_registry.py +2 -2
- claude_mpm/core/session_manager.py +3 -3
- claude_mpm/core/shared/config_loader.py +1 -1
- claude_mpm/core/socketio_pool.py +2 -2
- claude_mpm/core/unified_agent_registry.py +2 -2
- claude_mpm/core/unified_config.py +6 -6
- claude_mpm/core/unified_paths.py +2 -2
- claude_mpm/dashboard/api/simple_directory.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +1 -1
- claude_mpm/hooks/claude_hooks/event_handlers.py +2 -2
- claude_mpm/hooks/claude_hooks/installer.py +9 -9
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +7 -2
- claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/hooks/validation_hooks.py +1 -1
- claude_mpm/init.py +4 -4
- claude_mpm/models/agent_session.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +5 -5
- claude_mpm/services/__init__.py +2 -2
- claude_mpm/services/agent_capabilities_service.py +1 -1
- claude_mpm/services/agents/agent_builder.py +6 -4
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +3 -3
- claude_mpm/services/agents/deployment/deployment_wrapper.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +2 -2
- claude_mpm/services/agents/local_template_manager.py +5 -5
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
- claude_mpm/services/agents/registry/modification_tracker.py +19 -11
- claude_mpm/services/async_session_logger.py +1 -1
- claude_mpm/services/claude_session_logger.py +1 -1
- claude_mpm/services/cli/agent_listing_service.py +3 -3
- claude_mpm/services/cli/agent_validation_service.py +1 -1
- claude_mpm/services/cli/session_manager.py +2 -2
- claude_mpm/services/core/path_resolver.py +1 -1
- claude_mpm/services/diagnostics/checks/agent_check.py +1 -1
- claude_mpm/services/diagnostics/checks/claude_code_check.py +2 -2
- claude_mpm/services/diagnostics/checks/common_issues_check.py +3 -3
- claude_mpm/services/diagnostics/checks/configuration_check.py +2 -2
- claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
- claude_mpm/services/diagnostics/checks/mcp_check.py +1 -1
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +9 -9
- claude_mpm/services/diagnostics/checks/monitor_check.py +1 -1
- claude_mpm/services/diagnostics/doctor_reporter.py +1 -1
- claude_mpm/services/event_aggregator.py +1 -1
- claude_mpm/services/event_bus/event_bus.py +9 -2
- claude_mpm/services/events/consumers/dead_letter.py +2 -2
- claude_mpm/services/framework_claude_md_generator/__init__.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +3 -3
- claude_mpm/services/framework_claude_md_generator/version_manager.py +1 -1
- claude_mpm/services/hook_installer_service.py +7 -7
- claude_mpm/services/infrastructure/context_preservation.py +7 -7
- claude_mpm/services/infrastructure/daemon_manager.py +5 -5
- claude_mpm/services/mcp_config_manager.py +10 -10
- claude_mpm/services/mcp_gateway/auto_configure.py +5 -5
- claude_mpm/services/mcp_gateway/config/config_loader.py +2 -2
- claude_mpm/services/mcp_gateway/config/configuration.py +5 -3
- claude_mpm/services/mcp_gateway/core/process_pool.py +3 -3
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +2 -2
- claude_mpm/services/mcp_gateway/core/startup_verification.py +1 -1
- claude_mpm/services/mcp_gateway/main.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +4 -2
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +2 -1
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +1 -1
- claude_mpm/services/mcp_gateway/tools/hello_world.py +1 -1
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +5 -5
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +2 -2
- claude_mpm/services/mcp_service_verifier.py +1 -1
- claude_mpm/services/memory/builder.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +2 -1
- claude_mpm/services/memory/indexed_memory.py +3 -3
- claude_mpm/services/monitor/daemon.py +1 -1
- claude_mpm/services/monitor/daemon_manager.py +9 -9
- claude_mpm/services/monitor/handlers/file.py +1 -1
- claude_mpm/services/monitor/handlers/hooks.py +3 -3
- claude_mpm/services/monitor/management/lifecycle.py +7 -7
- claude_mpm/services/monitor/server.py +2 -2
- claude_mpm/services/orphan_detection.py +11 -16
- claude_mpm/services/port_manager.py +2 -2
- claude_mpm/services/project/analyzer.py +3 -3
- claude_mpm/services/project/archive_manager.py +17 -13
- claude_mpm/services/project/dependency_analyzer.py +4 -4
- claude_mpm/services/project/documentation_manager.py +4 -4
- claude_mpm/services/project/enhanced_analyzer.py +19 -8
- claude_mpm/services/project/registry.py +4 -4
- claude_mpm/services/project_port_allocator.py +7 -12
- claude_mpm/services/session_management_service.py +1 -1
- claude_mpm/services/socketio/event_normalizer.py +1 -1
- claude_mpm/services/socketio/handlers/code_analysis.py +14 -12
- claude_mpm/services/socketio/handlers/file.py +1 -1
- claude_mpm/services/socketio/migration_utils.py +1 -1
- claude_mpm/services/socketio/server/core.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +4 -4
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +1 -1
- claude_mpm/services/unified/config_strategies/config_schema.py +4 -4
- claude_mpm/services/unified/config_strategies/context_strategy.py +8 -6
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +10 -10
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +5 -5
- claude_mpm/services/unified/config_strategies/unified_config_service.py +8 -8
- claude_mpm/services/unified/config_strategies/validation_strategy.py +15 -15
- claude_mpm/services/unified/deployment_strategies/base.py +4 -4
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +15 -15
- claude_mpm/services/unified/deployment_strategies/local.py +11 -11
- claude_mpm/services/unified/deployment_strategies/utils.py +11 -9
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -9
- claude_mpm/services/unified/unified_config.py +5 -5
- claude_mpm/services/unified/unified_deployment.py +2 -2
- claude_mpm/services/utility_service.py +1 -1
- claude_mpm/services/version_control/conflict_resolution.py +2 -2
- claude_mpm/services/version_control/git_operations.py +3 -3
- claude_mpm/services/version_control/semantic_versioning.py +13 -13
- claude_mpm/services/version_control/version_parser.py +1 -1
- claude_mpm/storage/state_storage.py +12 -13
- claude_mpm/tools/code_tree_analyzer.py +5 -5
- claude_mpm/tools/code_tree_builder.py +4 -4
- claude_mpm/tools/socketio_debug.py +1 -1
- claude_mpm/utils/agent_dependency_loader.py +4 -4
- claude_mpm/utils/common.py +2 -2
- claude_mpm/utils/config_manager.py +3 -3
- claude_mpm/utils/dependency_cache.py +2 -2
- claude_mpm/utils/dependency_strategies.py +6 -6
- claude_mpm/utils/file_utils.py +11 -11
- claude_mpm/utils/log_cleanup.py +1 -1
- claude_mpm/utils/path_operations.py +1 -1
- claude_mpm/validation/agent_validator.py +2 -2
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/METADATA +1 -1
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/RECORD +190 -190
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/WHEEL +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/top_level.txt +0 -0
@@ -95,7 +95,7 @@ class DeploymentManager:
|
|
95
95
|
|
96
96
|
# Check if file exists and compare versions
|
97
97
|
if target_file.exists() and not force:
|
98
|
-
with open(
|
98
|
+
with target_file.open() as f:
|
99
99
|
existing_content = f.read()
|
100
100
|
existing_fw_ver = self.version_manager.parse_current_version(
|
101
101
|
existing_content
|
@@ -110,7 +110,7 @@ class DeploymentManager:
|
|
110
110
|
parent_path.mkdir(parents=True, exist_ok=True)
|
111
111
|
|
112
112
|
# Write content
|
113
|
-
with open(
|
113
|
+
with target_file.open("w") as f:
|
114
114
|
f.write(content)
|
115
115
|
|
116
116
|
# Get version info for success message
|
@@ -137,7 +137,7 @@ class DeploymentManager:
|
|
137
137
|
return True, f"{self.target_filename} does not exist"
|
138
138
|
|
139
139
|
try:
|
140
|
-
with open(
|
140
|
+
with target_file.open() as f:
|
141
141
|
existing_content = f.read()
|
142
142
|
existing_fw_ver = self.version_manager.parse_current_version(
|
143
143
|
existing_content
|
@@ -38,7 +38,7 @@ class VersionManager:
|
|
38
38
|
version_path = package_path.parent / "framework" / "VERSION"
|
39
39
|
|
40
40
|
if version_path.exists():
|
41
|
-
with open(
|
41
|
+
with version_path.open() as f:
|
42
42
|
version_content = f.read().strip()
|
43
43
|
# Framework VERSION file contains just the framework version number
|
44
44
|
try:
|
@@ -24,7 +24,7 @@ class HookInstallerService:
|
|
24
24
|
self.claude_dir = Path.home() / ".claude"
|
25
25
|
self.settings_file = self.claude_dir / "settings.json"
|
26
26
|
|
27
|
-
def is_hooks_configured(self) -> bool:
|
27
|
+
def is_hooks_configured(self) -> bool:
|
28
28
|
"""Check if hooks are configured in Claude settings.
|
29
29
|
|
30
30
|
Returns:
|
@@ -35,7 +35,7 @@ class HookInstallerService:
|
|
35
35
|
self.logger.debug("Claude settings file does not exist")
|
36
36
|
return False
|
37
37
|
|
38
|
-
with
|
38
|
+
with self.settings_file.open() as f:
|
39
39
|
settings = json.load(f)
|
40
40
|
|
41
41
|
# Check if hooks section exists
|
@@ -292,7 +292,7 @@ class HookInstallerService:
|
|
292
292
|
|
293
293
|
# Load existing settings or create new
|
294
294
|
if self.settings_file.exists():
|
295
|
-
with
|
295
|
+
with self.settings_file.open() as f:
|
296
296
|
settings = json.load(f)
|
297
297
|
self.logger.debug("Found existing Claude settings")
|
298
298
|
else:
|
@@ -320,7 +320,7 @@ class HookInstallerService:
|
|
320
320
|
settings["hooks"][event_type] = [hook_config]
|
321
321
|
|
322
322
|
# Write settings
|
323
|
-
with
|
323
|
+
with self.settings_file.open("w") as f:
|
324
324
|
json.dump(settings, f, indent=2)
|
325
325
|
|
326
326
|
self.logger.info(f"Updated Claude settings at: {self.settings_file}")
|
@@ -380,7 +380,7 @@ class HookInstallerService:
|
|
380
380
|
|
381
381
|
self.logger.info("Removing Claude Code hooks...")
|
382
382
|
|
383
|
-
with
|
383
|
+
with self.settings_file.open() as f:
|
384
384
|
settings = json.load(f)
|
385
385
|
|
386
386
|
hooks_removed = 0
|
@@ -422,7 +422,7 @@ class HookInstallerService:
|
|
422
422
|
del settings["hooks"]
|
423
423
|
|
424
424
|
# Write updated settings
|
425
|
-
with
|
425
|
+
with self.settings_file.open("w") as f:
|
426
426
|
json.dump(settings, f, indent=2)
|
427
427
|
|
428
428
|
if hooks_removed > 0:
|
@@ -469,7 +469,7 @@ class HookInstallerService:
|
|
469
469
|
|
470
470
|
try:
|
471
471
|
if self.settings_file.exists():
|
472
|
-
with
|
472
|
+
with self.settings_file.open() as f:
|
473
473
|
settings = json.load(f)
|
474
474
|
|
475
475
|
if "hooks" in settings:
|
@@ -151,7 +151,7 @@ class ContextPreservationService(BaseService):
|
|
151
151
|
return None
|
152
152
|
|
153
153
|
# Use streaming to find active conversation
|
154
|
-
with
|
154
|
+
with self.claude_json_path.open("rb") as f:
|
155
155
|
parser = ijson.parse(f)
|
156
156
|
|
157
157
|
active_conv_id = None
|
@@ -207,7 +207,7 @@ class ContextPreservationService(BaseService):
|
|
207
207
|
keep_recent_days * 86400
|
208
208
|
)
|
209
209
|
|
210
|
-
with
|
210
|
+
with self.claude_json_path.open() as f:
|
211
211
|
data = json.load(f)
|
212
212
|
|
213
213
|
original_count = len(data.get("conversations", []))
|
@@ -239,7 +239,7 @@ class ContextPreservationService(BaseService):
|
|
239
239
|
|
240
240
|
# Write compressed version
|
241
241
|
temp_path = self.claude_json_path.with_suffix(".tmp")
|
242
|
-
with open(
|
242
|
+
with temp_path.open("w") as f:
|
243
243
|
json.dump(data, f, separators=(",", ":")) # Compact format
|
244
244
|
|
245
245
|
# Replace original
|
@@ -316,7 +316,7 @@ class ContextPreservationService(BaseService):
|
|
316
316
|
# Use streaming to extract preferences
|
317
317
|
preferences = {}
|
318
318
|
|
319
|
-
with
|
319
|
+
with self.claude_json_path.open("rb") as f:
|
320
320
|
parser = ijson.parse(f)
|
321
321
|
|
322
322
|
for prefix, event, value in parser:
|
@@ -339,7 +339,7 @@ class ContextPreservationService(BaseService):
|
|
339
339
|
) -> ConversationState:
|
340
340
|
"""Parse Claude JSON using standard JSON parser."""
|
341
341
|
try:
|
342
|
-
with
|
342
|
+
with self.claude_json_path.open() as f:
|
343
343
|
data = json.load(f)
|
344
344
|
|
345
345
|
return await self._extract_conversation_state(data, extract_full)
|
@@ -357,7 +357,7 @@ class ContextPreservationService(BaseService):
|
|
357
357
|
preferences = {}
|
358
358
|
open_files = []
|
359
359
|
|
360
|
-
with
|
360
|
+
with self.claude_json_path.open("rb") as f:
|
361
361
|
parser = ijson.parse(f)
|
362
362
|
|
363
363
|
conversation_count = 0
|
@@ -527,7 +527,7 @@ class ContextPreservationService(BaseService):
|
|
527
527
|
backup_name += ".gz"
|
528
528
|
backup_path = self.claude_backup_dir / backup_name
|
529
529
|
|
530
|
-
with
|
530
|
+
with self.claude_json_path.open("rb") as f_in:
|
531
531
|
with gzip.open(backup_path, "wb") as f_out:
|
532
532
|
shutil.copyfileobj(f_in, f_out)
|
533
533
|
else:
|
@@ -80,7 +80,7 @@ class SocketIODaemonManager:
|
|
80
80
|
return False
|
81
81
|
|
82
82
|
try:
|
83
|
-
with
|
83
|
+
with self.pid_file.open() as f:
|
84
84
|
pid = int(f.read().strip())
|
85
85
|
|
86
86
|
# Check if process exists and is running
|
@@ -135,7 +135,7 @@ class SocketIODaemonManager:
|
|
135
135
|
pid = os.fork()
|
136
136
|
if pid > 0:
|
137
137
|
# Parent process - save PID and exit
|
138
|
-
with
|
138
|
+
with self.pid_file.open("w") as f:
|
139
139
|
f.write(str(pid))
|
140
140
|
logger.info(f"Socket.IO server started as daemon (PID: {pid})")
|
141
141
|
return True
|
@@ -155,7 +155,7 @@ class SocketIODaemonManager:
|
|
155
155
|
os.umask(0)
|
156
156
|
|
157
157
|
# Redirect stdout/stderr to log file
|
158
|
-
with
|
158
|
+
with self.log_file.open("a") as log:
|
159
159
|
os.dup2(log.fileno(), sys.stdout.fileno())
|
160
160
|
os.dup2(log.fileno(), sys.stderr.fileno())
|
161
161
|
|
@@ -199,7 +199,7 @@ class SocketIODaemonManager:
|
|
199
199
|
return False
|
200
200
|
|
201
201
|
try:
|
202
|
-
with
|
202
|
+
with self.pid_file.open() as f:
|
203
203
|
pid = int(f.read().strip())
|
204
204
|
|
205
205
|
logger.info(f"Stopping Socket.IO server (PID: {pid})")
|
@@ -254,7 +254,7 @@ class SocketIODaemonManager:
|
|
254
254
|
}
|
255
255
|
|
256
256
|
if status_info["running"]:
|
257
|
-
with
|
257
|
+
with self.pid_file.open() as f:
|
258
258
|
status_info["pid"] = int(f.read().strip())
|
259
259
|
|
260
260
|
# Check port accessibility
|
@@ -199,7 +199,7 @@ class MCPConfigManager:
|
|
199
199
|
f"Found kuzu-memory with MCP support at {path}"
|
200
200
|
)
|
201
201
|
return path
|
202
|
-
except:
|
202
|
+
except (subprocess.SubprocessError, subprocess.TimeoutExpired, OSError):
|
203
203
|
pass
|
204
204
|
|
205
205
|
# If no MCP-capable version found, log warning but return None
|
@@ -571,7 +571,7 @@ class MCPConfigManager:
|
|
571
571
|
if result.returncode == 0 or "version" in result.stdout.lower():
|
572
572
|
use_pipx_run = True
|
573
573
|
self.logger.debug(f"Will use 'pipx run' for {service_name}")
|
574
|
-
except:
|
574
|
+
except (subprocess.SubprocessError, subprocess.TimeoutExpired, OSError):
|
575
575
|
pass
|
576
576
|
|
577
577
|
# Try uvx if pipx run not available
|
@@ -587,7 +587,7 @@ class MCPConfigManager:
|
|
587
587
|
if result.returncode == 0 or "version" in result.stdout.lower():
|
588
588
|
use_uvx = True
|
589
589
|
self.logger.debug(f"Will use 'uvx' for {service_name}")
|
590
|
-
except:
|
590
|
+
except (subprocess.SubprocessError, subprocess.TimeoutExpired, OSError):
|
591
591
|
pass
|
592
592
|
|
593
593
|
# If neither work, try to find direct path
|
@@ -719,7 +719,7 @@ class MCPConfigManager:
|
|
719
719
|
claude_config = {}
|
720
720
|
if self.claude_config_path.exists():
|
721
721
|
try:
|
722
|
-
with
|
722
|
+
with self.claude_config_path.open() as f:
|
723
723
|
claude_config = json.load(f)
|
724
724
|
except Exception as e:
|
725
725
|
self.logger.error(f"Error reading {self.claude_config_path}: {e}")
|
@@ -832,7 +832,7 @@ class MCPConfigManager:
|
|
832
832
|
self.logger.debug(f"Created backup: {backup_path}")
|
833
833
|
|
834
834
|
# Write updated config
|
835
|
-
with
|
835
|
+
with self.claude_config_path.open("w") as f:
|
836
836
|
json.dump(claude_config, f, indent=2)
|
837
837
|
|
838
838
|
messages = []
|
@@ -884,7 +884,7 @@ class MCPConfigManager:
|
|
884
884
|
existing_config = {}
|
885
885
|
if mcp_config_path.exists():
|
886
886
|
try:
|
887
|
-
with open(
|
887
|
+
with mcp_config_path.open() as f:
|
888
888
|
existing_config = json.load(f)
|
889
889
|
except Exception as e:
|
890
890
|
self.logger.error(f"Error reading existing config: {e}")
|
@@ -912,7 +912,7 @@ class MCPConfigManager:
|
|
912
912
|
|
913
913
|
# Write the updated configuration
|
914
914
|
try:
|
915
|
-
with open(
|
915
|
+
with mcp_config_path.open("w") as f:
|
916
916
|
json.dump(new_config, f, indent=2)
|
917
917
|
|
918
918
|
if missing_services:
|
@@ -937,7 +937,7 @@ class MCPConfigManager:
|
|
937
937
|
mcp_config_path = self.project_root / ConfigLocation.PROJECT_MCP.value
|
938
938
|
if mcp_config_path.exists():
|
939
939
|
try:
|
940
|
-
with open(
|
940
|
+
with mcp_config_path.open() as f:
|
941
941
|
config = json.load(f)
|
942
942
|
results = {}
|
943
943
|
for service_name, service_config in config.get(
|
@@ -951,7 +951,7 @@ class MCPConfigManager:
|
|
951
951
|
return {}
|
952
952
|
|
953
953
|
try:
|
954
|
-
with
|
954
|
+
with self.claude_config_path.open() as f:
|
955
955
|
claude_config = json.load(f)
|
956
956
|
|
957
957
|
# Get project's MCP servers
|
@@ -1638,7 +1638,7 @@ class MCPConfigManager:
|
|
1638
1638
|
if result.returncode == 0 or "version" in result.stdout.lower():
|
1639
1639
|
self.logger.debug(f"{service_name} accessible via 'pipx run'")
|
1640
1640
|
return True
|
1641
|
-
except:
|
1641
|
+
except (subprocess.SubprocessError, subprocess.TimeoutExpired, OSError):
|
1642
1642
|
pass
|
1643
1643
|
return False
|
1644
1644
|
|
@@ -78,7 +78,7 @@ class MCPAutoConfigurator:
|
|
78
78
|
return False
|
79
79
|
|
80
80
|
try:
|
81
|
-
with
|
81
|
+
with self.claude_config_path.open() as f:
|
82
82
|
config = json.load(f)
|
83
83
|
|
84
84
|
# Check if claude-mpm-gateway is configured
|
@@ -131,7 +131,7 @@ class MCPAutoConfigurator:
|
|
131
131
|
return False
|
132
132
|
|
133
133
|
try:
|
134
|
-
with
|
134
|
+
with self.preference_file.open() as f:
|
135
135
|
prefs = json.load(f)
|
136
136
|
return prefs.get("asked", False)
|
137
137
|
except (OSError, json.JSONDecodeError):
|
@@ -148,7 +148,7 @@ class MCPAutoConfigurator:
|
|
148
148
|
}
|
149
149
|
|
150
150
|
try:
|
151
|
-
with
|
151
|
+
with self.preference_file.open("w") as f:
|
152
152
|
json.dump(prefs, f, indent=2)
|
153
153
|
except Exception as e:
|
154
154
|
self.logger.debug(f"Could not save preference: {e}")
|
@@ -244,7 +244,7 @@ class MCPAutoConfigurator:
|
|
244
244
|
}
|
245
245
|
|
246
246
|
# Save configuration
|
247
|
-
with
|
247
|
+
with self.claude_config_path.open("w") as f:
|
248
248
|
json.dump(config, f, indent=2)
|
249
249
|
|
250
250
|
print(f"✅ Configuration saved to: {self.claude_config_path}")
|
@@ -284,7 +284,7 @@ class MCPAutoConfigurator:
|
|
284
284
|
"""Load existing config or create new one."""
|
285
285
|
if self.claude_config_path.exists():
|
286
286
|
try:
|
287
|
-
with
|
287
|
+
with self.claude_config_path.open() as f:
|
288
288
|
return json.load(f)
|
289
289
|
except json.JSONDecodeError:
|
290
290
|
self.logger.warning("Existing config is invalid JSON, creating new")
|
@@ -97,7 +97,7 @@ class MCPConfigLoader:
|
|
97
97
|
self.logger.error(f"Configuration file not found: {expanded_path}")
|
98
98
|
return None
|
99
99
|
|
100
|
-
with open(
|
100
|
+
with expanded_path.open() as f:
|
101
101
|
config = yaml.safe_load(f)
|
102
102
|
|
103
103
|
self.logger.info(f"Configuration loaded from {expanded_path}")
|
@@ -271,7 +271,7 @@ class MCPConfigLoader:
|
|
271
271
|
expanded_path = path.expanduser()
|
272
272
|
expanded_path.parent.mkdir(parents=True, exist_ok=True)
|
273
273
|
|
274
|
-
with open(
|
274
|
+
with expanded_path.open("w") as f:
|
275
275
|
yaml.dump(
|
276
276
|
MCPConfiguration.DEFAULT_CONFIG,
|
277
277
|
f,
|
@@ -155,7 +155,7 @@ class MCPConfiguration(BaseMCPService, IMCPConfiguration):
|
|
155
155
|
self.log_warning(f"Configuration file not found: {config_path}")
|
156
156
|
return True # Not an error, use defaults
|
157
157
|
|
158
|
-
with open(
|
158
|
+
with config_path.open() as f:
|
159
159
|
if config_path.suffix in [".yaml", ".yml"]:
|
160
160
|
loaded_config = yaml.safe_load(f) or {}
|
161
161
|
else:
|
@@ -171,7 +171,9 @@ class MCPConfiguration(BaseMCPService, IMCPConfiguration):
|
|
171
171
|
return True
|
172
172
|
|
173
173
|
except yaml.YAMLError as e:
|
174
|
-
raise MCPConfigurationError(
|
174
|
+
raise MCPConfigurationError(
|
175
|
+
f"Failed to parse YAML configuration: {e}"
|
176
|
+
) from e
|
175
177
|
except Exception as e:
|
176
178
|
self.log_error(f"Failed to load configuration: {e}")
|
177
179
|
return False
|
@@ -364,7 +366,7 @@ class MCPConfiguration(BaseMCPService, IMCPConfiguration):
|
|
364
366
|
save_path = Path(save_path).expanduser()
|
365
367
|
save_path.parent.mkdir(parents=True, exist_ok=True)
|
366
368
|
|
367
|
-
with open(
|
369
|
+
with save_path.open("w") as f:
|
368
370
|
yaml.dump(
|
369
371
|
self._config_data, f, default_flow_style=False, sort_keys=True
|
370
372
|
)
|
@@ -190,7 +190,7 @@ class MCPProcessPool:
|
|
190
190
|
|
191
191
|
# Write process info to file for debugging
|
192
192
|
info_file = self.pool_dir / f"{server_name}_{process.pid}.json"
|
193
|
-
with open(
|
193
|
+
with info_file.open("w") as f:
|
194
194
|
json.dump(self._process_info[server_name], f, indent=2)
|
195
195
|
|
196
196
|
return process
|
@@ -934,7 +934,7 @@ async def pre_warm_mcp_servers():
|
|
934
934
|
#
|
935
935
|
# if claude_config_path.exists():
|
936
936
|
# try:
|
937
|
-
# with open(
|
937
|
+
# with claude_config_path.open() as f:
|
938
938
|
# config_data = json.load(f)
|
939
939
|
# mcp_servers = config_data.get("mcpServers", {})
|
940
940
|
# configs.update(mcp_servers)
|
@@ -945,7 +945,7 @@ async def pre_warm_mcp_servers():
|
|
945
945
|
# mcp_config_path = Path.cwd() / ".mcp.json"
|
946
946
|
# if mcp_config_path.exists():
|
947
947
|
# try:
|
948
|
-
# with open(
|
948
|
+
# with mcp_config_path.open() as f:
|
949
949
|
# config_data = json.load(f)
|
950
950
|
# mcp_servers = config_data.get("mcpServers", {})
|
951
951
|
# configs.update(mcp_servers)
|
@@ -149,7 +149,7 @@ class MCPGatewayManager:
|
|
149
149
|
return None
|
150
150
|
|
151
151
|
try:
|
152
|
-
with
|
152
|
+
with self.instance_file.open() as f:
|
153
153
|
instance_info = json.load(f)
|
154
154
|
|
155
155
|
# Validate PID is still running
|
@@ -195,7 +195,7 @@ class MCPGatewayManager:
|
|
195
195
|
"lock_file": str(self.lock_file),
|
196
196
|
}
|
197
197
|
|
198
|
-
with
|
198
|
+
with self.instance_file.open("w") as f:
|
199
199
|
json.dump(instance_info, f, indent=2)
|
200
200
|
|
201
201
|
self._current_instance = instance_info
|
@@ -63,7 +63,7 @@ except ImportError:
|
|
63
63
|
try:
|
64
64
|
from claude_mpm.services.mcp_gateway.server.mcp_gateway import MCPGateway
|
65
65
|
except ImportError as e:
|
66
|
-
raise ImportError(f"Critical: Cannot import MCPGateway server: {e}")
|
66
|
+
raise ImportError(f"Critical: Cannot import MCPGateway server: {e}") from e
|
67
67
|
|
68
68
|
try:
|
69
69
|
from claude_mpm.services.mcp_gateway.server.stdio_handler import StdioHandler
|
@@ -224,7 +224,8 @@ class MCPServiceRegistry(ManagerBase):
|
|
224
224
|
try:
|
225
225
|
import asyncio
|
226
226
|
|
227
|
-
asyncio.create_task(instance.stop())
|
227
|
+
_task = asyncio.create_task(instance.stop()) # noqa: RUF006
|
228
|
+
# Fire-and-forget shutdown during unregister
|
228
229
|
except Exception as e:
|
229
230
|
self.logger.warning(
|
230
231
|
f"Error stopping service {interface.__name__}: {e}"
|
@@ -335,7 +336,8 @@ class MCPServiceRegistry(ManagerBase):
|
|
335
336
|
try:
|
336
337
|
import asyncio
|
337
338
|
|
338
|
-
asyncio.create_task(instance.stop())
|
339
|
+
_task = asyncio.create_task(instance.stop()) # noqa: RUF006
|
340
|
+
# Fire-and-forget shutdown during clear
|
339
341
|
except Exception as e:
|
340
342
|
self.logger.warning(f"Error stopping service: {e}")
|
341
343
|
|
@@ -216,7 +216,8 @@ class ToolRegistry(BaseMCPService, IMCPToolRegistry):
|
|
216
216
|
|
217
217
|
# Shutdown adapter (outside lock to avoid deadlock)
|
218
218
|
try:
|
219
|
-
asyncio.create_task(adapter.shutdown())
|
219
|
+
_task = asyncio.create_task(adapter.shutdown()) # noqa: RUF006
|
220
|
+
# Fire-and-forget shutdown during tool unregister
|
220
221
|
except Exception as e:
|
221
222
|
self.log_warning(f"Error shutting down tool adapter {tool_name}: {e}")
|
222
223
|
|
@@ -139,7 +139,7 @@ class StdioHandler(BaseMCPService, IMCPCommunication):
|
|
139
139
|
self._metrics["errors"] += 1
|
140
140
|
raise
|
141
141
|
|
142
|
-
async def receive_message(self) -> Optional[Dict[str, Any]]:
|
142
|
+
async def receive_message(self) -> Optional[Dict[str, Any]]:
|
143
143
|
"""
|
144
144
|
Receive a message from the MCP client via stdin.
|
145
145
|
|
@@ -306,7 +306,7 @@ class DocumentSummarizerTool(BaseToolAdapter):
|
|
306
306
|
continue
|
307
307
|
|
308
308
|
# If all fail, read as binary and decode with errors='ignore'
|
309
|
-
with open(
|
309
|
+
with file_path.open("rb") as f:
|
310
310
|
content = f.read()
|
311
311
|
return content.decode("utf-8", errors="ignore")
|
312
312
|
|
@@ -204,7 +204,7 @@ class HelloWorldTool(BaseToolAdapter):
|
|
204
204
|
self.greeting_history: List[Dict[str, Any]] = []
|
205
205
|
self.max_history_size = 100
|
206
206
|
|
207
|
-
def validate_parameters(self, parameters: Dict[str, Any]) -> bool:
|
207
|
+
def validate_parameters(self, parameters: Dict[str, Any]) -> bool:
|
208
208
|
"""
|
209
209
|
Enhanced parameter validation with detailed error messages.
|
210
210
|
|
@@ -8,7 +8,7 @@ Provides non-blocking version checking for MCP tools like kuzu-memory.
|
|
8
8
|
|
9
9
|
import asyncio
|
10
10
|
import json
|
11
|
-
from datetime import datetime, timedelta
|
11
|
+
from datetime import datetime, timedelta, timezone
|
12
12
|
from pathlib import Path
|
13
13
|
from typing import Any, Dict, Optional
|
14
14
|
|
@@ -83,7 +83,7 @@ class PackageVersionChecker:
|
|
83
83
|
"latest": latest,
|
84
84
|
"update_available": version.parse(latest)
|
85
85
|
> version.parse(current_version),
|
86
|
-
"checked_at": datetime.now().isoformat(),
|
86
|
+
"checked_at": datetime.now(timezone.utc).isoformat(),
|
87
87
|
}
|
88
88
|
self._write_cache(cache_file, result)
|
89
89
|
return result
|
@@ -133,12 +133,12 @@ class PackageVersionChecker:
|
|
133
133
|
return None
|
134
134
|
|
135
135
|
try:
|
136
|
-
with open(
|
136
|
+
with cache_file.open() as f:
|
137
137
|
data = json.load(f)
|
138
138
|
|
139
139
|
# Check TTL
|
140
140
|
checked_at = datetime.fromisoformat(data["checked_at"])
|
141
|
-
if datetime.now() - checked_at < timedelta(seconds=ttl):
|
141
|
+
if datetime.now(timezone.utc) - checked_at < timedelta(seconds=ttl):
|
142
142
|
return data
|
143
143
|
except Exception as e:
|
144
144
|
self.logger.debug(f"Cache read error: {e}")
|
@@ -154,7 +154,7 @@ class PackageVersionChecker:
|
|
154
154
|
data: Data to cache
|
155
155
|
"""
|
156
156
|
try:
|
157
|
-
with open(
|
157
|
+
with cache_file.open("w") as f:
|
158
158
|
json.dump(data, f, indent=2)
|
159
159
|
except Exception as e:
|
160
160
|
self.logger.debug(f"Cache write failed: {e}")
|
@@ -36,7 +36,7 @@ class UpdatePreferences:
|
|
36
36
|
"""
|
37
37
|
if cls.PREFS_FILE.exists():
|
38
38
|
try:
|
39
|
-
with
|
39
|
+
with cls.PREFS_FILE.open() as f:
|
40
40
|
return json.load(f)
|
41
41
|
except (OSError, json.JSONDecodeError):
|
42
42
|
# Return empty dict if file is corrupted or unreadable
|
@@ -53,7 +53,7 @@ class UpdatePreferences:
|
|
53
53
|
"""
|
54
54
|
cls.PREFS_FILE.parent.mkdir(parents=True, exist_ok=True)
|
55
55
|
try:
|
56
|
-
with
|
56
|
+
with cls.PREFS_FILE.open("w") as f:
|
57
57
|
json.dump(prefs, f, indent=2)
|
58
58
|
except OSError:
|
59
59
|
# Silently fail if we can't write preferences
|
@@ -458,7 +458,7 @@ class MemoryBuilder(LoggerMixin):
|
|
458
458
|
import tomllib
|
459
459
|
except ImportError:
|
460
460
|
import tomli as tomllib
|
461
|
-
with open(
|
461
|
+
with file_path.open("rb") as f:
|
462
462
|
config_data = tomllib.load(f)
|
463
463
|
items = self._extract_from_toml_config(config_data, source)
|
464
464
|
extracted_items.extend(items)
|
@@ -194,7 +194,8 @@ class SharedPromptCache(BaseService):
|
|
194
194
|
with cls._lock:
|
195
195
|
if cls._instance is not None:
|
196
196
|
if cls._instance.running:
|
197
|
-
asyncio.create_task(cls._instance.stop())
|
197
|
+
_task = asyncio.create_task(cls._instance.stop()) # noqa: RUF006
|
198
|
+
# Fire-and-forget cleanup task during test reset
|
198
199
|
cls._instance = None
|
199
200
|
|
200
201
|
async def _initialize(self) -> None:
|
@@ -213,7 +213,7 @@ class InvertedIndex:
|
|
213
213
|
"doc_freqs": dict(self.doc_freqs),
|
214
214
|
"doc_count": self.doc_count,
|
215
215
|
}
|
216
|
-
with open(
|
216
|
+
with path.open("wb") as f:
|
217
217
|
pickle.dump(data, f)
|
218
218
|
|
219
219
|
def load(self, path: Path):
|
@@ -221,7 +221,7 @@ class InvertedIndex:
|
|
221
221
|
if not path.exists():
|
222
222
|
return
|
223
223
|
|
224
|
-
with open(
|
224
|
+
with path.open("rb") as f:
|
225
225
|
data = pickle.load(f)
|
226
226
|
|
227
227
|
self.index = defaultdict(set, {k: set(v) for k, v in data["index"].items()})
|
@@ -597,7 +597,7 @@ class IndexedMemoryService:
|
|
597
597
|
# Load other indexes
|
598
598
|
indexes_path = self.data_dir / "indexes.pkl"
|
599
599
|
if indexes_path.exists():
|
600
|
-
with open(
|
600
|
+
with indexes_path.open("rb") as f:
|
601
601
|
data = pickle.load(f)
|
602
602
|
|
603
603
|
self.memories = data.get("memories", {})
|
@@ -121,7 +121,7 @@ class UnifiedMonitorDaemon:
|
|
121
121
|
"""
|
122
122
|
return self.daemon_manager.cleanup_port_conflicts()
|
123
123
|
|
124
|
-
def _start_daemon(self, force_restart: bool = False) -> bool:
|
124
|
+
def _start_daemon(self, force_restart: bool = False) -> bool:
|
125
125
|
"""Start as background daemon process.
|
126
126
|
|
127
127
|
Args:
|