claude-mpm 4.7.4__py3-none-any.whl → 4.18.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/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
- claude_mpm/agents/BASE_ENGINEER.md +286 -0
- claude_mpm/agents/BASE_PM.md +106 -1
- claude_mpm/agents/OUTPUT_STYLE.md +329 -11
- claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
- claude_mpm/agents/agent_loader.py +17 -5
- claude_mpm/agents/frontmatter_validator.py +284 -253
- claude_mpm/agents/templates/README.md +465 -0
- claude_mpm/agents/templates/agent-manager.json +4 -1
- claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
- claude_mpm/agents/templates/api_qa.json +11 -2
- claude_mpm/agents/templates/circuit_breakers.md +638 -0
- claude_mpm/agents/templates/clerk-ops.json +12 -2
- claude_mpm/agents/templates/code_analyzer.json +8 -2
- claude_mpm/agents/templates/content-agent.json +358 -0
- claude_mpm/agents/templates/dart_engineer.json +15 -2
- claude_mpm/agents/templates/data_engineer.json +15 -2
- claude_mpm/agents/templates/documentation.json +10 -2
- claude_mpm/agents/templates/engineer.json +21 -1
- claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
- claude_mpm/agents/templates/git_file_tracking.md +584 -0
- claude_mpm/agents/templates/golang_engineer.json +270 -0
- claude_mpm/agents/templates/imagemagick.json +4 -1
- claude_mpm/agents/templates/java_engineer.json +346 -0
- claude_mpm/agents/templates/local_ops_agent.json +1227 -6
- claude_mpm/agents/templates/memory_manager.json +4 -1
- claude_mpm/agents/templates/nextjs_engineer.json +141 -133
- claude_mpm/agents/templates/ops.json +12 -2
- claude_mpm/agents/templates/php-engineer.json +270 -174
- claude_mpm/agents/templates/pm_examples.md +474 -0
- claude_mpm/agents/templates/pm_red_flags.md +240 -0
- claude_mpm/agents/templates/product_owner.json +338 -0
- claude_mpm/agents/templates/project_organizer.json +14 -4
- claude_mpm/agents/templates/prompt-engineer.json +13 -2
- claude_mpm/agents/templates/python_engineer.json +174 -81
- claude_mpm/agents/templates/qa.json +11 -2
- claude_mpm/agents/templates/react_engineer.json +16 -3
- claude_mpm/agents/templates/refactoring_engineer.json +12 -2
- claude_mpm/agents/templates/research.json +34 -21
- claude_mpm/agents/templates/response_format.md +583 -0
- claude_mpm/agents/templates/ruby-engineer.json +129 -192
- claude_mpm/agents/templates/rust_engineer.json +270 -0
- claude_mpm/agents/templates/security.json +10 -2
- claude_mpm/agents/templates/svelte-engineer.json +225 -0
- claude_mpm/agents/templates/ticketing.json +10 -2
- claude_mpm/agents/templates/typescript_engineer.json +116 -125
- claude_mpm/agents/templates/validation_templates.md +312 -0
- claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
- claude_mpm/agents/templates/version_control.json +12 -2
- claude_mpm/agents/templates/web_qa.json +11 -2
- claude_mpm/agents/templates/web_ui.json +15 -2
- claude_mpm/cli/__init__.py +34 -614
- claude_mpm/cli/commands/agent_manager.py +25 -12
- claude_mpm/cli/commands/agent_state_manager.py +186 -0
- claude_mpm/cli/commands/agents.py +235 -148
- claude_mpm/cli/commands/agents_detect.py +380 -0
- claude_mpm/cli/commands/agents_recommend.py +309 -0
- claude_mpm/cli/commands/aggregate.py +7 -3
- claude_mpm/cli/commands/analyze.py +9 -4
- claude_mpm/cli/commands/analyze_code.py +7 -2
- claude_mpm/cli/commands/auto_configure.py +570 -0
- claude_mpm/cli/commands/config.py +47 -13
- claude_mpm/cli/commands/configure.py +419 -1571
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +167 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/local_deploy.py +537 -0
- claude_mpm/cli/commands/memory.py +54 -20
- claude_mpm/cli/commands/mpm_init.py +585 -196
- claude_mpm/cli/commands/mpm_init_handler.py +37 -3
- claude_mpm/cli/commands/search.py +170 -4
- claude_mpm/cli/commands/upgrade.py +152 -0
- claude_mpm/cli/executor.py +202 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +3 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/agents_parser.py +9 -0
- claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
- claude_mpm/cli/parsers/base_parser.py +110 -3
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +481 -0
- claude_mpm/cli/utils.py +52 -1
- claude_mpm/commands/mpm-agents-detect.md +168 -0
- claude_mpm/commands/mpm-agents-recommend.md +214 -0
- claude_mpm/commands/mpm-agents.md +75 -1
- claude_mpm/commands/mpm-auto-configure.md +217 -0
- claude_mpm/commands/mpm-help.md +163 -0
- claude_mpm/commands/mpm-init.md +148 -3
- claude_mpm/commands/mpm-version.md +113 -0
- claude_mpm/commands/mpm.md +1 -0
- claude_mpm/config/agent_config.py +2 -2
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/constants.py +1 -0
- claude_mpm/core/base_service.py +13 -12
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/instruction_reinforcement_hook.py +2 -1
- claude_mpm/core/interactive_session.py +9 -3
- claude_mpm/core/log_manager.py +2 -0
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/oneshot_session.py +8 -4
- claude_mpm/core/optimized_agent_loader.py +3 -3
- claude_mpm/core/output_style_manager.py +12 -192
- claude_mpm/core/service_registry.py +5 -1
- claude_mpm/core/types.py +2 -9
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/dashboard/static/js/dashboard.js +0 -14
- claude_mpm/dashboard/templates/index.html +3 -41
- claude_mpm/hooks/__init__.py +20 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
- claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
- claude_mpm/hooks/failure_learning/__init__.py +60 -0
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
- claude_mpm/hooks/instruction_reinforcement.py +7 -2
- claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
- claude_mpm/hooks/kuzu_memory_hook.py +37 -12
- claude_mpm/hooks/kuzu_response_hook.py +183 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/services/agents/__init__.py +18 -5
- claude_mpm/services/agents/auto_config_manager.py +796 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
- claude_mpm/services/agents/deployment/agent_validator.py +17 -1
- claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/local_template_manager.py +1 -1
- claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
- claude_mpm/services/agents/observers.py +547 -0
- claude_mpm/services/agents/recommender.py +568 -0
- claude_mpm/services/agents/registry/modification_tracker.py +5 -2
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/__init__.py +33 -1
- claude_mpm/services/core/interfaces/__init__.py +90 -3
- claude_mpm/services/core/interfaces/agent.py +184 -0
- claude_mpm/services/core/interfaces/health.py +172 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/project.py +121 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/memory_manager.py +11 -24
- claude_mpm/services/core/models/__init__.py +79 -0
- claude_mpm/services/core/models/agent_config.py +381 -0
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +235 -0
- claude_mpm/services/core/models/restart.py +302 -0
- claude_mpm/services/core/models/stability.py +264 -0
- claude_mpm/services/core/models/toolchain.py +306 -0
- claude_mpm/services/core/path_resolver.py +23 -7
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
- claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
- claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
- claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
- claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
- claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
- claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
- claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
- claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
- claude_mpm/services/diagnostics/models.py +19 -24
- claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
- claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/local_ops/__init__.py +163 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +430 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +9 -4
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +18 -31
- claude_mpm/services/mcp_gateway/main.py +30 -0
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
- claude_mpm/services/mcp_service_verifier.py +1 -1
- claude_mpm/services/memory/failure_tracker.py +563 -0
- claude_mpm/services/memory_hook_service.py +165 -4
- claude_mpm/services/model/__init__.py +147 -0
- claude_mpm/services/model/base_provider.py +365 -0
- claude_mpm/services/model/claude_provider.py +412 -0
- claude_mpm/services/model/model_router.py +453 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/daemon_manager.py +3 -2
- claude_mpm/services/monitor/handlers/dashboard.py +2 -1
- claude_mpm/services/monitor/handlers/hooks.py +2 -1
- claude_mpm/services/monitor/management/lifecycle.py +3 -2
- claude_mpm/services/monitor/server.py +2 -1
- claude_mpm/services/project/__init__.py +23 -0
- claude_mpm/services/project/detection_strategies.py +719 -0
- claude_mpm/services/project/toolchain_analyzer.py +581 -0
- claude_mpm/services/self_upgrade_service.py +342 -0
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/session_manager.py +205 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/hook.py +13 -2
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/server/main.py +10 -8
- claude_mpm/services/subprocess_launcher_service.py +14 -5
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
- claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
- claude_mpm/services/unified/deployment_strategies/local.py +6 -5
- claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
- claude_mpm/services/unified/interfaces.py +3 -1
- claude_mpm/services/unified/unified_analyzer.py +14 -10
- claude_mpm/services/unified/unified_config.py +2 -1
- claude_mpm/services/unified/unified_deployment.py +9 -4
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/skills/__init__.py +21 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +567 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +310 -0
- claude_mpm/storage/state_storage.py +15 -15
- claude_mpm/tools/code_tree_analyzer.py +177 -141
- claude_mpm/tools/code_tree_events.py +4 -2
- claude_mpm/utils/agent_dependency_loader.py +40 -20
- claude_mpm/utils/display_helper.py +260 -0
- claude_mpm/utils/git_analyzer.py +407 -0
- claude_mpm/utils/robust_installer.py +73 -19
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
- claude_mpm/dashboard/static/css/code-tree.css +0 -1639
- claude_mpm/dashboard/static/index-hub-backup.html +0 -713
- claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/top_level.txt +0 -0
|
@@ -8,25 +8,12 @@ Part of ISS-0034: Infrastructure Setup - MCP Gateway Project Foundation
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import asyncio
|
|
11
|
-
from enum import Enum
|
|
12
11
|
from typing import Any, Dict, Optional
|
|
13
12
|
|
|
13
|
+
from claude_mpm.core.enums import ServiceState
|
|
14
14
|
from claude_mpm.services.core.base import BaseService
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
class MCPServiceState(Enum):
|
|
18
|
-
"""MCP service lifecycle states."""
|
|
19
|
-
|
|
20
|
-
UNINITIALIZED = "uninitialized"
|
|
21
|
-
INITIALIZING = "initializing"
|
|
22
|
-
INITIALIZED = "initialized"
|
|
23
|
-
STARTING = "starting"
|
|
24
|
-
RUNNING = "running"
|
|
25
|
-
STOPPING = "stopping"
|
|
26
|
-
STOPPED = "stopped"
|
|
27
|
-
ERROR = "error"
|
|
28
|
-
|
|
29
|
-
|
|
30
17
|
class BaseMCPService(BaseService):
|
|
31
18
|
"""
|
|
32
19
|
Base class for all MCP Gateway services.
|
|
@@ -53,7 +40,7 @@ class BaseMCPService(BaseService):
|
|
|
53
40
|
config: Service-specific configuration
|
|
54
41
|
"""
|
|
55
42
|
super().__init__(service_name or "MCPService", config)
|
|
56
|
-
self._state =
|
|
43
|
+
self._state = ServiceState.UNINITIALIZED
|
|
57
44
|
self._health_status = {
|
|
58
45
|
"healthy": False,
|
|
59
46
|
"state": self._state.value,
|
|
@@ -76,13 +63,13 @@ class BaseMCPService(BaseService):
|
|
|
76
63
|
"""
|
|
77
64
|
async with self._state_lock:
|
|
78
65
|
if self._state not in [
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
ServiceState.UNINITIALIZED,
|
|
67
|
+
ServiceState.STOPPED,
|
|
81
68
|
]:
|
|
82
69
|
self.log_warning(f"Cannot initialize from state {self._state.value}")
|
|
83
70
|
return False
|
|
84
71
|
|
|
85
|
-
self._state =
|
|
72
|
+
self._state = ServiceState.INITIALIZING
|
|
86
73
|
self.log_info("Initializing MCP service")
|
|
87
74
|
|
|
88
75
|
try:
|
|
@@ -91,13 +78,13 @@ class BaseMCPService(BaseService):
|
|
|
91
78
|
|
|
92
79
|
async with self._state_lock:
|
|
93
80
|
if success:
|
|
94
|
-
self._state =
|
|
81
|
+
self._state = ServiceState.INITIALIZED
|
|
95
82
|
self._initialized = True
|
|
96
83
|
self._health_status["healthy"] = True
|
|
97
84
|
self._health_status["state"] = self._state.value
|
|
98
85
|
self.log_info("MCP service initialized successfully")
|
|
99
86
|
else:
|
|
100
|
-
self._state =
|
|
87
|
+
self._state = ServiceState.ERROR
|
|
101
88
|
self._health_status["healthy"] = False
|
|
102
89
|
self._health_status["state"] = self._state.value
|
|
103
90
|
self.log_error("MCP service initialization failed")
|
|
@@ -106,7 +93,7 @@ class BaseMCPService(BaseService):
|
|
|
106
93
|
|
|
107
94
|
except Exception as e:
|
|
108
95
|
async with self._state_lock:
|
|
109
|
-
self._state =
|
|
96
|
+
self._state = ServiceState.ERROR
|
|
110
97
|
self._health_status["healthy"] = False
|
|
111
98
|
self._health_status["state"] = self._state.value
|
|
112
99
|
self._health_status["details"]["error"] = str(e)
|
|
@@ -134,11 +121,11 @@ class BaseMCPService(BaseService):
|
|
|
134
121
|
True if startup successful
|
|
135
122
|
"""
|
|
136
123
|
async with self._state_lock:
|
|
137
|
-
if self._state !=
|
|
124
|
+
if self._state != ServiceState.INITIALIZED:
|
|
138
125
|
self.log_warning(f"Cannot start from state {self._state.value}")
|
|
139
126
|
return False
|
|
140
127
|
|
|
141
|
-
self._state =
|
|
128
|
+
self._state = ServiceState.STARTING
|
|
142
129
|
self.log_info("Starting MCP service")
|
|
143
130
|
|
|
144
131
|
try:
|
|
@@ -146,12 +133,12 @@ class BaseMCPService(BaseService):
|
|
|
146
133
|
|
|
147
134
|
async with self._state_lock:
|
|
148
135
|
if success:
|
|
149
|
-
self._state =
|
|
136
|
+
self._state = ServiceState.RUNNING
|
|
150
137
|
self._health_status["healthy"] = True
|
|
151
138
|
self._health_status["state"] = self._state.value
|
|
152
139
|
self.log_info("MCP service started successfully")
|
|
153
140
|
else:
|
|
154
|
-
self._state =
|
|
141
|
+
self._state = ServiceState.ERROR
|
|
155
142
|
self._health_status["healthy"] = False
|
|
156
143
|
self._health_status["state"] = self._state.value
|
|
157
144
|
self.log_error("MCP service startup failed")
|
|
@@ -160,7 +147,7 @@ class BaseMCPService(BaseService):
|
|
|
160
147
|
|
|
161
148
|
except Exception as e:
|
|
162
149
|
async with self._state_lock:
|
|
163
|
-
self._state =
|
|
150
|
+
self._state = ServiceState.ERROR
|
|
164
151
|
self._health_status["healthy"] = False
|
|
165
152
|
self._health_status["state"] = self._state.value
|
|
166
153
|
self._health_status["details"]["error"] = str(e)
|
|
@@ -188,18 +175,18 @@ class BaseMCPService(BaseService):
|
|
|
188
175
|
Subclasses should override _do_shutdown() for custom shutdown logic.
|
|
189
176
|
"""
|
|
190
177
|
async with self._state_lock:
|
|
191
|
-
if self._state in [
|
|
178
|
+
if self._state in [ServiceState.STOPPED, ServiceState.STOPPING]:
|
|
192
179
|
self.log_warning(f"Already in state {self._state.value}")
|
|
193
180
|
return
|
|
194
181
|
|
|
195
|
-
self._state =
|
|
182
|
+
self._state = ServiceState.STOPPING
|
|
196
183
|
self.log_info("Shutting down MCP service")
|
|
197
184
|
|
|
198
185
|
try:
|
|
199
186
|
await self._do_shutdown()
|
|
200
187
|
|
|
201
188
|
async with self._state_lock:
|
|
202
|
-
self._state =
|
|
189
|
+
self._state = ServiceState.STOPPED
|
|
203
190
|
self._shutdown = True
|
|
204
191
|
self._health_status["healthy"] = False
|
|
205
192
|
self._health_status["state"] = self._state.value
|
|
@@ -207,7 +194,7 @@ class BaseMCPService(BaseService):
|
|
|
207
194
|
|
|
208
195
|
except Exception as e:
|
|
209
196
|
async with self._state_lock:
|
|
210
|
-
self._state =
|
|
197
|
+
self._state = ServiceState.ERROR
|
|
211
198
|
self._health_status["healthy"] = False
|
|
212
199
|
self._health_status["state"] = self._state.value
|
|
213
200
|
self._health_status["details"]["error"] = str(e)
|
|
@@ -232,7 +219,7 @@ class BaseMCPService(BaseService):
|
|
|
232
219
|
self.log_info("Restarting MCP service")
|
|
233
220
|
|
|
234
221
|
# Shutdown if running
|
|
235
|
-
if self._state ==
|
|
222
|
+
if self._state == ServiceState.RUNNING:
|
|
236
223
|
await self.shutdown()
|
|
237
224
|
|
|
238
225
|
# Re-initialize
|
|
@@ -314,6 +314,36 @@ class MCPGatewayOrchestrator:
|
|
|
314
314
|
except Exception as e:
|
|
315
315
|
self.logger.warning(f"Could not load document summarizer: {e}")
|
|
316
316
|
|
|
317
|
+
# Kuzu-Memory Service (now a required dependency)
|
|
318
|
+
try:
|
|
319
|
+
from .tools.kuzu_memory_service import KuzuMemoryService
|
|
320
|
+
|
|
321
|
+
tools.append(KuzuMemoryService())
|
|
322
|
+
self.logger.info("KuzuMemoryService added to built-in tools")
|
|
323
|
+
except Exception as e:
|
|
324
|
+
self.logger.warning(f"Could not load KuzuMemoryService: {e}")
|
|
325
|
+
|
|
326
|
+
# MCP Vector Search Service (optional - will auto-install on first use)
|
|
327
|
+
try:
|
|
328
|
+
from .tools.external_mcp_services import MCPVectorSearchService
|
|
329
|
+
|
|
330
|
+
vector_search = MCPVectorSearchService()
|
|
331
|
+
# Try to initialize without interactive prompts during gateway startup
|
|
332
|
+
# This will only succeed if already installed
|
|
333
|
+
init_success = await vector_search.initialize(
|
|
334
|
+
auto_install=False, interactive=False
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
if init_success:
|
|
338
|
+
tools.append(vector_search)
|
|
339
|
+
self.logger.info("MCPVectorSearchService added to built-in tools")
|
|
340
|
+
else:
|
|
341
|
+
self.logger.debug(
|
|
342
|
+
"mcp-vector-search not installed - will be available via auto-install on first use"
|
|
343
|
+
)
|
|
344
|
+
except Exception as e:
|
|
345
|
+
self.logger.debug(f"Could not load MCPVectorSearchService: {e}")
|
|
346
|
+
|
|
317
347
|
# Ticket tools removed - mcp-ticketer provides ticket functionality
|
|
318
348
|
|
|
319
349
|
if not tools:
|
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
External MCP Services Integration
|
|
3
3
|
==================================
|
|
4
4
|
|
|
5
|
-
Manages
|
|
5
|
+
Manages detection and setup of external MCP services like mcp-vector-search
|
|
6
6
|
and mcp-browser. These services run as separate MCP servers in Claude Code,
|
|
7
7
|
not as part of the Claude MPM MCP Gateway.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
IMPORTANT: External services are NOT auto-installed. Users must manually install
|
|
10
|
+
them using pipx or pip. This gives users explicit control over which optional
|
|
11
|
+
services they want to enable.
|
|
12
|
+
|
|
13
|
+
Installation:
|
|
14
|
+
pipx install mcp-vector-search
|
|
15
|
+
pipx install mcp-browser
|
|
16
|
+
pipx install kuzu-memory
|
|
17
|
+
pipx install mcp-ticketer
|
|
18
|
+
|
|
19
|
+
Note: External services are registered as separate MCP servers in Claude Code
|
|
20
|
+
configuration, not as tools within the gateway.
|
|
11
21
|
"""
|
|
12
22
|
|
|
13
23
|
import json
|
|
@@ -20,7 +30,12 @@ from claude_mpm.services.mcp_gateway.tools.base_adapter import BaseToolAdapter
|
|
|
20
30
|
|
|
21
31
|
|
|
22
32
|
class ExternalMCPService(BaseToolAdapter):
|
|
23
|
-
"""Base class for external MCP service integration.
|
|
33
|
+
"""Base class for external MCP service integration.
|
|
34
|
+
|
|
35
|
+
External services are detected if already installed but are NOT
|
|
36
|
+
automatically installed. Users must install them manually using
|
|
37
|
+
pipx or pip to enable these optional features.
|
|
38
|
+
"""
|
|
24
39
|
|
|
25
40
|
def __init__(self, service_name: str, package_name: str):
|
|
26
41
|
"""
|
|
@@ -64,21 +79,38 @@ class ExternalMCPService(BaseToolAdapter):
|
|
|
64
79
|
execution_time=0.0,
|
|
65
80
|
)
|
|
66
81
|
|
|
67
|
-
async def initialize(
|
|
68
|
-
|
|
82
|
+
async def initialize(
|
|
83
|
+
self, auto_install: bool = False, interactive: bool = False
|
|
84
|
+
) -> bool:
|
|
85
|
+
"""Initialize the external service.
|
|
86
|
+
|
|
87
|
+
NOTE: Auto-installation is disabled by default (v4.9.0+). Users must
|
|
88
|
+
manually install external services using pipx or pip.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
auto_install: Whether to automatically install if not found (default: False)
|
|
92
|
+
Deprecated - will be removed in future versions
|
|
93
|
+
interactive: Whether to prompt user for installation preferences (default: False)
|
|
94
|
+
Only used if auto_install=True
|
|
95
|
+
"""
|
|
69
96
|
try:
|
|
70
97
|
# Check if package is installed
|
|
71
98
|
self._is_installed = await self._check_installation()
|
|
72
99
|
|
|
73
|
-
if not self._is_installed:
|
|
74
|
-
|
|
75
|
-
|
|
100
|
+
if not self._is_installed and auto_install:
|
|
101
|
+
# This path is deprecated but kept for backward compatibility
|
|
102
|
+
self.logger.warning(
|
|
103
|
+
f"Auto-installation is deprecated. Please install {self.package_name} manually: "
|
|
104
|
+
f"pipx install {self.package_name}"
|
|
76
105
|
)
|
|
77
|
-
await self._install_package()
|
|
106
|
+
await self._install_package(interactive=interactive)
|
|
78
107
|
self._is_installed = await self._check_installation()
|
|
79
108
|
|
|
80
109
|
if not self._is_installed:
|
|
81
|
-
self.logger.
|
|
110
|
+
self.logger.debug(
|
|
111
|
+
f"{self.package_name} is not available. "
|
|
112
|
+
f"Install manually with: pipx install {self.package_name}"
|
|
113
|
+
)
|
|
82
114
|
return False
|
|
83
115
|
|
|
84
116
|
self.logger.info(f"{self.package_name} is available")
|
|
@@ -90,9 +122,21 @@ class ExternalMCPService(BaseToolAdapter):
|
|
|
90
122
|
|
|
91
123
|
async def _check_installation(self) -> bool:
|
|
92
124
|
"""Check if the package is installed."""
|
|
125
|
+
# First check if importable (faster and more reliable)
|
|
126
|
+
import_name = self.package_name.replace("-", "_")
|
|
127
|
+
try:
|
|
128
|
+
import importlib.util
|
|
129
|
+
|
|
130
|
+
spec = importlib.util.find_spec(import_name)
|
|
131
|
+
if spec is not None:
|
|
132
|
+
return True
|
|
133
|
+
except (ImportError, ModuleNotFoundError, ValueError):
|
|
134
|
+
pass
|
|
135
|
+
|
|
136
|
+
# Fallback: try running as module
|
|
93
137
|
try:
|
|
94
138
|
result = subprocess.run(
|
|
95
|
-
[sys.executable, "-m",
|
|
139
|
+
[sys.executable, "-m", import_name, "--help"],
|
|
96
140
|
capture_output=True,
|
|
97
141
|
text=True,
|
|
98
142
|
timeout=5,
|
|
@@ -106,25 +150,133 @@ class ExternalMCPService(BaseToolAdapter):
|
|
|
106
150
|
):
|
|
107
151
|
return False
|
|
108
152
|
|
|
109
|
-
async def _install_package(self) -> bool:
|
|
110
|
-
"""Install the package using pip.
|
|
153
|
+
async def _install_package(self, interactive: bool = True) -> bool:
|
|
154
|
+
"""Install the package using pip or pipx.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
interactive: Whether to prompt user for installation method choice
|
|
158
|
+
"""
|
|
111
159
|
try:
|
|
112
|
-
|
|
160
|
+
install_method = None
|
|
161
|
+
|
|
162
|
+
if interactive:
|
|
163
|
+
# Show user-friendly installation prompt
|
|
164
|
+
print(f"\n⚠️ {self.package_name} not found")
|
|
165
|
+
print("This package enables enhanced functionality (optional).")
|
|
166
|
+
print("\nInstallation options:")
|
|
167
|
+
print("1. Install via pip (recommended for this project)")
|
|
168
|
+
print("2. Install via pipx (isolated, system-wide)")
|
|
169
|
+
print("3. Skip (continue without this package)")
|
|
170
|
+
|
|
171
|
+
try:
|
|
172
|
+
choice = input("\nChoose option (1/2/3) [1]: ").strip() or "1"
|
|
173
|
+
if choice == "1":
|
|
174
|
+
install_method = "pip"
|
|
175
|
+
elif choice == "2":
|
|
176
|
+
install_method = "pipx"
|
|
177
|
+
else:
|
|
178
|
+
self.logger.info(
|
|
179
|
+
f"Skipping installation of {self.package_name}"
|
|
180
|
+
)
|
|
181
|
+
return False
|
|
182
|
+
except (EOFError, KeyboardInterrupt):
|
|
183
|
+
print("\nInstallation cancelled")
|
|
184
|
+
return False
|
|
185
|
+
else:
|
|
186
|
+
# Non-interactive: default to pip
|
|
187
|
+
install_method = "pip"
|
|
188
|
+
|
|
189
|
+
# Install using selected method
|
|
190
|
+
if install_method == "pip":
|
|
191
|
+
return await self._install_via_pip()
|
|
192
|
+
if install_method == "pipx":
|
|
193
|
+
return await self._install_via_pipx()
|
|
194
|
+
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
except Exception as e:
|
|
198
|
+
self.logger.error(f"Error installing {self.package_name}: {e}")
|
|
199
|
+
return False
|
|
200
|
+
|
|
201
|
+
async def _install_via_pip(self) -> bool:
|
|
202
|
+
"""Install package via pip."""
|
|
203
|
+
try:
|
|
204
|
+
print(f"\n📦 Installing {self.package_name} via pip...")
|
|
113
205
|
result = subprocess.run(
|
|
114
206
|
[sys.executable, "-m", "pip", "install", self.package_name],
|
|
115
207
|
capture_output=True,
|
|
116
208
|
text=True,
|
|
117
|
-
timeout=
|
|
209
|
+
timeout=120,
|
|
118
210
|
check=False,
|
|
119
211
|
)
|
|
120
212
|
|
|
121
213
|
if result.returncode == 0:
|
|
122
|
-
|
|
214
|
+
print(f"✓ Successfully installed {self.package_name}")
|
|
215
|
+
self.logger.info(f"Successfully installed {self.package_name} via pip")
|
|
123
216
|
return True
|
|
124
|
-
|
|
217
|
+
|
|
218
|
+
error_msg = result.stderr.strip() if result.stderr else "Unknown error"
|
|
219
|
+
print(f"✗ Installation failed: {error_msg}")
|
|
220
|
+
self.logger.error(f"Failed to install {self.package_name}: {error_msg}")
|
|
221
|
+
return False
|
|
222
|
+
|
|
223
|
+
except subprocess.TimeoutExpired:
|
|
224
|
+
print("✗ Installation timed out")
|
|
225
|
+
self.logger.error(f"Installation of {self.package_name} timed out")
|
|
226
|
+
return False
|
|
227
|
+
except Exception as e:
|
|
228
|
+
print(f"✗ Installation error: {e}")
|
|
229
|
+
self.logger.error(f"Error installing {self.package_name}: {e}")
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
async def _install_via_pipx(self) -> bool:
|
|
233
|
+
"""Install package via pipx."""
|
|
234
|
+
try:
|
|
235
|
+
# Check if pipx is available
|
|
236
|
+
pipx_check = subprocess.run(
|
|
237
|
+
["pipx", "--version"],
|
|
238
|
+
capture_output=True,
|
|
239
|
+
text=True,
|
|
240
|
+
timeout=5,
|
|
241
|
+
check=False,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
if pipx_check.returncode != 0:
|
|
245
|
+
print("✗ pipx is not installed")
|
|
246
|
+
print("Install pipx first: python -m pip install pipx")
|
|
247
|
+
self.logger.error("pipx not available for installation")
|
|
248
|
+
return False
|
|
249
|
+
|
|
250
|
+
print(f"\n📦 Installing {self.package_name} via pipx...")
|
|
251
|
+
result = subprocess.run(
|
|
252
|
+
["pipx", "install", self.package_name],
|
|
253
|
+
capture_output=True,
|
|
254
|
+
text=True,
|
|
255
|
+
timeout=120,
|
|
256
|
+
check=False,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
if result.returncode == 0:
|
|
260
|
+
print(f"✓ Successfully installed {self.package_name}")
|
|
261
|
+
self.logger.info(f"Successfully installed {self.package_name} via pipx")
|
|
262
|
+
return True
|
|
263
|
+
|
|
264
|
+
error_msg = result.stderr.strip() if result.stderr else "Unknown error"
|
|
265
|
+
print(f"✗ Installation failed: {error_msg}")
|
|
266
|
+
self.logger.error(f"Failed to install {self.package_name}: {error_msg}")
|
|
125
267
|
return False
|
|
126
268
|
|
|
269
|
+
except FileNotFoundError:
|
|
270
|
+
print("✗ pipx command not found")
|
|
271
|
+
print("Install pipx first: python -m pip install pipx")
|
|
272
|
+
self.logger.error("pipx command not found")
|
|
273
|
+
return False
|
|
274
|
+
except subprocess.TimeoutExpired:
|
|
275
|
+
print("✗ Installation timed out")
|
|
276
|
+
self.logger.error(f"Installation of {self.package_name} timed out")
|
|
277
|
+
return False
|
|
127
278
|
except Exception as e:
|
|
279
|
+
print(f"✗ Installation error: {e}")
|
|
128
280
|
self.logger.error(f"Error installing {self.package_name}: {e}")
|
|
129
281
|
return False
|
|
130
282
|
|
|
@@ -395,13 +547,20 @@ class MCPBrowserService(ExternalMCPService):
|
|
|
395
547
|
class ExternalMCPServiceManager:
|
|
396
548
|
"""Manager for external MCP services.
|
|
397
549
|
|
|
398
|
-
This manager is responsible for
|
|
399
|
-
for external MCP services. The actual registration of these services
|
|
400
|
-
|
|
550
|
+
This manager is responsible for detecting (but NOT installing) Python packages
|
|
551
|
+
for external MCP services. The actual registration of these services happens
|
|
552
|
+
in Claude Code configuration as separate MCP servers.
|
|
401
553
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
554
|
+
IMPORTANT: As of v4.9.0, this manager NO LONGER auto-installs missing services.
|
|
555
|
+
Users must manually install external services using pipx or pip:
|
|
556
|
+
- pipx install mcp-vector-search
|
|
557
|
+
- pipx install mcp-browser
|
|
558
|
+
- pipx install kuzu-memory
|
|
559
|
+
- pipx install mcp-ticketer
|
|
560
|
+
|
|
561
|
+
Note: This class is maintained for backward compatibility and service detection.
|
|
562
|
+
The actual tool registration is handled by separate MCP server instances in
|
|
563
|
+
Claude Code.
|
|
405
564
|
"""
|
|
406
565
|
|
|
407
566
|
def __init__(self):
|
|
@@ -412,20 +571,34 @@ class ExternalMCPServiceManager:
|
|
|
412
571
|
async def initialize_services(self) -> List[ExternalMCPService]:
|
|
413
572
|
"""Initialize all external MCP services.
|
|
414
573
|
|
|
415
|
-
This method checks if external service packages are installed
|
|
416
|
-
and
|
|
417
|
-
|
|
574
|
+
This method checks if external service packages are already installed
|
|
575
|
+
and registers them if available. It does NOT auto-install missing services.
|
|
576
|
+
|
|
577
|
+
External MCP services (mcp-vector-search, mcp-browser, kuzu-memory, mcp-ticketer)
|
|
578
|
+
must be manually installed by users. This gives users explicit control over
|
|
579
|
+
which services they want to use.
|
|
580
|
+
|
|
581
|
+
Installation instructions:
|
|
582
|
+
- mcp-vector-search: pipx install mcp-vector-search
|
|
583
|
+
- mcp-browser: pipx install mcp-browser
|
|
584
|
+
- kuzu-memory: pipx install kuzu-memory
|
|
585
|
+
- mcp-ticketer: pipx install mcp-ticketer
|
|
586
|
+
|
|
587
|
+
Services run as separate MCP servers in Claude Code, not as tools within
|
|
588
|
+
the gateway.
|
|
418
589
|
"""
|
|
419
590
|
# Create service instances
|
|
420
|
-
# Note: kuzu-memory
|
|
421
|
-
#
|
|
591
|
+
# Note: kuzu-memory and mcp-ticketer are configured via MCPConfigManager
|
|
592
|
+
# and run as separate MCP servers. They don't need to be included here
|
|
593
|
+
# since they're already set up through the MCP config.
|
|
422
594
|
services = [MCPVectorSearchService(), MCPBrowserService()]
|
|
423
595
|
|
|
424
|
-
# Initialize each service
|
|
596
|
+
# Initialize each service (check if installed, but DO NOT auto-install)
|
|
425
597
|
initialized_services = []
|
|
426
598
|
for service in services:
|
|
427
599
|
try:
|
|
428
|
-
|
|
600
|
+
# Pass auto_install=False to prevent automatic installation
|
|
601
|
+
if await service.initialize(auto_install=False, interactive=False):
|
|
429
602
|
initialized_services.append(service)
|
|
430
603
|
if self.logger:
|
|
431
604
|
self.logger.info(
|
|
@@ -433,7 +606,8 @@ class ExternalMCPServiceManager:
|
|
|
433
606
|
)
|
|
434
607
|
elif self.logger:
|
|
435
608
|
self.logger.debug(
|
|
436
|
-
f"Service not available (optional): {service.service_name}"
|
|
609
|
+
f"Service not available (optional): {service.service_name}. "
|
|
610
|
+
f"Install manually with: pipx install {service.package_name}"
|
|
437
611
|
)
|
|
438
612
|
except Exception as e:
|
|
439
613
|
if self.logger:
|