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.
Files changed (308) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
  3. claude_mpm/agents/BASE_ENGINEER.md +286 -0
  4. claude_mpm/agents/BASE_PM.md +106 -1
  5. claude_mpm/agents/OUTPUT_STYLE.md +329 -11
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +397 -459
  7. claude_mpm/agents/agent_loader.py +17 -5
  8. claude_mpm/agents/frontmatter_validator.py +284 -253
  9. claude_mpm/agents/templates/README.md +465 -0
  10. claude_mpm/agents/templates/agent-manager.json +4 -1
  11. claude_mpm/agents/templates/agentic-coder-optimizer.json +13 -3
  12. claude_mpm/agents/templates/api_qa.json +11 -2
  13. claude_mpm/agents/templates/circuit_breakers.md +638 -0
  14. claude_mpm/agents/templates/clerk-ops.json +12 -2
  15. claude_mpm/agents/templates/code_analyzer.json +8 -2
  16. claude_mpm/agents/templates/content-agent.json +358 -0
  17. claude_mpm/agents/templates/dart_engineer.json +15 -2
  18. claude_mpm/agents/templates/data_engineer.json +15 -2
  19. claude_mpm/agents/templates/documentation.json +10 -2
  20. claude_mpm/agents/templates/engineer.json +21 -1
  21. claude_mpm/agents/templates/gcp_ops_agent.json +12 -2
  22. claude_mpm/agents/templates/git_file_tracking.md +584 -0
  23. claude_mpm/agents/templates/golang_engineer.json +270 -0
  24. claude_mpm/agents/templates/imagemagick.json +4 -1
  25. claude_mpm/agents/templates/java_engineer.json +346 -0
  26. claude_mpm/agents/templates/local_ops_agent.json +1227 -6
  27. claude_mpm/agents/templates/memory_manager.json +4 -1
  28. claude_mpm/agents/templates/nextjs_engineer.json +141 -133
  29. claude_mpm/agents/templates/ops.json +12 -2
  30. claude_mpm/agents/templates/php-engineer.json +270 -174
  31. claude_mpm/agents/templates/pm_examples.md +474 -0
  32. claude_mpm/agents/templates/pm_red_flags.md +240 -0
  33. claude_mpm/agents/templates/product_owner.json +338 -0
  34. claude_mpm/agents/templates/project_organizer.json +14 -4
  35. claude_mpm/agents/templates/prompt-engineer.json +13 -2
  36. claude_mpm/agents/templates/python_engineer.json +174 -81
  37. claude_mpm/agents/templates/qa.json +11 -2
  38. claude_mpm/agents/templates/react_engineer.json +16 -3
  39. claude_mpm/agents/templates/refactoring_engineer.json +12 -2
  40. claude_mpm/agents/templates/research.json +34 -21
  41. claude_mpm/agents/templates/response_format.md +583 -0
  42. claude_mpm/agents/templates/ruby-engineer.json +129 -192
  43. claude_mpm/agents/templates/rust_engineer.json +270 -0
  44. claude_mpm/agents/templates/security.json +10 -2
  45. claude_mpm/agents/templates/svelte-engineer.json +225 -0
  46. claude_mpm/agents/templates/ticketing.json +10 -2
  47. claude_mpm/agents/templates/typescript_engineer.json +116 -125
  48. claude_mpm/agents/templates/validation_templates.md +312 -0
  49. claude_mpm/agents/templates/vercel_ops_agent.json +12 -2
  50. claude_mpm/agents/templates/version_control.json +12 -2
  51. claude_mpm/agents/templates/web_qa.json +11 -2
  52. claude_mpm/agents/templates/web_ui.json +15 -2
  53. claude_mpm/cli/__init__.py +34 -614
  54. claude_mpm/cli/commands/agent_manager.py +25 -12
  55. claude_mpm/cli/commands/agent_state_manager.py +186 -0
  56. claude_mpm/cli/commands/agents.py +235 -148
  57. claude_mpm/cli/commands/agents_detect.py +380 -0
  58. claude_mpm/cli/commands/agents_recommend.py +309 -0
  59. claude_mpm/cli/commands/aggregate.py +7 -3
  60. claude_mpm/cli/commands/analyze.py +9 -4
  61. claude_mpm/cli/commands/analyze_code.py +7 -2
  62. claude_mpm/cli/commands/auto_configure.py +570 -0
  63. claude_mpm/cli/commands/config.py +47 -13
  64. claude_mpm/cli/commands/configure.py +419 -1571
  65. claude_mpm/cli/commands/configure_agent_display.py +261 -0
  66. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  67. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  68. claude_mpm/cli/commands/configure_models.py +18 -0
  69. claude_mpm/cli/commands/configure_navigation.py +167 -0
  70. claude_mpm/cli/commands/configure_paths.py +104 -0
  71. claude_mpm/cli/commands/configure_persistence.py +254 -0
  72. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  73. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  74. claude_mpm/cli/commands/configure_validators.py +73 -0
  75. claude_mpm/cli/commands/local_deploy.py +537 -0
  76. claude_mpm/cli/commands/memory.py +54 -20
  77. claude_mpm/cli/commands/mpm_init.py +585 -196
  78. claude_mpm/cli/commands/mpm_init_handler.py +37 -3
  79. claude_mpm/cli/commands/search.py +170 -4
  80. claude_mpm/cli/commands/upgrade.py +152 -0
  81. claude_mpm/cli/executor.py +202 -0
  82. claude_mpm/cli/helpers.py +105 -0
  83. claude_mpm/cli/interactive/__init__.py +3 -0
  84. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  85. claude_mpm/cli/parsers/__init__.py +7 -1
  86. claude_mpm/cli/parsers/agents_parser.py +9 -0
  87. claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
  88. claude_mpm/cli/parsers/base_parser.py +110 -3
  89. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  90. claude_mpm/cli/parsers/mpm_init_parser.py +65 -5
  91. claude_mpm/cli/shared/output_formatters.py +28 -19
  92. claude_mpm/cli/startup.py +481 -0
  93. claude_mpm/cli/utils.py +52 -1
  94. claude_mpm/commands/mpm-agents-detect.md +168 -0
  95. claude_mpm/commands/mpm-agents-recommend.md +214 -0
  96. claude_mpm/commands/mpm-agents.md +75 -1
  97. claude_mpm/commands/mpm-auto-configure.md +217 -0
  98. claude_mpm/commands/mpm-help.md +163 -0
  99. claude_mpm/commands/mpm-init.md +148 -3
  100. claude_mpm/commands/mpm-version.md +113 -0
  101. claude_mpm/commands/mpm.md +1 -0
  102. claude_mpm/config/agent_config.py +2 -2
  103. claude_mpm/config/model_config.py +428 -0
  104. claude_mpm/constants.py +1 -0
  105. claude_mpm/core/base_service.py +13 -12
  106. claude_mpm/core/enums.py +452 -0
  107. claude_mpm/core/factories.py +1 -1
  108. claude_mpm/core/instruction_reinforcement_hook.py +2 -1
  109. claude_mpm/core/interactive_session.py +9 -3
  110. claude_mpm/core/log_manager.py +2 -0
  111. claude_mpm/core/logging_config.py +6 -2
  112. claude_mpm/core/oneshot_session.py +8 -4
  113. claude_mpm/core/optimized_agent_loader.py +3 -3
  114. claude_mpm/core/output_style_manager.py +12 -192
  115. claude_mpm/core/service_registry.py +5 -1
  116. claude_mpm/core/types.py +2 -9
  117. claude_mpm/core/typing_utils.py +7 -6
  118. claude_mpm/dashboard/static/js/dashboard.js +0 -14
  119. claude_mpm/dashboard/templates/index.html +3 -41
  120. claude_mpm/hooks/__init__.py +20 -0
  121. claude_mpm/hooks/claude_hooks/event_handlers.py +4 -2
  122. claude_mpm/hooks/claude_hooks/response_tracking.py +35 -1
  123. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +23 -2
  124. claude_mpm/hooks/failure_learning/__init__.py +60 -0
  125. claude_mpm/hooks/failure_learning/failure_detection_hook.py +235 -0
  126. claude_mpm/hooks/failure_learning/fix_detection_hook.py +217 -0
  127. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +286 -0
  128. claude_mpm/hooks/instruction_reinforcement.py +7 -2
  129. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  130. claude_mpm/hooks/kuzu_memory_hook.py +37 -12
  131. claude_mpm/hooks/kuzu_response_hook.py +183 -0
  132. claude_mpm/models/resume_log.py +340 -0
  133. claude_mpm/services/agents/__init__.py +18 -5
  134. claude_mpm/services/agents/auto_config_manager.py +796 -0
  135. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  136. claude_mpm/services/agents/deployment/agent_record_service.py +1 -1
  137. claude_mpm/services/agents/deployment/agent_validator.py +17 -1
  138. claude_mpm/services/agents/deployment/async_agent_deployment.py +1 -1
  139. claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
  140. claude_mpm/services/agents/deployment/local_template_deployment.py +1 -1
  141. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
  142. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
  143. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
  144. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
  145. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
  146. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +9 -6
  147. claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
  148. claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
  149. claude_mpm/services/agents/local_template_manager.py +1 -1
  150. claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
  151. claude_mpm/services/agents/observers.py +547 -0
  152. claude_mpm/services/agents/recommender.py +568 -0
  153. claude_mpm/services/agents/registry/modification_tracker.py +5 -2
  154. claude_mpm/services/command_handler_service.py +11 -5
  155. claude_mpm/services/core/__init__.py +33 -1
  156. claude_mpm/services/core/interfaces/__init__.py +90 -3
  157. claude_mpm/services/core/interfaces/agent.py +184 -0
  158. claude_mpm/services/core/interfaces/health.py +172 -0
  159. claude_mpm/services/core/interfaces/model.py +281 -0
  160. claude_mpm/services/core/interfaces/process.py +372 -0
  161. claude_mpm/services/core/interfaces/project.py +121 -0
  162. claude_mpm/services/core/interfaces/restart.py +307 -0
  163. claude_mpm/services/core/interfaces/stability.py +260 -0
  164. claude_mpm/services/core/memory_manager.py +11 -24
  165. claude_mpm/services/core/models/__init__.py +79 -0
  166. claude_mpm/services/core/models/agent_config.py +381 -0
  167. claude_mpm/services/core/models/health.py +162 -0
  168. claude_mpm/services/core/models/process.py +235 -0
  169. claude_mpm/services/core/models/restart.py +302 -0
  170. claude_mpm/services/core/models/stability.py +264 -0
  171. claude_mpm/services/core/models/toolchain.py +306 -0
  172. claude_mpm/services/core/path_resolver.py +23 -7
  173. claude_mpm/services/diagnostics/__init__.py +2 -2
  174. claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
  175. claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
  176. claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
  177. claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
  178. claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
  179. claude_mpm/services/diagnostics/checks/installation_check.py +30 -29
  180. claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
  181. claude_mpm/services/diagnostics/checks/mcp_check.py +50 -36
  182. claude_mpm/services/diagnostics/checks/mcp_services_check.py +38 -33
  183. claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
  184. claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
  185. claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
  186. claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
  187. claude_mpm/services/diagnostics/models.py +19 -24
  188. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -1
  189. claude_mpm/services/infrastructure/monitoring/aggregator.py +12 -12
  190. claude_mpm/services/infrastructure/monitoring/base.py +5 -13
  191. claude_mpm/services/infrastructure/monitoring/network.py +7 -6
  192. claude_mpm/services/infrastructure/monitoring/process.py +13 -12
  193. claude_mpm/services/infrastructure/monitoring/resources.py +7 -6
  194. claude_mpm/services/infrastructure/monitoring/service.py +16 -15
  195. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  196. claude_mpm/services/local_ops/__init__.py +163 -0
  197. claude_mpm/services/local_ops/crash_detector.py +257 -0
  198. claude_mpm/services/local_ops/health_checks/__init__.py +28 -0
  199. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  200. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  201. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  202. claude_mpm/services/local_ops/health_manager.py +430 -0
  203. claude_mpm/services/local_ops/log_monitor.py +396 -0
  204. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  205. claude_mpm/services/local_ops/process_manager.py +595 -0
  206. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  207. claude_mpm/services/local_ops/restart_manager.py +401 -0
  208. claude_mpm/services/local_ops/restart_policy.py +387 -0
  209. claude_mpm/services/local_ops/state_manager.py +372 -0
  210. claude_mpm/services/local_ops/unified_manager.py +600 -0
  211. claude_mpm/services/mcp_config_manager.py +9 -4
  212. claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
  213. claude_mpm/services/mcp_gateway/core/base.py +18 -31
  214. claude_mpm/services/mcp_gateway/main.py +30 -0
  215. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +206 -32
  216. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +30 -28
  217. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +25 -5
  218. claude_mpm/services/mcp_service_verifier.py +1 -1
  219. claude_mpm/services/memory/failure_tracker.py +563 -0
  220. claude_mpm/services/memory_hook_service.py +165 -4
  221. claude_mpm/services/model/__init__.py +147 -0
  222. claude_mpm/services/model/base_provider.py +365 -0
  223. claude_mpm/services/model/claude_provider.py +412 -0
  224. claude_mpm/services/model/model_router.py +453 -0
  225. claude_mpm/services/model/ollama_provider.py +415 -0
  226. claude_mpm/services/monitor/daemon_manager.py +3 -2
  227. claude_mpm/services/monitor/handlers/dashboard.py +2 -1
  228. claude_mpm/services/monitor/handlers/hooks.py +2 -1
  229. claude_mpm/services/monitor/management/lifecycle.py +3 -2
  230. claude_mpm/services/monitor/server.py +2 -1
  231. claude_mpm/services/project/__init__.py +23 -0
  232. claude_mpm/services/project/detection_strategies.py +719 -0
  233. claude_mpm/services/project/toolchain_analyzer.py +581 -0
  234. claude_mpm/services/self_upgrade_service.py +342 -0
  235. claude_mpm/services/session_management_service.py +3 -2
  236. claude_mpm/services/session_manager.py +205 -1
  237. claude_mpm/services/shared/async_service_base.py +16 -27
  238. claude_mpm/services/shared/lifecycle_service_base.py +1 -14
  239. claude_mpm/services/socketio/handlers/__init__.py +5 -2
  240. claude_mpm/services/socketio/handlers/hook.py +13 -2
  241. claude_mpm/services/socketio/handlers/registry.py +4 -2
  242. claude_mpm/services/socketio/server/main.py +10 -8
  243. claude_mpm/services/subprocess_launcher_service.py +14 -5
  244. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +8 -7
  245. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +6 -5
  246. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +8 -7
  247. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +7 -6
  248. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +5 -4
  249. claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
  250. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
  251. claude_mpm/services/unified/deployment_strategies/local.py +6 -5
  252. claude_mpm/services/unified/deployment_strategies/utils.py +6 -5
  253. claude_mpm/services/unified/deployment_strategies/vercel.py +7 -6
  254. claude_mpm/services/unified/interfaces.py +3 -1
  255. claude_mpm/services/unified/unified_analyzer.py +14 -10
  256. claude_mpm/services/unified/unified_config.py +2 -1
  257. claude_mpm/services/unified/unified_deployment.py +9 -4
  258. claude_mpm/services/version_service.py +104 -1
  259. claude_mpm/skills/__init__.py +21 -0
  260. claude_mpm/skills/bundled/__init__.py +6 -0
  261. claude_mpm/skills/bundled/api-documentation.md +393 -0
  262. claude_mpm/skills/bundled/async-testing.md +571 -0
  263. claude_mpm/skills/bundled/code-review.md +143 -0
  264. claude_mpm/skills/bundled/database-migration.md +199 -0
  265. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  266. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  267. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  268. claude_mpm/skills/bundled/git-workflow.md +414 -0
  269. claude_mpm/skills/bundled/imagemagick.md +204 -0
  270. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  271. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  272. claude_mpm/skills/bundled/pdf.md +141 -0
  273. claude_mpm/skills/bundled/performance-profiling.md +567 -0
  274. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  275. claude_mpm/skills/bundled/security-scanning.md +327 -0
  276. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  277. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  278. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  279. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  280. claude_mpm/skills/bundled/xlsx.md +157 -0
  281. claude_mpm/skills/registry.py +286 -0
  282. claude_mpm/skills/skill_manager.py +310 -0
  283. claude_mpm/storage/state_storage.py +15 -15
  284. claude_mpm/tools/code_tree_analyzer.py +177 -141
  285. claude_mpm/tools/code_tree_events.py +4 -2
  286. claude_mpm/utils/agent_dependency_loader.py +40 -20
  287. claude_mpm/utils/display_helper.py +260 -0
  288. claude_mpm/utils/git_analyzer.py +407 -0
  289. claude_mpm/utils/robust_installer.py +73 -19
  290. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/METADATA +129 -12
  291. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/RECORD +295 -193
  292. claude_mpm/dashboard/static/css/code-tree.css +0 -1639
  293. claude_mpm/dashboard/static/index-hub-backup.html +0 -713
  294. claude_mpm/dashboard/static/js/components/code-tree/tree-breadcrumb.js +0 -353
  295. claude_mpm/dashboard/static/js/components/code-tree/tree-constants.js +0 -235
  296. claude_mpm/dashboard/static/js/components/code-tree/tree-search.js +0 -409
  297. claude_mpm/dashboard/static/js/components/code-tree/tree-utils.js +0 -435
  298. claude_mpm/dashboard/static/js/components/code-tree.js +0 -5869
  299. claude_mpm/dashboard/static/js/components/code-viewer.js +0 -1386
  300. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
  301. claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
  302. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
  303. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
  304. claude_mpm/services/project/analyzer_refactored.py +0 -450
  305. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/WHEEL +0 -0
  306. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/entry_points.txt +0 -0
  307. {claude_mpm-4.7.4.dist-info → claude_mpm-4.18.2.dist-info}/licenses/LICENSE +0 -0
  308. {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 = MCPServiceState.UNINITIALIZED
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
- MCPServiceState.UNINITIALIZED,
80
- MCPServiceState.STOPPED,
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 = MCPServiceState.INITIALIZING
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 = MCPServiceState.INITIALIZED
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 = MCPServiceState.ERROR
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 = MCPServiceState.ERROR
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 != MCPServiceState.INITIALIZED:
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 = MCPServiceState.STARTING
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 = MCPServiceState.RUNNING
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 = MCPServiceState.ERROR
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 = MCPServiceState.ERROR
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 [MCPServiceState.STOPPED, MCPServiceState.STOPPING]:
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 = MCPServiceState.STOPPING
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 = MCPServiceState.STOPPED
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 = MCPServiceState.ERROR
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 == MCPServiceState.RUNNING:
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 installation and basic setup of external MCP services like mcp-vector-search
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
- Note: As of the latest architecture, external services are registered as separate
10
- MCP servers in Claude Code configuration, not as tools within the gateway.
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(self) -> bool:
68
- """Initialize the external service."""
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
- self.logger.debug(
75
- f"{self.package_name} not installed - will attempt automatic installation if needed"
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.error(f"Failed to install {self.package_name}")
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", self.package_name.replace("-", "_"), "--help"],
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
- self.logger.info(f"Installing {self.package_name}...")
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=30,
209
+ timeout=120,
118
210
  check=False,
119
211
  )
120
212
 
121
213
  if result.returncode == 0:
122
- self.logger.info(f"Successfully installed {self.package_name}")
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
- self.logger.error(f"Failed to install {self.package_name}: {result.stderr}")
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 checking and installing Python packages
399
- for external MCP services. The actual registration of these services
400
- happens in Claude Code configuration as separate MCP servers.
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
- Note: This class is maintained for backward compatibility and package
403
- management. The actual tool registration is handled by separate MCP
404
- server instances in Claude Code.
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 attempts to install them if missing. It does NOT register
417
- them as tools in the gateway - they run as separate MCP servers.
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 is configured via MCPConfigManager and runs as a separate MCP server
421
- # It doesn't need to be included here since it's already set up through the MCP config
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
- if await service.initialize():
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: