claude-mpm 4.1.0__py3-none-any.whl → 4.1.2__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/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__main__.py +1 -1
- claude_mpm/agents/BASE_PM.md +74 -46
- claude_mpm/agents/INSTRUCTIONS.md +11 -153
- claude_mpm/agents/WORKFLOW.md +61 -321
- claude_mpm/agents/__init__.py +11 -11
- claude_mpm/agents/agent_loader.py +23 -20
- claude_mpm/agents/agent_loader_integration.py +1 -1
- claude_mpm/agents/agents_metadata.py +27 -0
- claude_mpm/agents/async_agent_loader.py +5 -8
- claude_mpm/agents/base_agent_loader.py +36 -25
- claude_mpm/agents/frontmatter_validator.py +6 -6
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +9 -9
- claude_mpm/agents/templates/api_qa.json +47 -2
- claude_mpm/agents/templates/imagemagick.json +256 -0
- claude_mpm/agents/templates/qa.json +41 -2
- claude_mpm/agents/templates/ticketing.json +5 -5
- claude_mpm/agents/templates/web_qa.json +133 -58
- claude_mpm/agents/templates/web_ui.json +3 -3
- claude_mpm/cli/__init__.py +51 -46
- claude_mpm/cli/__main__.py +1 -1
- claude_mpm/cli/commands/__init__.py +10 -12
- claude_mpm/cli/commands/agent_manager.py +186 -181
- claude_mpm/cli/commands/agents.py +271 -268
- claude_mpm/cli/commands/aggregate.py +30 -29
- claude_mpm/cli/commands/cleanup.py +50 -44
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
- claude_mpm/cli/commands/config.py +162 -127
- claude_mpm/cli/commands/doctor.py +52 -62
- claude_mpm/cli/commands/info.py +37 -25
- claude_mpm/cli/commands/mcp.py +3 -7
- claude_mpm/cli/commands/mcp_command_router.py +14 -18
- claude_mpm/cli/commands/mcp_install_commands.py +28 -23
- claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
- claude_mpm/cli/commands/mcp_server_commands.py +23 -17
- claude_mpm/cli/commands/memory.py +192 -141
- claude_mpm/cli/commands/monitor.py +117 -88
- claude_mpm/cli/commands/run.py +120 -84
- claude_mpm/cli/commands/run_config_checker.py +4 -5
- claude_mpm/cli/commands/socketio_monitor.py +17 -19
- claude_mpm/cli/commands/tickets.py +92 -92
- claude_mpm/cli/parser.py +1 -5
- claude_mpm/cli/parsers/__init__.py +1 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
- claude_mpm/cli/parsers/agents_parser.py +2 -3
- claude_mpm/cli/parsers/base_parser.py +7 -5
- claude_mpm/cli/parsers/mcp_parser.py +4 -2
- claude_mpm/cli/parsers/monitor_parser.py +26 -18
- claude_mpm/cli/shared/__init__.py +10 -10
- claude_mpm/cli/shared/argument_patterns.py +57 -71
- claude_mpm/cli/shared/base_command.py +61 -53
- claude_mpm/cli/shared/error_handling.py +62 -58
- claude_mpm/cli/shared/output_formatters.py +78 -77
- claude_mpm/cli/startup_logging.py +204 -172
- claude_mpm/cli/utils.py +10 -11
- claude_mpm/cli_module/__init__.py +1 -1
- claude_mpm/cli_module/args.py +1 -1
- claude_mpm/cli_module/migration_example.py +5 -5
- claude_mpm/config/__init__.py +9 -9
- claude_mpm/config/agent_config.py +15 -14
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/paths.py +0 -1
- claude_mpm/config/socketio_config.py +5 -6
- claude_mpm/constants.py +1 -2
- claude_mpm/core/__init__.py +8 -8
- claude_mpm/core/agent_name_normalizer.py +1 -1
- claude_mpm/core/agent_registry.py +20 -23
- claude_mpm/core/agent_session_manager.py +3 -3
- claude_mpm/core/base_service.py +7 -15
- claude_mpm/core/cache.py +4 -6
- claude_mpm/core/claude_runner.py +85 -113
- claude_mpm/core/config.py +43 -28
- claude_mpm/core/config_aliases.py +0 -9
- claude_mpm/core/config_constants.py +52 -30
- claude_mpm/core/constants.py +0 -1
- claude_mpm/core/container.py +18 -27
- claude_mpm/core/exceptions.py +2 -2
- claude_mpm/core/factories.py +10 -12
- claude_mpm/core/framework_loader.py +581 -280
- claude_mpm/core/hook_manager.py +26 -22
- claude_mpm/core/hook_performance_config.py +58 -47
- claude_mpm/core/injectable_service.py +1 -1
- claude_mpm/core/interactive_session.py +61 -152
- claude_mpm/core/interfaces.py +1 -100
- claude_mpm/core/lazy.py +5 -5
- claude_mpm/core/log_manager.py +587 -0
- claude_mpm/core/logger.py +125 -8
- claude_mpm/core/logging_config.py +15 -15
- claude_mpm/core/minimal_framework_loader.py +5 -8
- claude_mpm/core/oneshot_session.py +15 -33
- claude_mpm/core/optimized_agent_loader.py +4 -6
- claude_mpm/core/optimized_startup.py +2 -1
- claude_mpm/core/output_style_manager.py +147 -106
- claude_mpm/core/pm_hook_interceptor.py +0 -1
- claude_mpm/core/service_registry.py +11 -8
- claude_mpm/core/session_manager.py +1 -2
- claude_mpm/core/shared/__init__.py +1 -1
- claude_mpm/core/shared/config_loader.py +101 -97
- claude_mpm/core/shared/path_resolver.py +72 -68
- claude_mpm/core/shared/singleton_manager.py +56 -50
- claude_mpm/core/socketio_pool.py +26 -6
- claude_mpm/core/tool_access_control.py +4 -5
- claude_mpm/core/typing_utils.py +50 -59
- claude_mpm/core/unified_agent_registry.py +14 -19
- claude_mpm/core/unified_config.py +4 -6
- claude_mpm/core/unified_paths.py +197 -109
- claude_mpm/dashboard/open_dashboard.py +2 -4
- claude_mpm/experimental/cli_enhancements.py +51 -36
- claude_mpm/generators/agent_profile_generator.py +2 -4
- claude_mpm/hooks/base_hook.py +1 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
- claude_mpm/hooks/claude_hooks/event_handlers.py +93 -38
- claude_mpm/hooks/claude_hooks/hook_handler.py +130 -76
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
- claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
- claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
- claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
- claude_mpm/hooks/memory_integration_hook.py +5 -5
- claude_mpm/hooks/tool_call_interceptor.py +1 -1
- claude_mpm/hooks/validation_hooks.py +4 -4
- claude_mpm/init.py +4 -9
- claude_mpm/models/__init__.py +2 -2
- claude_mpm/models/agent_session.py +11 -14
- claude_mpm/scripts/mcp_server.py +20 -11
- claude_mpm/scripts/mcp_wrapper.py +5 -5
- claude_mpm/scripts/mpm_doctor.py +321 -0
- claude_mpm/scripts/socketio_daemon.py +28 -25
- claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
- claude_mpm/scripts/socketio_server_manager.py +116 -95
- claude_mpm/services/__init__.py +49 -49
- claude_mpm/services/agent_capabilities_service.py +12 -18
- claude_mpm/services/agents/__init__.py +22 -22
- claude_mpm/services/agents/agent_builder.py +140 -119
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
- claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
- claude_mpm/services/agents/deployment/agent_deployment.py +136 -106
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
- claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
- claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
- claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
- claude_mpm/services/agents/deployment/agent_validator.py +0 -1
- claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
- claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
- claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
- claude_mpm/services/agents/deployment/config/__init__.py +1 -1
- claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
- claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
- claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
- claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
- claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
- claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
- claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
- claude_mpm/services/agents/deployment/results/__init__.py +1 -1
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
- claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
- claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
- claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
- claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
- claude_mpm/services/agents/loading/__init__.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
- claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
- claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
- claude_mpm/services/agents/management/__init__.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
- claude_mpm/services/agents/management/agent_management_service.py +5 -9
- claude_mpm/services/agents/memory/__init__.py +4 -4
- claude_mpm/services/agents/memory/agent_memory_manager.py +280 -160
- claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
- claude_mpm/services/agents/memory/content_manager.py +44 -38
- claude_mpm/services/agents/memory/template_generator.py +4 -6
- claude_mpm/services/agents/registry/__init__.py +10 -6
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
- claude_mpm/services/agents/registry/modification_tracker.py +3 -6
- claude_mpm/services/async_session_logger.py +1 -2
- claude_mpm/services/claude_session_logger.py +1 -2
- claude_mpm/services/command_deployment_service.py +173 -0
- claude_mpm/services/command_handler_service.py +20 -22
- claude_mpm/services/core/__init__.py +25 -25
- claude_mpm/services/core/base.py +0 -5
- claude_mpm/services/core/interfaces/__init__.py +32 -32
- claude_mpm/services/core/interfaces/agent.py +0 -21
- claude_mpm/services/core/interfaces/communication.py +0 -27
- claude_mpm/services/core/interfaces/infrastructure.py +0 -56
- claude_mpm/services/core/interfaces/service.py +0 -29
- claude_mpm/services/diagnostics/__init__.py +1 -1
- claude_mpm/services/diagnostics/checks/__init__.py +6 -6
- claude_mpm/services/diagnostics/checks/agent_check.py +89 -80
- claude_mpm/services/diagnostics/checks/base_check.py +12 -16
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
- claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
- claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
- claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
- claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
- claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
- claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
- claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
- claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
- claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
- claude_mpm/services/diagnostics/models.py +21 -19
- claude_mpm/services/event_aggregator.py +10 -17
- claude_mpm/services/event_bus/__init__.py +1 -1
- claude_mpm/services/event_bus/config.py +54 -35
- claude_mpm/services/event_bus/event_bus.py +76 -71
- claude_mpm/services/event_bus/relay.py +74 -64
- claude_mpm/services/events/__init__.py +11 -11
- claude_mpm/services/events/consumers/__init__.py +3 -3
- claude_mpm/services/events/consumers/dead_letter.py +71 -63
- claude_mpm/services/events/consumers/logging.py +39 -37
- claude_mpm/services/events/consumers/metrics.py +56 -57
- claude_mpm/services/events/consumers/socketio.py +82 -81
- claude_mpm/services/events/core.py +110 -99
- claude_mpm/services/events/interfaces.py +56 -72
- claude_mpm/services/events/producers/__init__.py +1 -1
- claude_mpm/services/events/producers/hook.py +38 -38
- claude_mpm/services/events/producers/system.py +46 -44
- claude_mpm/services/exceptions.py +81 -80
- claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
- claude_mpm/services/hook_service.py +6 -9
- claude_mpm/services/infrastructure/__init__.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +8 -12
- claude_mpm/services/infrastructure/monitoring.py +21 -23
- claude_mpm/services/mcp_gateway/__init__.py +37 -37
- claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
- claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
- claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
- claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
- claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
- claude_mpm/services/mcp_gateway/core/base.py +0 -3
- claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
- claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
- claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
- claude_mpm/services/mcp_gateway/main.py +2 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
- claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
- claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
- claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
- claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
- claude_mpm/services/memory/__init__.py +3 -3
- claude_mpm/services/memory/builder.py +3 -6
- claude_mpm/services/memory/cache/__init__.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/memory/indexed_memory.py +5 -7
- claude_mpm/services/memory/optimizer.py +7 -10
- claude_mpm/services/memory/router.py +8 -9
- claude_mpm/services/memory_hook_service.py +48 -34
- claude_mpm/services/monitor_build_service.py +77 -73
- claude_mpm/services/port_manager.py +130 -108
- claude_mpm/services/project/analyzer.py +12 -10
- claude_mpm/services/project/registry.py +11 -11
- claude_mpm/services/recovery_manager.py +10 -19
- claude_mpm/services/response_tracker.py +0 -1
- claude_mpm/services/runner_configuration_service.py +19 -20
- claude_mpm/services/session_management_service.py +7 -11
- claude_mpm/services/shared/__init__.py +1 -1
- claude_mpm/services/shared/async_service_base.py +58 -50
- claude_mpm/services/shared/config_service_base.py +73 -67
- claude_mpm/services/shared/lifecycle_service_base.py +82 -78
- claude_mpm/services/shared/manager_base.py +94 -82
- claude_mpm/services/shared/service_factory.py +96 -98
- claude_mpm/services/socketio/__init__.py +3 -3
- claude_mpm/services/socketio/client_proxy.py +5 -5
- claude_mpm/services/socketio/event_normalizer.py +199 -181
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +5 -4
- claude_mpm/services/socketio/handlers/connection.py +163 -136
- claude_mpm/services/socketio/handlers/file.py +13 -14
- claude_mpm/services/socketio/handlers/git.py +12 -7
- claude_mpm/services/socketio/handlers/hook.py +49 -44
- claude_mpm/services/socketio/handlers/memory.py +0 -1
- claude_mpm/services/socketio/handlers/project.py +0 -1
- claude_mpm/services/socketio/handlers/registry.py +37 -19
- claude_mpm/services/socketio/migration_utils.py +98 -84
- claude_mpm/services/socketio/server/__init__.py +1 -1
- claude_mpm/services/socketio/server/broadcaster.py +81 -87
- claude_mpm/services/socketio/server/core.py +65 -54
- claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
- claude_mpm/services/socketio/server/main.py +64 -38
- claude_mpm/services/socketio_client_manager.py +10 -12
- claude_mpm/services/subprocess_launcher_service.py +4 -7
- claude_mpm/services/system_instructions_service.py +13 -14
- claude_mpm/services/ticket_manager.py +2 -2
- claude_mpm/services/utility_service.py +5 -13
- claude_mpm/services/version_control/__init__.py +16 -16
- claude_mpm/services/version_control/branch_strategy.py +5 -8
- claude_mpm/services/version_control/conflict_resolution.py +9 -23
- claude_mpm/services/version_control/git_operations.py +5 -7
- claude_mpm/services/version_control/semantic_versioning.py +16 -17
- claude_mpm/services/version_control/version_parser.py +13 -18
- claude_mpm/services/version_service.py +10 -11
- claude_mpm/storage/__init__.py +1 -1
- claude_mpm/storage/state_storage.py +22 -28
- claude_mpm/utils/__init__.py +6 -6
- claude_mpm/utils/agent_dependency_loader.py +47 -33
- claude_mpm/utils/config_manager.py +11 -14
- claude_mpm/utils/dependency_cache.py +1 -1
- claude_mpm/utils/dependency_manager.py +13 -17
- claude_mpm/utils/dependency_strategies.py +8 -10
- claude_mpm/utils/environment_context.py +3 -9
- claude_mpm/utils/error_handler.py +3 -13
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/path_operations.py +8 -12
- claude_mpm/utils/robust_installer.py +110 -33
- claude_mpm/utils/subprocess_utils.py +5 -6
- claude_mpm/validation/agent_validator.py +3 -6
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/METADATA +1 -1
- claude_mpm-4.1.2.dist-info/RECORD +498 -0
- claude_mpm-4.1.0.dist-info/RECORD +0 -494
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/top_level.txt +0 -0
|
@@ -15,14 +15,13 @@ DESIGN DECISIONS:
|
|
|
15
15
|
- Thread-safe singleton pattern
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
import
|
|
18
|
+
import contextlib
|
|
19
19
|
import fcntl
|
|
20
20
|
import json
|
|
21
21
|
import os
|
|
22
22
|
import signal
|
|
23
23
|
import threading
|
|
24
24
|
import time
|
|
25
|
-
from pathlib import Path
|
|
26
25
|
from typing import Any, Dict, Optional
|
|
27
26
|
|
|
28
27
|
from claude_mpm.config.paths import paths
|
|
@@ -32,14 +31,14 @@ from claude_mpm.core.logger import get_logger
|
|
|
32
31
|
class MCPGatewayManager:
|
|
33
32
|
"""
|
|
34
33
|
Singleton manager for MCP Gateway instances.
|
|
35
|
-
|
|
34
|
+
|
|
36
35
|
Ensures only one gateway instance is running per installation using
|
|
37
36
|
file-based locking and PID tracking.
|
|
38
37
|
"""
|
|
39
|
-
|
|
40
|
-
_instance: Optional[
|
|
38
|
+
|
|
39
|
+
_instance: Optional["MCPGatewayManager"] = None
|
|
41
40
|
_lock = threading.Lock()
|
|
42
|
-
|
|
41
|
+
|
|
43
42
|
def __new__(cls):
|
|
44
43
|
"""Singleton pattern implementation."""
|
|
45
44
|
with cls._lock:
|
|
@@ -47,71 +46,72 @@ class MCPGatewayManager:
|
|
|
47
46
|
cls._instance = super().__new__(cls)
|
|
48
47
|
cls._instance._initialized = False
|
|
49
48
|
return cls._instance
|
|
50
|
-
|
|
49
|
+
|
|
51
50
|
def __init__(self):
|
|
52
51
|
"""Initialize the gateway manager."""
|
|
53
52
|
if self._initialized:
|
|
54
53
|
return
|
|
55
|
-
|
|
54
|
+
|
|
56
55
|
self.logger = get_logger("MCPGatewayManager")
|
|
57
56
|
self._initialized = True
|
|
58
|
-
|
|
57
|
+
|
|
59
58
|
# Paths for coordination
|
|
60
59
|
self.mcp_dir = paths.claude_mpm_dir_hidden / "mcp"
|
|
61
60
|
self.lock_file = self.mcp_dir / "gateway.lock"
|
|
62
61
|
self.instance_file = self.mcp_dir / "gateway.json"
|
|
63
|
-
|
|
62
|
+
|
|
64
63
|
# Ensure directory exists
|
|
65
64
|
self.mcp_dir.mkdir(parents=True, exist_ok=True)
|
|
66
|
-
|
|
65
|
+
|
|
67
66
|
# Lock file handle
|
|
68
67
|
self._lock_fd: Optional[int] = None
|
|
69
68
|
self._current_instance: Optional[Dict[str, Any]] = None
|
|
70
|
-
|
|
69
|
+
|
|
71
70
|
# Setup cleanup handlers
|
|
72
71
|
self._setup_cleanup_handlers()
|
|
73
|
-
|
|
72
|
+
|
|
74
73
|
def _setup_cleanup_handlers(self):
|
|
75
74
|
"""Setup signal handlers for cleanup on termination."""
|
|
75
|
+
|
|
76
76
|
def cleanup_handler(signum, frame):
|
|
77
77
|
self.logger.info(f"Received signal {signum}, cleaning up gateway")
|
|
78
78
|
self.cleanup()
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
signal.signal(signal.SIGTERM, cleanup_handler)
|
|
81
81
|
signal.signal(signal.SIGINT, cleanup_handler)
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
def acquire_lock(self) -> bool:
|
|
84
84
|
"""
|
|
85
85
|
Acquire exclusive lock for gateway instance.
|
|
86
|
-
|
|
86
|
+
|
|
87
87
|
Returns:
|
|
88
88
|
True if lock acquired successfully, False otherwise
|
|
89
89
|
"""
|
|
90
90
|
try:
|
|
91
91
|
# Open lock file
|
|
92
|
-
self._lock_fd = os.open(
|
|
93
|
-
|
|
92
|
+
self._lock_fd = os.open(
|
|
93
|
+
self.lock_file, os.O_CREAT | os.O_WRONLY | os.O_TRUNC
|
|
94
|
+
)
|
|
95
|
+
|
|
94
96
|
# Try to acquire exclusive lock (non-blocking)
|
|
95
97
|
fcntl.flock(self._lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
96
|
-
|
|
98
|
+
|
|
97
99
|
# Write current PID to lock file
|
|
98
100
|
os.write(self._lock_fd, str(os.getpid()).encode())
|
|
99
101
|
os.fsync(self._lock_fd)
|
|
100
|
-
|
|
102
|
+
|
|
101
103
|
self.logger.info(f"Acquired gateway lock (PID: {os.getpid()})")
|
|
102
104
|
return True
|
|
103
|
-
|
|
104
|
-
except
|
|
105
|
+
|
|
106
|
+
except OSError as e:
|
|
105
107
|
if self._lock_fd:
|
|
106
|
-
|
|
108
|
+
with contextlib.suppress(Exception):
|
|
107
109
|
os.close(self._lock_fd)
|
|
108
|
-
except:
|
|
109
|
-
pass
|
|
110
110
|
self._lock_fd = None
|
|
111
|
-
|
|
111
|
+
|
|
112
112
|
self.logger.debug(f"Failed to acquire gateway lock: {e}")
|
|
113
113
|
return False
|
|
114
|
-
|
|
114
|
+
|
|
115
115
|
def release_lock(self):
|
|
116
116
|
"""Release the gateway lock."""
|
|
117
117
|
if self._lock_fd:
|
|
@@ -119,52 +119,51 @@ class MCPGatewayManager:
|
|
|
119
119
|
fcntl.flock(self._lock_fd, fcntl.LOCK_UN)
|
|
120
120
|
os.close(self._lock_fd)
|
|
121
121
|
self._lock_fd = None
|
|
122
|
-
|
|
122
|
+
|
|
123
123
|
# Remove lock file
|
|
124
124
|
if self.lock_file.exists():
|
|
125
125
|
self.lock_file.unlink()
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
self.logger.info("Released gateway lock")
|
|
128
128
|
except Exception as e:
|
|
129
129
|
self.logger.warning(f"Error releasing lock: {e}")
|
|
130
|
-
|
|
130
|
+
|
|
131
131
|
def is_gateway_running(self) -> bool:
|
|
132
132
|
"""
|
|
133
133
|
Check if a gateway instance is currently running.
|
|
134
|
-
|
|
134
|
+
|
|
135
135
|
Returns:
|
|
136
136
|
True if gateway is running, False otherwise
|
|
137
137
|
"""
|
|
138
138
|
instance_info = self.get_running_instance_info()
|
|
139
139
|
return instance_info is not None
|
|
140
|
-
|
|
140
|
+
|
|
141
141
|
def get_running_instance_info(self) -> Optional[Dict[str, Any]]:
|
|
142
142
|
"""
|
|
143
143
|
Get information about the currently running gateway instance.
|
|
144
|
-
|
|
144
|
+
|
|
145
145
|
Returns:
|
|
146
146
|
Instance information dict or None if no instance running
|
|
147
147
|
"""
|
|
148
148
|
if not self.instance_file.exists():
|
|
149
149
|
return None
|
|
150
|
-
|
|
150
|
+
|
|
151
151
|
try:
|
|
152
|
-
with open(self.instance_file
|
|
152
|
+
with open(self.instance_file) as f:
|
|
153
153
|
instance_info = json.load(f)
|
|
154
|
-
|
|
154
|
+
|
|
155
155
|
# Validate PID is still running
|
|
156
|
-
pid = instance_info.get(
|
|
156
|
+
pid = instance_info.get("pid")
|
|
157
157
|
if pid and self._is_pid_running(pid):
|
|
158
158
|
return instance_info
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
159
|
+
# Stale instance file, remove it
|
|
160
|
+
self.instance_file.unlink()
|
|
161
|
+
return None
|
|
162
|
+
|
|
164
163
|
except (json.JSONDecodeError, OSError) as e:
|
|
165
164
|
self.logger.warning(f"Error reading instance file: {e}")
|
|
166
165
|
return None
|
|
167
|
-
|
|
166
|
+
|
|
168
167
|
def _is_pid_running(self, pid: int) -> bool:
|
|
169
168
|
"""Check if a PID is currently running."""
|
|
170
169
|
try:
|
|
@@ -172,55 +171,55 @@ class MCPGatewayManager:
|
|
|
172
171
|
return True
|
|
173
172
|
except (OSError, ProcessLookupError):
|
|
174
173
|
return False
|
|
175
|
-
|
|
174
|
+
|
|
176
175
|
def register_instance(self, gateway_name: str, version: str) -> bool:
|
|
177
176
|
"""
|
|
178
177
|
Register a new gateway instance.
|
|
179
|
-
|
|
178
|
+
|
|
180
179
|
Args:
|
|
181
180
|
gateway_name: Name of the gateway
|
|
182
181
|
version: Gateway version
|
|
183
|
-
|
|
182
|
+
|
|
184
183
|
Returns:
|
|
185
184
|
True if registration successful, False otherwise
|
|
186
185
|
"""
|
|
187
186
|
if not self.acquire_lock():
|
|
188
187
|
return False
|
|
189
|
-
|
|
188
|
+
|
|
190
189
|
try:
|
|
191
190
|
instance_info = {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
191
|
+
"pid": os.getpid(),
|
|
192
|
+
"gateway_name": gateway_name,
|
|
193
|
+
"version": version,
|
|
194
|
+
"started_at": time.time(),
|
|
195
|
+
"lock_file": str(self.lock_file),
|
|
197
196
|
}
|
|
198
|
-
|
|
199
|
-
with open(self.instance_file,
|
|
197
|
+
|
|
198
|
+
with open(self.instance_file, "w") as f:
|
|
200
199
|
json.dump(instance_info, f, indent=2)
|
|
201
|
-
|
|
200
|
+
|
|
202
201
|
self._current_instance = instance_info
|
|
203
202
|
self.logger.info(f"Registered gateway instance: {gateway_name} v{version}")
|
|
204
203
|
return True
|
|
205
|
-
|
|
204
|
+
|
|
206
205
|
except Exception as e:
|
|
207
206
|
self.logger.error(f"Failed to register instance: {e}")
|
|
208
207
|
self.release_lock()
|
|
209
208
|
return False
|
|
210
|
-
|
|
209
|
+
|
|
211
210
|
def cleanup(self):
|
|
212
211
|
"""Clean up gateway instance and release resources."""
|
|
213
212
|
try:
|
|
214
213
|
# Remove instance file
|
|
215
214
|
if self.instance_file.exists():
|
|
216
215
|
self.instance_file.unlink()
|
|
217
|
-
|
|
216
|
+
|
|
218
217
|
# Release lock
|
|
219
218
|
self.release_lock()
|
|
220
|
-
|
|
219
|
+
|
|
221
220
|
self._current_instance = None
|
|
222
221
|
self.logger.info("Gateway cleanup completed")
|
|
223
|
-
|
|
222
|
+
|
|
224
223
|
except Exception as e:
|
|
225
224
|
self.logger.warning(f"Error during cleanup: {e}")
|
|
226
225
|
|
|
@@ -247,7 +246,9 @@ def get_gateway_status() -> Optional[Dict[str, Any]]:
|
|
|
247
246
|
return get_gateway_manager().get_running_instance_info()
|
|
248
247
|
|
|
249
248
|
|
|
250
|
-
async def start_global_gateway(
|
|
249
|
+
async def start_global_gateway(
|
|
250
|
+
gateway_name: str = "claude-mpm-mcp", version: str = "1.0.0"
|
|
251
|
+
) -> bool:
|
|
251
252
|
"""
|
|
252
253
|
Start the global MCP gateway instance.
|
|
253
254
|
|
|
@@ -263,7 +264,9 @@ async def start_global_gateway(gateway_name: str = "claude-mpm-mcp", version: st
|
|
|
263
264
|
# Check if already running
|
|
264
265
|
if manager.is_gateway_running():
|
|
265
266
|
instance_info = manager.get_running_instance_info()
|
|
266
|
-
manager.logger.info(
|
|
267
|
+
manager.logger.info(
|
|
268
|
+
f"Gateway already running (PID: {instance_info.get('pid')})"
|
|
269
|
+
)
|
|
267
270
|
return True
|
|
268
271
|
|
|
269
272
|
# Register new instance
|
|
@@ -16,9 +16,7 @@ DESIGN DECISIONS:
|
|
|
16
16
|
- Non-blocking startup (warnings instead of failures)
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
import
|
|
20
|
-
from pathlib import Path
|
|
21
|
-
from typing import Any, Dict, List, Optional, Tuple
|
|
19
|
+
from typing import Any, Dict
|
|
22
20
|
|
|
23
21
|
from claude_mpm.config.paths import paths
|
|
24
22
|
from claude_mpm.core.logger import get_logger
|
|
@@ -29,17 +27,17 @@ from .singleton_manager import get_gateway_manager, is_gateway_running
|
|
|
29
27
|
class MCPGatewayStartupVerifier:
|
|
30
28
|
"""
|
|
31
29
|
Verifies and configures MCP Gateway on startup.
|
|
32
|
-
|
|
30
|
+
|
|
33
31
|
Ensures the gateway is properly configured with essential tools and
|
|
34
32
|
provides diagnostic information about the gateway state.
|
|
35
33
|
"""
|
|
36
|
-
|
|
34
|
+
|
|
37
35
|
def __init__(self):
|
|
38
36
|
"""Initialize the startup verifier."""
|
|
39
37
|
self.logger = get_logger("MCPGatewayStartupVerifier")
|
|
40
38
|
self.config_dir = paths.claude_mpm_dir_hidden / "mcp"
|
|
41
39
|
self.config_file = self.config_dir / "gateway_config.json"
|
|
42
|
-
|
|
40
|
+
|
|
43
41
|
# Essential tools that should be available
|
|
44
42
|
self.essential_tools = [
|
|
45
43
|
"echo", # Basic diagnostic tool
|
|
@@ -49,16 +47,16 @@ class MCPGatewayStartupVerifier:
|
|
|
49
47
|
"document_summarizer", # File summarizer
|
|
50
48
|
"ticket", # Ticket service (unified)
|
|
51
49
|
]
|
|
52
|
-
|
|
50
|
+
|
|
53
51
|
async def verify_and_configure(self) -> Dict[str, Any]:
|
|
54
52
|
"""
|
|
55
53
|
Verify MCP gateway configuration and configure if needed.
|
|
56
|
-
|
|
54
|
+
|
|
57
55
|
Returns:
|
|
58
56
|
Dictionary with verification results and status
|
|
59
57
|
"""
|
|
60
58
|
self.logger.info("Starting MCP Gateway verification")
|
|
61
|
-
|
|
59
|
+
|
|
62
60
|
results = {
|
|
63
61
|
"gateway_configured": False,
|
|
64
62
|
"singleton_manager": False,
|
|
@@ -67,73 +65,78 @@ class MCPGatewayStartupVerifier:
|
|
|
67
65
|
"warnings": [],
|
|
68
66
|
"errors": [],
|
|
69
67
|
}
|
|
70
|
-
|
|
68
|
+
|
|
71
69
|
try:
|
|
72
70
|
# 1. Verify singleton manager
|
|
73
71
|
results["singleton_manager"] = self._verify_singleton_manager()
|
|
74
|
-
|
|
72
|
+
|
|
75
73
|
# 2. Ensure configuration directory exists
|
|
76
74
|
self._ensure_config_directory()
|
|
77
|
-
|
|
75
|
+
|
|
78
76
|
# 3. Verify or create gateway configuration
|
|
79
77
|
config_created = await self._verify_gateway_configuration()
|
|
80
78
|
results["configuration_created"] = config_created
|
|
81
|
-
|
|
79
|
+
|
|
82
80
|
# 4. Verify essential tools
|
|
83
81
|
tools_status = await self._verify_essential_tools()
|
|
84
82
|
results["essential_tools"] = tools_status
|
|
85
|
-
|
|
83
|
+
|
|
86
84
|
# 5. Check overall gateway status
|
|
87
85
|
results["gateway_configured"] = self._assess_gateway_status(results)
|
|
88
|
-
|
|
86
|
+
|
|
89
87
|
# Log summary
|
|
90
88
|
self._log_verification_summary(results)
|
|
91
|
-
|
|
89
|
+
|
|
92
90
|
return results
|
|
93
|
-
|
|
91
|
+
|
|
94
92
|
except Exception as e:
|
|
95
93
|
self.logger.error(f"Error during MCP Gateway verification: {e}")
|
|
96
94
|
results["errors"].append(f"Verification failed: {e}")
|
|
97
95
|
return results
|
|
98
|
-
|
|
96
|
+
|
|
99
97
|
def _verify_singleton_manager(self) -> bool:
|
|
100
98
|
"""Verify singleton manager is working."""
|
|
101
99
|
try:
|
|
102
|
-
|
|
100
|
+
get_gateway_manager()
|
|
103
101
|
# Test basic functionality
|
|
104
102
|
running = is_gateway_running()
|
|
105
|
-
self.logger.debug(
|
|
103
|
+
self.logger.debug(
|
|
104
|
+
f"Singleton manager operational, gateway running: {running}"
|
|
105
|
+
)
|
|
106
106
|
return True
|
|
107
107
|
except Exception as e:
|
|
108
108
|
self.logger.warning(f"Singleton manager issue: {e}")
|
|
109
109
|
return False
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
def _ensure_config_directory(self):
|
|
112
112
|
"""Ensure MCP configuration directory exists."""
|
|
113
113
|
self.config_dir.mkdir(parents=True, exist_ok=True)
|
|
114
114
|
self.logger.debug(f"MCP config directory: {self.config_dir}")
|
|
115
|
-
|
|
115
|
+
|
|
116
116
|
async def _verify_gateway_configuration(self) -> bool:
|
|
117
117
|
"""Verify or create gateway configuration."""
|
|
118
118
|
if self.config_file.exists():
|
|
119
119
|
self.logger.debug("Gateway configuration file exists")
|
|
120
120
|
return False
|
|
121
|
-
|
|
121
|
+
|
|
122
122
|
# Create default configuration
|
|
123
123
|
default_config = self._create_default_configuration()
|
|
124
|
-
|
|
124
|
+
|
|
125
125
|
try:
|
|
126
126
|
import json
|
|
127
|
-
|
|
127
|
+
|
|
128
|
+
with open(self.config_file, "w") as f:
|
|
128
129
|
json.dump(default_config, f, indent=2)
|
|
129
|
-
|
|
130
|
-
self.logger.info(
|
|
130
|
+
|
|
131
|
+
self.logger.info(
|
|
132
|
+
f"Created default gateway configuration: {self.config_file}"
|
|
133
|
+
)
|
|
131
134
|
return True
|
|
132
|
-
|
|
135
|
+
|
|
133
136
|
except Exception as e:
|
|
134
137
|
self.logger.warning(f"Failed to create configuration: {e}")
|
|
135
138
|
return False
|
|
136
|
-
|
|
139
|
+
|
|
137
140
|
def _create_default_configuration(self) -> Dict[str, Any]:
|
|
138
141
|
"""Create default MCP gateway configuration."""
|
|
139
142
|
return {
|
|
@@ -141,36 +144,33 @@ class MCPGatewayStartupVerifier:
|
|
|
141
144
|
"server": {
|
|
142
145
|
"name": "claude-mpm-mcp-gateway",
|
|
143
146
|
"version": "1.0.0",
|
|
144
|
-
"description": "Claude MPM MCP Gateway with essential tools"
|
|
147
|
+
"description": "Claude MPM MCP Gateway with essential tools",
|
|
145
148
|
},
|
|
146
149
|
"tools": {
|
|
147
150
|
"enabled": True,
|
|
148
151
|
"auto_discover": True,
|
|
149
152
|
"timeout_default": 30,
|
|
150
153
|
"max_concurrent": 10,
|
|
151
|
-
"essential_tools": self.essential_tools
|
|
154
|
+
"essential_tools": self.essential_tools,
|
|
152
155
|
},
|
|
153
156
|
"logging": {
|
|
154
157
|
"level": "INFO",
|
|
155
|
-
"file": str(paths.logs_dir / "mcp_gateway.log")
|
|
158
|
+
"file": str(paths.logs_dir / "mcp_gateway.log"),
|
|
156
159
|
},
|
|
157
|
-
"security": {
|
|
158
|
-
"validate_schemas": True,
|
|
159
|
-
"sanitize_inputs": True
|
|
160
|
-
}
|
|
160
|
+
"security": {"validate_schemas": True, "sanitize_inputs": True},
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
|
|
163
|
+
|
|
164
164
|
async def _verify_essential_tools(self) -> Dict[str, Dict[str, Any]]:
|
|
165
165
|
"""Verify essential tools are available."""
|
|
166
166
|
tools_status = {}
|
|
167
|
-
|
|
167
|
+
|
|
168
168
|
for tool_name in self.essential_tools:
|
|
169
169
|
status = await self._verify_tool(tool_name)
|
|
170
170
|
tools_status[tool_name] = status
|
|
171
|
-
|
|
171
|
+
|
|
172
172
|
return tools_status
|
|
173
|
-
|
|
173
|
+
|
|
174
174
|
async def _verify_tool(self, tool_name: str) -> Dict[str, Any]:
|
|
175
175
|
"""Verify a specific tool is available."""
|
|
176
176
|
status = {
|
|
@@ -178,27 +178,27 @@ class MCPGatewayStartupVerifier:
|
|
|
178
178
|
"initialized": False,
|
|
179
179
|
"error": None,
|
|
180
180
|
}
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
try:
|
|
183
183
|
# Try to import and initialize the tool
|
|
184
184
|
tool_instance = await self._create_tool_instance(tool_name)
|
|
185
|
-
|
|
185
|
+
|
|
186
186
|
if tool_instance:
|
|
187
187
|
status["available"] = True
|
|
188
|
-
|
|
188
|
+
|
|
189
189
|
# Try to initialize
|
|
190
|
-
if hasattr(tool_instance,
|
|
190
|
+
if hasattr(tool_instance, "initialize"):
|
|
191
191
|
initialized = await tool_instance.initialize()
|
|
192
192
|
status["initialized"] = initialized
|
|
193
193
|
else:
|
|
194
194
|
status["initialized"] = True
|
|
195
|
-
|
|
195
|
+
|
|
196
196
|
except Exception as e:
|
|
197
197
|
status["error"] = str(e)
|
|
198
198
|
self.logger.debug(f"Tool {tool_name} verification failed: {e}")
|
|
199
|
-
|
|
199
|
+
|
|
200
200
|
return status
|
|
201
|
-
|
|
201
|
+
|
|
202
202
|
async def _create_tool_instance(self, tool_name: str):
|
|
203
203
|
"""Create an instance of the specified tool."""
|
|
204
204
|
tool_map = {
|
|
@@ -206,74 +206,78 @@ class MCPGatewayStartupVerifier:
|
|
|
206
206
|
"calculator": ("..tools.base_adapter", "CalculatorToolAdapter"),
|
|
207
207
|
"system_info": ("..tools.base_adapter", "SystemInfoToolAdapter"),
|
|
208
208
|
"health_check": ("..tools.health_check_tool", "HealthCheckTool"),
|
|
209
|
-
"document_summarizer": (
|
|
209
|
+
"document_summarizer": (
|
|
210
|
+
"..tools.document_summarizer",
|
|
211
|
+
"DocumentSummarizerTool",
|
|
212
|
+
),
|
|
210
213
|
"ticket": ("..tools.unified_ticket_tool", "UnifiedTicketTool"),
|
|
211
214
|
}
|
|
212
|
-
|
|
215
|
+
|
|
213
216
|
if tool_name not in tool_map:
|
|
214
217
|
return None
|
|
215
|
-
|
|
218
|
+
|
|
216
219
|
module_path, class_name = tool_map[tool_name]
|
|
217
|
-
|
|
220
|
+
|
|
218
221
|
try:
|
|
219
222
|
# Dynamic import
|
|
220
223
|
from importlib import import_module
|
|
224
|
+
|
|
221
225
|
module = import_module(module_path, package=__package__)
|
|
222
226
|
tool_class = getattr(module, class_name)
|
|
223
227
|
return tool_class()
|
|
224
228
|
except (ImportError, AttributeError) as e:
|
|
225
229
|
self.logger.debug(f"Could not import {tool_name}: {e}")
|
|
226
230
|
return None
|
|
227
|
-
|
|
231
|
+
|
|
228
232
|
def _assess_gateway_status(self, results: Dict[str, Any]) -> bool:
|
|
229
233
|
"""Assess overall gateway configuration status."""
|
|
230
234
|
# Gateway is considered configured if:
|
|
231
235
|
# 1. Singleton manager works
|
|
232
236
|
# 2. At least basic tools are available
|
|
233
237
|
# 3. No critical errors
|
|
234
|
-
|
|
238
|
+
|
|
235
239
|
if not results["singleton_manager"]:
|
|
236
240
|
return False
|
|
237
|
-
|
|
241
|
+
|
|
238
242
|
if results["errors"]:
|
|
239
243
|
return False
|
|
240
|
-
|
|
244
|
+
|
|
241
245
|
# Check if at least basic diagnostic tools are available
|
|
242
246
|
essential_available = 0
|
|
243
|
-
for
|
|
247
|
+
for _tool_name, status in results["essential_tools"].items():
|
|
244
248
|
if status.get("available", False):
|
|
245
249
|
essential_available += 1
|
|
246
|
-
|
|
250
|
+
|
|
247
251
|
# Consider configured if at least 3 essential tools are available
|
|
248
252
|
return essential_available >= 3
|
|
249
|
-
|
|
253
|
+
|
|
250
254
|
def _log_verification_summary(self, results: Dict[str, Any]):
|
|
251
255
|
"""Log verification summary."""
|
|
252
256
|
if results["gateway_configured"]:
|
|
253
257
|
self.logger.info("✅ MCP Gateway verification completed successfully")
|
|
254
258
|
else:
|
|
255
259
|
self.logger.warning("⚠️ MCP Gateway verification completed with issues")
|
|
256
|
-
|
|
260
|
+
|
|
257
261
|
# Log tool status
|
|
258
262
|
available_tools = []
|
|
259
263
|
unavailable_tools = []
|
|
260
|
-
|
|
264
|
+
|
|
261
265
|
for tool_name, status in results["essential_tools"].items():
|
|
262
266
|
if status.get("available", False):
|
|
263
267
|
available_tools.append(tool_name)
|
|
264
268
|
else:
|
|
265
269
|
unavailable_tools.append(tool_name)
|
|
266
|
-
|
|
270
|
+
|
|
267
271
|
if available_tools:
|
|
268
272
|
self.logger.info(f"Available tools: {', '.join(available_tools)}")
|
|
269
|
-
|
|
273
|
+
|
|
270
274
|
if unavailable_tools:
|
|
271
275
|
self.logger.warning(f"Unavailable tools: {', '.join(unavailable_tools)}")
|
|
272
|
-
|
|
276
|
+
|
|
273
277
|
# Log warnings and errors
|
|
274
278
|
for warning in results.get("warnings", []):
|
|
275
279
|
self.logger.warning(warning)
|
|
276
|
-
|
|
280
|
+
|
|
277
281
|
for error in results.get("errors", []):
|
|
278
282
|
self.logger.error(error)
|
|
279
283
|
|
|
@@ -282,10 +286,10 @@ class MCPGatewayStartupVerifier:
|
|
|
282
286
|
async def verify_mcp_gateway_on_startup() -> Dict[str, Any]:
|
|
283
287
|
"""
|
|
284
288
|
Verify MCP Gateway configuration on startup.
|
|
285
|
-
|
|
289
|
+
|
|
286
290
|
This function should be called during application startup to ensure
|
|
287
291
|
the MCP gateway is properly configured.
|
|
288
|
-
|
|
292
|
+
|
|
289
293
|
Returns:
|
|
290
294
|
Dictionary with verification results
|
|
291
295
|
"""
|
|
@@ -296,20 +300,17 @@ async def verify_mcp_gateway_on_startup() -> Dict[str, Any]:
|
|
|
296
300
|
def is_mcp_gateway_configured() -> bool:
|
|
297
301
|
"""
|
|
298
302
|
Quick check if MCP gateway appears to be configured.
|
|
299
|
-
|
|
303
|
+
|
|
300
304
|
Returns:
|
|
301
305
|
True if gateway appears configured, False otherwise
|
|
302
306
|
"""
|
|
303
307
|
try:
|
|
304
308
|
# Check if singleton manager works
|
|
305
|
-
|
|
306
|
-
|
|
309
|
+
get_gateway_manager()
|
|
310
|
+
|
|
307
311
|
# Check if config directory exists
|
|
308
312
|
config_dir = paths.claude_mpm_dir_hidden / "mcp"
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return True
|
|
313
|
-
|
|
313
|
+
return config_dir.exists()
|
|
314
|
+
|
|
314
315
|
except Exception:
|
|
315
316
|
return False
|
|
@@ -15,7 +15,7 @@ import asyncio
|
|
|
15
15
|
import logging
|
|
16
16
|
import signal
|
|
17
17
|
import sys
|
|
18
|
-
from typing import
|
|
18
|
+
from typing import Optional
|
|
19
19
|
|
|
20
20
|
# Import with fallback handling for missing dependencies
|
|
21
21
|
try:
|
|
@@ -259,6 +259,7 @@ class MCPGatewayOrchestrator:
|
|
|
259
259
|
# Optional: Health check tool
|
|
260
260
|
try:
|
|
261
261
|
from .tools.health_check_tool import HealthCheckTool
|
|
262
|
+
|
|
262
263
|
tools.append(HealthCheckTool())
|
|
263
264
|
except Exception as e:
|
|
264
265
|
self.logger.warning(f"Could not load health check tool: {e}")
|