claude-mpm 4.1.1__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 +50 -2
- 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.1.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.1.dist-info/RECORD +0 -494
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.2.dist-info}/top_level.txt +0 -0
|
@@ -20,34 +20,33 @@ DESIGN DECISIONS:
|
|
|
20
20
|
import json
|
|
21
21
|
import os
|
|
22
22
|
import sys
|
|
23
|
-
import time
|
|
24
23
|
from datetime import datetime
|
|
25
24
|
from pathlib import Path
|
|
26
|
-
from typing import
|
|
25
|
+
from typing import Any, Dict, Optional
|
|
27
26
|
|
|
28
|
-
from claude_mpm.core.logger import get_logger
|
|
29
27
|
from claude_mpm.config.paths import paths
|
|
28
|
+
from claude_mpm.core.logger import get_logger
|
|
30
29
|
|
|
31
30
|
|
|
32
31
|
class MCPAutoConfigurator:
|
|
33
32
|
"""
|
|
34
33
|
Handles automatic MCP configuration for pipx installations.
|
|
35
|
-
|
|
34
|
+
|
|
36
35
|
Provides a one-time prompt to configure MCP Gateway with user consent,
|
|
37
36
|
making the experience seamless for pipx users while respecting choice.
|
|
38
37
|
"""
|
|
39
|
-
|
|
38
|
+
|
|
40
39
|
def __init__(self):
|
|
41
40
|
"""Initialize the auto-configurator."""
|
|
42
41
|
self.logger = get_logger("MCPAutoConfig")
|
|
43
42
|
self.config_dir = paths.claude_mpm_dir_hidden
|
|
44
43
|
self.preference_file = self.config_dir / "mcp_auto_config_preference.json"
|
|
45
44
|
self.claude_config_path = Path.home() / ".claude.json"
|
|
46
|
-
|
|
45
|
+
|
|
47
46
|
def should_auto_configure(self) -> bool:
|
|
48
47
|
"""
|
|
49
48
|
Check if auto-configuration should be attempted.
|
|
50
|
-
|
|
49
|
+
|
|
51
50
|
Returns:
|
|
52
51
|
True if auto-configuration should be offered, False otherwise
|
|
53
52
|
"""
|
|
@@ -55,120 +54,118 @@ class MCPAutoConfigurator:
|
|
|
55
54
|
if os.environ.get("CLAUDE_MPM_NO_AUTO_CONFIG"):
|
|
56
55
|
self.logger.debug("Auto-configuration disabled via environment variable")
|
|
57
56
|
return False
|
|
58
|
-
|
|
57
|
+
|
|
59
58
|
# Check if already configured
|
|
60
59
|
if self._is_mcp_configured():
|
|
61
60
|
self.logger.debug("MCP already configured")
|
|
62
61
|
return False
|
|
63
|
-
|
|
62
|
+
|
|
64
63
|
# Check if this is a pipx installation
|
|
65
64
|
if not self._is_pipx_installation():
|
|
66
65
|
self.logger.debug("Not a pipx installation")
|
|
67
66
|
return False
|
|
68
|
-
|
|
67
|
+
|
|
69
68
|
# Check if we've already asked
|
|
70
69
|
if self._has_user_preference():
|
|
71
70
|
self.logger.debug("User preference already saved")
|
|
72
71
|
return False
|
|
73
|
-
|
|
72
|
+
|
|
74
73
|
return True
|
|
75
|
-
|
|
74
|
+
|
|
76
75
|
def _is_mcp_configured(self) -> bool:
|
|
77
76
|
"""Check if MCP is already configured in Claude Code."""
|
|
78
77
|
if not self.claude_config_path.exists():
|
|
79
78
|
return False
|
|
80
|
-
|
|
79
|
+
|
|
81
80
|
try:
|
|
82
|
-
with open(self.claude_config_path
|
|
81
|
+
with open(self.claude_config_path) as f:
|
|
83
82
|
config = json.load(f)
|
|
84
|
-
|
|
83
|
+
|
|
85
84
|
# Check if claude-mpm-gateway is configured
|
|
86
85
|
mcp_servers = config.get("mcpServers", {})
|
|
87
86
|
return "claude-mpm-gateway" in mcp_servers
|
|
88
|
-
|
|
89
|
-
except (json.JSONDecodeError
|
|
87
|
+
|
|
88
|
+
except (OSError, json.JSONDecodeError):
|
|
90
89
|
return False
|
|
91
|
-
|
|
90
|
+
|
|
92
91
|
def _is_pipx_installation(self) -> bool:
|
|
93
92
|
"""Check if claude-mpm is installed via pipx."""
|
|
94
93
|
# Check if running from pipx virtual environment
|
|
95
94
|
if "pipx" in sys.executable.lower():
|
|
96
95
|
return True
|
|
97
|
-
|
|
96
|
+
|
|
98
97
|
# Check module path
|
|
99
98
|
try:
|
|
100
99
|
import claude_mpm
|
|
100
|
+
|
|
101
101
|
module_path = Path(claude_mpm.__file__).parent
|
|
102
102
|
if "pipx" in str(module_path):
|
|
103
103
|
return True
|
|
104
104
|
except Exception:
|
|
105
105
|
pass
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
# Check for pipx in PATH for claude-mpm command
|
|
108
108
|
try:
|
|
109
|
-
import subprocess
|
|
110
109
|
import platform
|
|
111
|
-
|
|
110
|
+
import subprocess
|
|
111
|
+
|
|
112
112
|
# Use appropriate command for OS
|
|
113
113
|
if platform.system() == "Windows":
|
|
114
114
|
cmd = ["where", "claude-mpm"]
|
|
115
115
|
else:
|
|
116
116
|
cmd = ["which", "claude-mpm"]
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
result = subprocess.run(
|
|
119
|
-
cmd,
|
|
120
|
-
capture_output=True,
|
|
121
|
-
text=True,
|
|
122
|
-
timeout=2
|
|
119
|
+
cmd, capture_output=True, text=True, timeout=2, check=False
|
|
123
120
|
)
|
|
124
121
|
if result.returncode == 0 and "pipx" in result.stdout:
|
|
125
122
|
return True
|
|
126
123
|
except Exception:
|
|
127
124
|
pass
|
|
128
|
-
|
|
125
|
+
|
|
129
126
|
return False
|
|
130
|
-
|
|
127
|
+
|
|
131
128
|
def _has_user_preference(self) -> bool:
|
|
132
129
|
"""Check if user has already been asked about auto-configuration."""
|
|
133
130
|
if not self.preference_file.exists():
|
|
134
131
|
return False
|
|
135
|
-
|
|
132
|
+
|
|
136
133
|
try:
|
|
137
|
-
with open(self.preference_file
|
|
134
|
+
with open(self.preference_file) as f:
|
|
138
135
|
prefs = json.load(f)
|
|
139
136
|
return prefs.get("asked", False)
|
|
140
|
-
except (json.JSONDecodeError
|
|
137
|
+
except (OSError, json.JSONDecodeError):
|
|
141
138
|
return False
|
|
142
|
-
|
|
139
|
+
|
|
143
140
|
def _save_user_preference(self, choice: str):
|
|
144
141
|
"""Save user's preference to avoid asking again."""
|
|
145
142
|
self.config_dir.mkdir(parents=True, exist_ok=True)
|
|
146
|
-
|
|
143
|
+
|
|
147
144
|
prefs = {
|
|
148
145
|
"asked": True,
|
|
149
146
|
"choice": choice,
|
|
150
|
-
"timestamp": datetime.now().isoformat()
|
|
147
|
+
"timestamp": datetime.now().isoformat(),
|
|
151
148
|
}
|
|
152
|
-
|
|
149
|
+
|
|
153
150
|
try:
|
|
154
|
-
with open(self.preference_file,
|
|
151
|
+
with open(self.preference_file, "w") as f:
|
|
155
152
|
json.dump(prefs, f, indent=2)
|
|
156
153
|
except Exception as e:
|
|
157
154
|
self.logger.debug(f"Could not save preference: {e}")
|
|
158
|
-
|
|
155
|
+
|
|
159
156
|
def prompt_user(self, timeout: int = 10) -> Optional[bool]:
|
|
160
157
|
"""
|
|
161
158
|
Prompt user for auto-configuration with timeout.
|
|
162
|
-
|
|
159
|
+
|
|
163
160
|
Args:
|
|
164
161
|
timeout: Seconds to wait for response (default 10)
|
|
165
|
-
|
|
162
|
+
|
|
166
163
|
Returns:
|
|
167
164
|
True if user agrees, False if declines, None if timeout
|
|
168
165
|
"""
|
|
169
|
-
print("\n" + "="*60)
|
|
166
|
+
print("\n" + "=" * 60)
|
|
170
167
|
print("🔧 MCP Gateway Configuration")
|
|
171
|
-
print("="*60)
|
|
168
|
+
print("=" * 60)
|
|
172
169
|
print("\nClaude MPM can automatically configure MCP Gateway for")
|
|
173
170
|
print("Claude Code integration. This enables advanced features:")
|
|
174
171
|
print(" • File analysis and summarization")
|
|
@@ -177,48 +174,45 @@ class MCPAutoConfigurator:
|
|
|
177
174
|
print(" • And more...")
|
|
178
175
|
print("\nWould you like to configure it now? (y/n)")
|
|
179
176
|
print(f"(Auto-declining in {timeout} seconds)")
|
|
180
|
-
|
|
177
|
+
|
|
181
178
|
# Use threading for cross-platform timeout support
|
|
182
179
|
import threading
|
|
180
|
+
|
|
183
181
|
try:
|
|
184
182
|
# Python 3.7+ has queue built-in
|
|
185
183
|
import queue
|
|
186
184
|
except ImportError:
|
|
187
185
|
# Python 2.x fallback
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
pass
|
|
187
|
+
|
|
190
188
|
user_input = None
|
|
191
|
-
|
|
189
|
+
|
|
192
190
|
def get_input():
|
|
193
191
|
nonlocal user_input
|
|
194
192
|
try:
|
|
195
193
|
user_input = input("> ").strip().lower()
|
|
196
194
|
except (EOFError, KeyboardInterrupt):
|
|
197
|
-
user_input =
|
|
198
|
-
|
|
195
|
+
user_input = "n"
|
|
196
|
+
|
|
199
197
|
# Start input thread
|
|
200
198
|
input_thread = threading.Thread(target=get_input)
|
|
201
199
|
input_thread.daemon = True
|
|
202
200
|
input_thread.start()
|
|
203
|
-
|
|
201
|
+
|
|
204
202
|
# Wait for input or timeout
|
|
205
203
|
input_thread.join(timeout)
|
|
206
|
-
|
|
204
|
+
|
|
207
205
|
if input_thread.is_alive():
|
|
208
206
|
# Timed out
|
|
209
207
|
print("\n(Timed out - declining)")
|
|
210
208
|
return None
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
return True
|
|
215
|
-
else:
|
|
216
|
-
return False
|
|
217
|
-
|
|
209
|
+
# Got input
|
|
210
|
+
return user_input in ["y", "yes"]
|
|
211
|
+
|
|
218
212
|
def auto_configure(self) -> bool:
|
|
219
213
|
"""
|
|
220
214
|
Perform automatic MCP configuration.
|
|
221
|
-
|
|
215
|
+
|
|
222
216
|
Returns:
|
|
223
217
|
True if configuration successful, False otherwise
|
|
224
218
|
"""
|
|
@@ -228,145 +222,143 @@ class MCPAutoConfigurator:
|
|
|
228
222
|
backup_path = self._create_backup()
|
|
229
223
|
if backup_path:
|
|
230
224
|
print(f"✅ Backup created: {backup_path}")
|
|
231
|
-
|
|
225
|
+
|
|
232
226
|
# Load or create configuration
|
|
233
227
|
config = self._load_or_create_config()
|
|
234
|
-
|
|
228
|
+
|
|
235
229
|
# Add MCP Gateway configuration
|
|
236
230
|
if "mcpServers" not in config:
|
|
237
231
|
config["mcpServers"] = {}
|
|
238
|
-
|
|
232
|
+
|
|
239
233
|
# Find claude-mpm executable
|
|
240
234
|
executable = self._find_claude_mpm_executable()
|
|
241
235
|
if not executable:
|
|
242
236
|
print("❌ Could not find claude-mpm executable")
|
|
243
237
|
return False
|
|
244
|
-
|
|
238
|
+
|
|
245
239
|
# Configure MCP server
|
|
246
240
|
config["mcpServers"]["claude-mpm-gateway"] = {
|
|
247
241
|
"command": str(executable),
|
|
248
242
|
"args": ["mcp", "server"],
|
|
249
|
-
"env": {
|
|
250
|
-
"MCP_MODE": "production"
|
|
251
|
-
}
|
|
243
|
+
"env": {"MCP_MODE": "production"},
|
|
252
244
|
}
|
|
253
|
-
|
|
245
|
+
|
|
254
246
|
# Save configuration
|
|
255
|
-
with open(self.claude_config_path,
|
|
247
|
+
with open(self.claude_config_path, "w") as f:
|
|
256
248
|
json.dump(config, f, indent=2)
|
|
257
|
-
|
|
249
|
+
|
|
258
250
|
print(f"✅ Configuration saved to: {self.claude_config_path}")
|
|
259
251
|
print("\n🎉 MCP Gateway configured successfully!")
|
|
260
252
|
print("\nNext steps:")
|
|
261
253
|
print("1. Restart Claude Code (if running)")
|
|
262
254
|
print("2. Look for the MCP icon in the interface")
|
|
263
255
|
print("3. Try @claude-mpm-gateway in a conversation")
|
|
264
|
-
|
|
256
|
+
|
|
265
257
|
return True
|
|
266
|
-
|
|
258
|
+
|
|
267
259
|
except Exception as e:
|
|
268
260
|
self.logger.error(f"Auto-configuration failed: {e}")
|
|
269
261
|
print(f"❌ Configuration failed: {e}")
|
|
270
262
|
print("\nYou can configure manually with:")
|
|
271
263
|
print(" claude-mpm mcp install")
|
|
272
264
|
return False
|
|
273
|
-
|
|
265
|
+
|
|
274
266
|
def _create_backup(self) -> Optional[Path]:
|
|
275
267
|
"""Create backup of existing configuration."""
|
|
276
268
|
try:
|
|
277
269
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
278
|
-
backup_path = self.claude_config_path.with_suffix(
|
|
279
|
-
|
|
270
|
+
backup_path = self.claude_config_path.with_suffix(
|
|
271
|
+
f".backup.{timestamp}.json"
|
|
272
|
+
)
|
|
273
|
+
|
|
280
274
|
import shutil
|
|
275
|
+
|
|
281
276
|
shutil.copy2(self.claude_config_path, backup_path)
|
|
282
277
|
return backup_path
|
|
283
|
-
|
|
278
|
+
|
|
284
279
|
except Exception as e:
|
|
285
280
|
self.logger.debug(f"Could not create backup: {e}")
|
|
286
281
|
return None
|
|
287
|
-
|
|
282
|
+
|
|
288
283
|
def _load_or_create_config(self) -> Dict[str, Any]:
|
|
289
284
|
"""Load existing config or create new one."""
|
|
290
285
|
if self.claude_config_path.exists():
|
|
291
286
|
try:
|
|
292
|
-
with open(self.claude_config_path
|
|
287
|
+
with open(self.claude_config_path) as f:
|
|
293
288
|
return json.load(f)
|
|
294
289
|
except json.JSONDecodeError:
|
|
295
290
|
self.logger.warning("Existing config is invalid JSON, creating new")
|
|
296
|
-
|
|
291
|
+
|
|
297
292
|
return {}
|
|
298
|
-
|
|
293
|
+
|
|
299
294
|
def _find_claude_mpm_executable(self) -> Optional[str]:
|
|
300
295
|
"""Find the claude-mpm executable path."""
|
|
301
296
|
# Try direct command first
|
|
302
|
-
import subprocess
|
|
303
297
|
import platform
|
|
304
|
-
|
|
298
|
+
import subprocess
|
|
299
|
+
|
|
305
300
|
try:
|
|
306
301
|
# Use appropriate command for OS
|
|
307
302
|
if platform.system() == "Windows":
|
|
308
303
|
cmd = ["where", "claude-mpm"]
|
|
309
304
|
else:
|
|
310
305
|
cmd = ["which", "claude-mpm"]
|
|
311
|
-
|
|
306
|
+
|
|
312
307
|
result = subprocess.run(
|
|
313
|
-
cmd,
|
|
314
|
-
capture_output=True,
|
|
315
|
-
text=True,
|
|
316
|
-
timeout=2
|
|
308
|
+
cmd, capture_output=True, text=True, timeout=2, check=False
|
|
317
309
|
)
|
|
318
310
|
if result.returncode == 0:
|
|
319
311
|
executable_path = result.stdout.strip()
|
|
320
312
|
# On Windows, 'where' might return multiple paths
|
|
321
|
-
if platform.system() == "Windows" and
|
|
322
|
-
executable_path = executable_path.split(
|
|
313
|
+
if platform.system() == "Windows" and "\n" in executable_path:
|
|
314
|
+
executable_path = executable_path.split("\n")[0]
|
|
323
315
|
return executable_path
|
|
324
316
|
except Exception:
|
|
325
317
|
pass
|
|
326
|
-
|
|
318
|
+
|
|
327
319
|
# Try to find via shutil.which (more portable)
|
|
328
320
|
import shutil
|
|
321
|
+
|
|
329
322
|
claude_mpm_path = shutil.which("claude-mpm")
|
|
330
323
|
if claude_mpm_path:
|
|
331
324
|
return claude_mpm_path
|
|
332
|
-
|
|
325
|
+
|
|
333
326
|
# Fallback to Python module invocation
|
|
334
327
|
return sys.executable
|
|
335
|
-
|
|
328
|
+
|
|
336
329
|
def run(self) -> bool:
|
|
337
330
|
"""
|
|
338
331
|
Main entry point for auto-configuration.
|
|
339
|
-
|
|
332
|
+
|
|
340
333
|
Returns:
|
|
341
334
|
True if configured (or already configured), False otherwise
|
|
342
335
|
"""
|
|
343
336
|
if not self.should_auto_configure():
|
|
344
337
|
return True # Already configured or not applicable
|
|
345
|
-
|
|
338
|
+
|
|
346
339
|
# Prompt user
|
|
347
340
|
user_choice = self.prompt_user()
|
|
348
|
-
|
|
341
|
+
|
|
349
342
|
# Save preference to not ask again
|
|
350
343
|
self._save_user_preference("yes" if user_choice else "no")
|
|
351
|
-
|
|
344
|
+
|
|
352
345
|
if user_choice:
|
|
353
346
|
return self.auto_configure()
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
return False
|
|
347
|
+
if user_choice is False: # User explicitly said no
|
|
348
|
+
print("\n📝 You can configure MCP later with:")
|
|
349
|
+
print(" claude-mpm mcp install")
|
|
350
|
+
# If timeout (None), don't show additional message
|
|
351
|
+
return False
|
|
360
352
|
|
|
361
353
|
|
|
362
354
|
def check_and_configure_mcp() -> bool:
|
|
363
355
|
"""
|
|
364
356
|
Check and potentially configure MCP for pipx installations.
|
|
365
|
-
|
|
357
|
+
|
|
366
358
|
This is the main entry point called during CLI initialization.
|
|
367
|
-
|
|
359
|
+
|
|
368
360
|
Returns:
|
|
369
361
|
True if MCP is configured (or configuration was successful), False otherwise
|
|
370
362
|
"""
|
|
371
363
|
configurator = MCPAutoConfigurator()
|
|
372
|
-
return configurator.run()
|
|
364
|
+
return configurator.run()
|
|
@@ -42,7 +42,7 @@ class MCPConfigLoader:
|
|
|
42
42
|
".mcp_gateway.yaml",
|
|
43
43
|
".mcp_gateway.yml",
|
|
44
44
|
"config.yaml",
|
|
45
|
-
"config.yml"
|
|
45
|
+
"config.yml",
|
|
46
46
|
],
|
|
47
47
|
search_paths=[
|
|
48
48
|
"~/.claude/mcp",
|
|
@@ -50,15 +50,10 @@ class MCPConfigLoader:
|
|
|
50
50
|
".",
|
|
51
51
|
"./config",
|
|
52
52
|
"./.claude",
|
|
53
|
-
"/etc/claude-mpm"
|
|
53
|
+
"/etc/claude-mpm",
|
|
54
54
|
],
|
|
55
55
|
env_prefix="CLAUDE_MPM_MCP_",
|
|
56
|
-
defaults={
|
|
57
|
-
"host": "localhost",
|
|
58
|
-
"port": 3000,
|
|
59
|
-
"debug": False,
|
|
60
|
-
"timeout": 30
|
|
61
|
-
}
|
|
56
|
+
defaults={"host": "localhost", "port": 3000, "debug": False, "timeout": 30},
|
|
62
57
|
)
|
|
63
58
|
|
|
64
59
|
def __init__(self):
|
|
@@ -102,7 +97,7 @@ class MCPConfigLoader:
|
|
|
102
97
|
self.logger.error(f"Configuration file not found: {expanded_path}")
|
|
103
98
|
return None
|
|
104
99
|
|
|
105
|
-
with open(expanded_path
|
|
100
|
+
with open(expanded_path) as f:
|
|
106
101
|
config = yaml.safe_load(f)
|
|
107
102
|
|
|
108
103
|
self.logger.info(f"Configuration loaded from {expanded_path}")
|
|
@@ -179,42 +174,44 @@ class MCPConfigLoader:
|
|
|
179
174
|
filenames=[config_path.name],
|
|
180
175
|
search_paths=[str(config_path.parent)],
|
|
181
176
|
env_prefix=self.MCP_CONFIG_PATTERN.env_prefix,
|
|
182
|
-
defaults=MCPConfiguration.DEFAULT_CONFIG.copy()
|
|
177
|
+
defaults=MCPConfiguration.DEFAULT_CONFIG.copy(),
|
|
183
178
|
)
|
|
184
|
-
config_obj = self._shared_loader.load_config(
|
|
185
|
-
|
|
186
|
-
else:
|
|
187
|
-
# Use standard MCP pattern with defaults
|
|
188
|
-
pattern = ConfigPattern(
|
|
189
|
-
filenames=self.MCP_CONFIG_PATTERN.filenames,
|
|
190
|
-
search_paths=self.MCP_CONFIG_PATTERN.search_paths,
|
|
191
|
-
env_prefix=self.MCP_CONFIG_PATTERN.env_prefix,
|
|
192
|
-
defaults=MCPConfiguration.DEFAULT_CONFIG.copy()
|
|
179
|
+
config_obj = self._shared_loader.load_config(
|
|
180
|
+
pattern, cache_key=f"mcp_{config_path}"
|
|
193
181
|
)
|
|
194
|
-
config_obj = self._shared_loader.load_config(pattern, cache_key="mcp_gateway")
|
|
195
182
|
return config_obj.to_dict()
|
|
183
|
+
# Use standard MCP pattern with defaults
|
|
184
|
+
pattern = ConfigPattern(
|
|
185
|
+
filenames=self.MCP_CONFIG_PATTERN.filenames,
|
|
186
|
+
search_paths=self.MCP_CONFIG_PATTERN.search_paths,
|
|
187
|
+
env_prefix=self.MCP_CONFIG_PATTERN.env_prefix,
|
|
188
|
+
defaults=MCPConfiguration.DEFAULT_CONFIG.copy(),
|
|
189
|
+
)
|
|
190
|
+
config_obj = self._shared_loader.load_config(pattern, cache_key="mcp_gateway")
|
|
191
|
+
return config_obj.to_dict()
|
|
196
192
|
|
|
197
193
|
# Backward compatibility methods (deprecated)
|
|
198
194
|
def find_config_file(self) -> Optional[Path]:
|
|
199
195
|
"""Find configuration file using legacy method (deprecated)."""
|
|
200
196
|
import warnings
|
|
197
|
+
|
|
201
198
|
warnings.warn(
|
|
202
199
|
"find_config_file is deprecated. Use load() method instead.",
|
|
203
200
|
DeprecationWarning,
|
|
204
|
-
stacklevel=2
|
|
201
|
+
stacklevel=2,
|
|
205
202
|
)
|
|
206
203
|
|
|
207
204
|
# Use shared loader to find config file
|
|
208
|
-
|
|
209
|
-
return config_file
|
|
205
|
+
return self._shared_loader._find_config_file(self.MCP_CONFIG_PATTERN)
|
|
210
206
|
|
|
211
207
|
def load_from_file(self, config_path: Path) -> Optional[dict]:
|
|
212
208
|
"""Load from file using legacy method (deprecated)."""
|
|
213
209
|
import warnings
|
|
210
|
+
|
|
214
211
|
warnings.warn(
|
|
215
212
|
"load_from_file is deprecated. Use load() method instead.",
|
|
216
213
|
DeprecationWarning,
|
|
217
|
-
stacklevel=2
|
|
214
|
+
stacklevel=2,
|
|
218
215
|
)
|
|
219
216
|
|
|
220
217
|
# Use shared loader
|
|
@@ -223,10 +220,11 @@ class MCPConfigLoader:
|
|
|
223
220
|
def load_from_env(self, prefix: str = "CLAUDE_MPM_MCP_") -> dict:
|
|
224
221
|
"""Load from environment using legacy method (deprecated)."""
|
|
225
222
|
import warnings
|
|
223
|
+
|
|
226
224
|
warnings.warn(
|
|
227
225
|
"load_from_env is deprecated. Use load() method instead.",
|
|
228
226
|
DeprecationWarning,
|
|
229
|
-
stacklevel=2
|
|
227
|
+
stacklevel=2,
|
|
230
228
|
)
|
|
231
229
|
|
|
232
230
|
# Use shared loader
|
|
@@ -175,19 +175,19 @@ def validate_config(
|
|
|
175
175
|
if expected_type == "object" and not isinstance(value, dict):
|
|
176
176
|
errors.append(f"{path}: Expected object, got {type(value).__name__}")
|
|
177
177
|
return
|
|
178
|
-
|
|
178
|
+
if expected_type == "array" and not isinstance(value, list):
|
|
179
179
|
errors.append(f"{path}: Expected array, got {type(value).__name__}")
|
|
180
180
|
return
|
|
181
|
-
|
|
181
|
+
if expected_type == "string" and not isinstance(value, str):
|
|
182
182
|
errors.append(f"{path}: Expected string, got {type(value).__name__}")
|
|
183
183
|
return
|
|
184
|
-
|
|
184
|
+
if expected_type == "number" and not isinstance(value, (int, float)):
|
|
185
185
|
errors.append(f"{path}: Expected number, got {type(value).__name__}")
|
|
186
186
|
return
|
|
187
|
-
|
|
187
|
+
if expected_type == "integer" and not isinstance(value, int):
|
|
188
188
|
errors.append(f"{path}: Expected integer, got {type(value).__name__}")
|
|
189
189
|
return
|
|
190
|
-
|
|
190
|
+
if expected_type == "boolean" and not isinstance(value, bool):
|
|
191
191
|
errors.append(f"{path}: Expected boolean, got {type(value).__name__}")
|
|
192
192
|
return
|
|
193
193
|
|
|
@@ -106,9 +106,8 @@ class MCPConfiguration(BaseMCPService, IMCPConfiguration):
|
|
|
106
106
|
self._config_data = self.DEFAULT_CONFIG.copy()
|
|
107
107
|
|
|
108
108
|
# Load from file if path provided
|
|
109
|
-
if self._config_path:
|
|
110
|
-
|
|
111
|
-
return False
|
|
109
|
+
if self._config_path and not self.load_config(self._config_path):
|
|
110
|
+
return False
|
|
112
111
|
|
|
113
112
|
# Apply environment variable overrides
|
|
114
113
|
self._apply_env_overrides()
|
|
@@ -139,7 +138,7 @@ class MCPConfiguration(BaseMCPService, IMCPConfiguration):
|
|
|
139
138
|
self.log_warning(f"Configuration file not found: {config_path}")
|
|
140
139
|
return True # Not an error, use defaults
|
|
141
140
|
|
|
142
|
-
with open(config_path
|
|
141
|
+
with open(config_path) as f:
|
|
143
142
|
if config_path.suffix in [".yaml", ".yml"]:
|
|
144
143
|
loaded_config = yaml.safe_load(f) or {}
|
|
145
144
|
else:
|
|
@@ -384,7 +383,9 @@ class MCPConfiguration(BaseMCPService, IMCPConfiguration):
|
|
|
384
383
|
# Revalidate
|
|
385
384
|
return self.validate()
|
|
386
385
|
|
|
387
|
-
def get_config_with_validation(
|
|
386
|
+
def get_config_with_validation(
|
|
387
|
+
self, key: str, default: Any = None, config_type: Optional[type] = None
|
|
388
|
+
) -> Any:
|
|
388
389
|
"""
|
|
389
390
|
Get configuration value with validation using shared utilities.
|
|
390
391
|
|
|
@@ -397,7 +398,9 @@ class MCPConfiguration(BaseMCPService, IMCPConfiguration):
|
|
|
397
398
|
Configuration value
|
|
398
399
|
"""
|
|
399
400
|
try:
|
|
400
|
-
return self._config_helper.get_config_value(
|
|
401
|
+
return self._config_helper.get_config_value(
|
|
402
|
+
key, default, config_type=config_type
|
|
403
|
+
)
|
|
401
404
|
except ValueError:
|
|
402
405
|
# Fall back to standard get method
|
|
403
406
|
return self.get(key, default)
|
|
@@ -24,21 +24,21 @@ from .interfaces import (
|
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
__all__ = [
|
|
27
|
+
# Base classes
|
|
28
|
+
"BaseMCPService",
|
|
29
|
+
"IMCPCommunication",
|
|
30
|
+
"IMCPConfiguration",
|
|
27
31
|
# Interfaces
|
|
28
32
|
"IMCPGateway",
|
|
29
|
-
"IMCPToolRegistry",
|
|
30
|
-
"IMCPConfiguration",
|
|
31
|
-
"IMCPToolAdapter",
|
|
32
33
|
"IMCPLifecycle",
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
"
|
|
34
|
+
"IMCPToolAdapter",
|
|
35
|
+
"IMCPToolRegistry",
|
|
36
|
+
"MCPCommunicationError",
|
|
37
|
+
"MCPConfigurationError",
|
|
37
38
|
# Exceptions
|
|
38
39
|
"MCPException",
|
|
39
|
-
"MCPConfigurationError",
|
|
40
|
-
"MCPToolNotFoundError",
|
|
41
40
|
"MCPServerError",
|
|
42
|
-
"
|
|
41
|
+
"MCPServiceState",
|
|
42
|
+
"MCPToolNotFoundError",
|
|
43
43
|
"MCPValidationError",
|
|
44
44
|
]
|