claude-mpm 3.9.11__py3-none-any.whl → 4.0.3__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 (419) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +2 -2
  3. claude_mpm/__main__.py +3 -2
  4. claude_mpm/agents/__init__.py +85 -79
  5. claude_mpm/agents/agent_loader.py +464 -1003
  6. claude_mpm/agents/agent_loader_integration.py +45 -45
  7. claude_mpm/agents/agents_metadata.py +29 -30
  8. claude_mpm/agents/async_agent_loader.py +156 -138
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/base_agent_loader.py +179 -151
  11. claude_mpm/agents/frontmatter_validator.py +229 -130
  12. claude_mpm/agents/schema/agent_schema.json +1 -1
  13. claude_mpm/agents/system_agent_config.py +213 -147
  14. claude_mpm/agents/templates/__init__.py +13 -13
  15. claude_mpm/agents/templates/code_analyzer.json +2 -2
  16. claude_mpm/agents/templates/data_engineer.json +1 -1
  17. claude_mpm/agents/templates/documentation.json +23 -11
  18. claude_mpm/agents/templates/engineer.json +22 -6
  19. claude_mpm/agents/templates/memory_manager.json +1 -1
  20. claude_mpm/agents/templates/ops.json +2 -2
  21. claude_mpm/agents/templates/project_organizer.json +1 -1
  22. claude_mpm/agents/templates/qa.json +1 -1
  23. claude_mpm/agents/templates/refactoring_engineer.json +222 -0
  24. claude_mpm/agents/templates/research.json +20 -14
  25. claude_mpm/agents/templates/security.json +1 -1
  26. claude_mpm/agents/templates/ticketing.json +1 -1
  27. claude_mpm/agents/templates/version_control.json +1 -1
  28. claude_mpm/agents/templates/web_qa.json +3 -1
  29. claude_mpm/agents/templates/web_ui.json +2 -2
  30. claude_mpm/cli/__init__.py +79 -51
  31. claude_mpm/cli/__main__.py +3 -2
  32. claude_mpm/cli/commands/__init__.py +20 -20
  33. claude_mpm/cli/commands/agents.py +279 -247
  34. claude_mpm/cli/commands/aggregate.py +138 -157
  35. claude_mpm/cli/commands/cleanup.py +147 -147
  36. claude_mpm/cli/commands/config.py +93 -76
  37. claude_mpm/cli/commands/info.py +17 -16
  38. claude_mpm/cli/commands/mcp.py +140 -905
  39. claude_mpm/cli/commands/mcp_command_router.py +139 -0
  40. claude_mpm/cli/commands/mcp_config_commands.py +20 -0
  41. claude_mpm/cli/commands/mcp_install_commands.py +20 -0
  42. claude_mpm/cli/commands/mcp_server_commands.py +175 -0
  43. claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
  44. claude_mpm/cli/commands/memory.py +239 -203
  45. claude_mpm/cli/commands/monitor.py +203 -81
  46. claude_mpm/cli/commands/run.py +380 -429
  47. claude_mpm/cli/commands/run_config_checker.py +160 -0
  48. claude_mpm/cli/commands/socketio_monitor.py +235 -0
  49. claude_mpm/cli/commands/tickets.py +305 -197
  50. claude_mpm/cli/parser.py +24 -1156
  51. claude_mpm/cli/parsers/__init__.py +29 -0
  52. claude_mpm/cli/parsers/agents_parser.py +136 -0
  53. claude_mpm/cli/parsers/base_parser.py +331 -0
  54. claude_mpm/cli/parsers/config_parser.py +85 -0
  55. claude_mpm/cli/parsers/mcp_parser.py +152 -0
  56. claude_mpm/cli/parsers/memory_parser.py +138 -0
  57. claude_mpm/cli/parsers/monitor_parser.py +104 -0
  58. claude_mpm/cli/parsers/run_parser.py +147 -0
  59. claude_mpm/cli/parsers/tickets_parser.py +203 -0
  60. claude_mpm/cli/ticket_cli.py +7 -3
  61. claude_mpm/cli/utils.py +55 -37
  62. claude_mpm/cli_module/__init__.py +6 -6
  63. claude_mpm/cli_module/args.py +188 -140
  64. claude_mpm/cli_module/commands.py +79 -70
  65. claude_mpm/cli_module/migration_example.py +38 -60
  66. claude_mpm/config/__init__.py +32 -25
  67. claude_mpm/config/agent_config.py +151 -119
  68. claude_mpm/config/experimental_features.py +71 -73
  69. claude_mpm/config/paths.py +94 -208
  70. claude_mpm/config/socketio_config.py +84 -73
  71. claude_mpm/constants.py +35 -18
  72. claude_mpm/core/__init__.py +9 -6
  73. claude_mpm/core/agent_name_normalizer.py +68 -71
  74. claude_mpm/core/agent_registry.py +372 -521
  75. claude_mpm/core/agent_session_manager.py +74 -63
  76. claude_mpm/core/base_service.py +116 -87
  77. claude_mpm/core/cache.py +119 -153
  78. claude_mpm/core/claude_runner.py +425 -1120
  79. claude_mpm/core/config.py +263 -168
  80. claude_mpm/core/config_aliases.py +69 -61
  81. claude_mpm/core/config_constants.py +292 -0
  82. claude_mpm/core/constants.py +57 -99
  83. claude_mpm/core/container.py +211 -178
  84. claude_mpm/core/exceptions.py +233 -89
  85. claude_mpm/core/factories.py +92 -54
  86. claude_mpm/core/framework_loader.py +378 -220
  87. claude_mpm/core/hook_manager.py +198 -83
  88. claude_mpm/core/hook_performance_config.py +136 -0
  89. claude_mpm/core/injectable_service.py +61 -55
  90. claude_mpm/core/interactive_session.py +165 -155
  91. claude_mpm/core/interfaces.py +221 -195
  92. claude_mpm/core/lazy.py +96 -96
  93. claude_mpm/core/logger.py +133 -107
  94. claude_mpm/core/logging_config.py +185 -157
  95. claude_mpm/core/minimal_framework_loader.py +20 -15
  96. claude_mpm/core/mixins.py +30 -29
  97. claude_mpm/core/oneshot_session.py +215 -181
  98. claude_mpm/core/optimized_agent_loader.py +134 -138
  99. claude_mpm/core/optimized_startup.py +159 -157
  100. claude_mpm/core/pm_hook_interceptor.py +85 -72
  101. claude_mpm/core/service_registry.py +103 -101
  102. claude_mpm/core/session_manager.py +97 -87
  103. claude_mpm/core/socketio_pool.py +212 -158
  104. claude_mpm/core/tool_access_control.py +58 -51
  105. claude_mpm/core/types.py +46 -24
  106. claude_mpm/core/typing_utils.py +166 -82
  107. claude_mpm/core/unified_agent_registry.py +721 -0
  108. claude_mpm/core/unified_config.py +550 -0
  109. claude_mpm/core/unified_paths.py +549 -0
  110. claude_mpm/dashboard/index.html +1 -1
  111. claude_mpm/dashboard/open_dashboard.py +51 -17
  112. claude_mpm/dashboard/static/css/dashboard.css +27 -8
  113. claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
  114. claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
  115. claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
  116. claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
  117. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
  118. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
  119. claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
  120. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
  121. claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
  122. claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
  123. claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
  124. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
  125. claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
  126. claude_mpm/dashboard/static/dist/dashboard.js +2 -0
  127. claude_mpm/dashboard/static/dist/socket-client.js +2 -0
  128. claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
  129. claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
  130. claude_mpm/dashboard/static/js/components/event-viewer.js +74 -70
  131. claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
  132. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
  133. claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
  134. claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
  135. claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
  136. claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
  137. claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
  138. claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
  139. claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
  140. claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
  141. claude_mpm/dashboard/static/js/dashboard.js +178 -453
  142. claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
  143. claude_mpm/dashboard/static/js/socket-client.js +120 -54
  144. claude_mpm/dashboard/templates/index.html +40 -50
  145. claude_mpm/experimental/cli_enhancements.py +60 -58
  146. claude_mpm/generators/__init__.py +1 -1
  147. claude_mpm/generators/agent_profile_generator.py +75 -65
  148. claude_mpm/hooks/__init__.py +1 -1
  149. claude_mpm/hooks/base_hook.py +33 -28
  150. claude_mpm/hooks/claude_hooks/__init__.py +1 -1
  151. claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
  152. claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
  153. claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
  154. claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
  155. claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
  156. claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
  157. claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
  158. claude_mpm/hooks/memory_integration_hook.py +140 -100
  159. claude_mpm/hooks/tool_call_interceptor.py +89 -76
  160. claude_mpm/hooks/validation_hooks.py +57 -49
  161. claude_mpm/init.py +145 -121
  162. claude_mpm/models/__init__.py +9 -9
  163. claude_mpm/models/agent_definition.py +33 -23
  164. claude_mpm/models/agent_session.py +228 -200
  165. claude_mpm/scripts/__init__.py +1 -1
  166. claude_mpm/scripts/socketio_daemon.py +192 -75
  167. claude_mpm/scripts/socketio_server_manager.py +328 -0
  168. claude_mpm/scripts/start_activity_logging.py +25 -22
  169. claude_mpm/services/__init__.py +68 -43
  170. claude_mpm/services/agent_capabilities_service.py +271 -0
  171. claude_mpm/services/agents/__init__.py +23 -32
  172. claude_mpm/services/agents/deployment/__init__.py +3 -3
  173. claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
  174. claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
  175. claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
  176. claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
  177. claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
  178. claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
  179. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
  180. claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
  181. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
  182. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
  183. claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
  184. claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
  185. claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
  186. claude_mpm/services/agents/deployment/agent_validator.py +352 -0
  187. claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
  188. claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
  189. claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
  190. claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
  191. claude_mpm/services/agents/deployment/config/__init__.py +13 -0
  192. claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
  193. claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
  194. claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
  195. claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
  196. claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
  197. claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
  198. claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
  199. claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
  200. claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
  201. claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
  202. claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
  203. claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
  204. claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
  205. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
  206. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
  207. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
  208. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
  209. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
  210. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
  211. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
  212. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
  213. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
  214. claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
  215. claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
  216. claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
  217. claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
  218. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
  219. claude_mpm/services/agents/deployment/results/__init__.py +13 -0
  220. claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
  221. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
  222. claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
  223. claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
  224. claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
  225. claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
  226. claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
  227. claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
  228. claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
  229. claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
  230. claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
  231. claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
  232. claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
  233. claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
  234. claude_mpm/services/agents/loading/__init__.py +2 -2
  235. claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
  236. claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
  237. claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
  238. claude_mpm/services/agents/management/__init__.py +2 -2
  239. claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
  240. claude_mpm/services/agents/management/agent_management_service.py +209 -156
  241. claude_mpm/services/agents/memory/__init__.py +9 -6
  242. claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
  243. claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
  244. claude_mpm/services/agents/memory/analyzer.py +430 -0
  245. claude_mpm/services/agents/memory/content_manager.py +376 -0
  246. claude_mpm/services/agents/memory/template_generator.py +468 -0
  247. claude_mpm/services/agents/registry/__init__.py +7 -10
  248. claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
  249. claude_mpm/services/agents/registry/modification_tracker.py +351 -285
  250. claude_mpm/services/async_session_logger.py +187 -153
  251. claude_mpm/services/claude_session_logger.py +87 -72
  252. claude_mpm/services/command_handler_service.py +217 -0
  253. claude_mpm/services/communication/__init__.py +3 -2
  254. claude_mpm/services/core/__init__.py +50 -97
  255. claude_mpm/services/core/base.py +60 -53
  256. claude_mpm/services/core/interfaces/__init__.py +188 -0
  257. claude_mpm/services/core/interfaces/agent.py +351 -0
  258. claude_mpm/services/core/interfaces/communication.py +343 -0
  259. claude_mpm/services/core/interfaces/infrastructure.py +413 -0
  260. claude_mpm/services/core/interfaces/service.py +434 -0
  261. claude_mpm/services/core/interfaces.py +19 -944
  262. claude_mpm/services/event_aggregator.py +208 -170
  263. claude_mpm/services/exceptions.py +387 -308
  264. claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
  265. claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
  266. claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
  267. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
  268. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
  269. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
  270. claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
  271. claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
  272. claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
  273. claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
  274. claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
  275. claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
  276. claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
  277. claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
  278. claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
  279. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
  280. claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
  281. claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
  282. claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
  283. claude_mpm/services/hook_service.py +106 -114
  284. claude_mpm/services/infrastructure/__init__.py +7 -5
  285. claude_mpm/services/infrastructure/context_preservation.py +233 -199
  286. claude_mpm/services/infrastructure/daemon_manager.py +279 -0
  287. claude_mpm/services/infrastructure/logging.py +83 -76
  288. claude_mpm/services/infrastructure/monitoring.py +547 -404
  289. claude_mpm/services/mcp_gateway/__init__.py +30 -13
  290. claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
  291. claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
  292. claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
  293. claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
  294. claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
  295. claude_mpm/services/mcp_gateway/core/base.py +80 -67
  296. claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
  297. claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
  298. claude_mpm/services/mcp_gateway/main.py +287 -137
  299. claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
  302. claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
  303. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
  304. claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
  305. claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
  306. claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
  307. claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
  308. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
  309. claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
  310. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
  311. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
  312. claude_mpm/services/memory/__init__.py +2 -2
  313. claude_mpm/services/memory/builder.py +451 -362
  314. claude_mpm/services/memory/cache/__init__.py +2 -2
  315. claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
  316. claude_mpm/services/memory/cache/simple_cache.py +107 -93
  317. claude_mpm/services/memory/indexed_memory.py +195 -193
  318. claude_mpm/services/memory/optimizer.py +267 -234
  319. claude_mpm/services/memory/router.py +571 -263
  320. claude_mpm/services/memory_hook_service.py +237 -0
  321. claude_mpm/services/port_manager.py +223 -0
  322. claude_mpm/services/project/__init__.py +3 -3
  323. claude_mpm/services/project/analyzer.py +451 -305
  324. claude_mpm/services/project/registry.py +262 -240
  325. claude_mpm/services/recovery_manager.py +287 -231
  326. claude_mpm/services/response_tracker.py +87 -67
  327. claude_mpm/services/runner_configuration_service.py +587 -0
  328. claude_mpm/services/session_management_service.py +304 -0
  329. claude_mpm/services/socketio/__init__.py +4 -4
  330. claude_mpm/services/socketio/client_proxy.py +174 -0
  331. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  332. claude_mpm/services/socketio/handlers/base.py +44 -30
  333. claude_mpm/services/socketio/handlers/connection.py +145 -65
  334. claude_mpm/services/socketio/handlers/file.py +123 -108
  335. claude_mpm/services/socketio/handlers/git.py +607 -373
  336. claude_mpm/services/socketio/handlers/hook.py +170 -0
  337. claude_mpm/services/socketio/handlers/memory.py +4 -4
  338. claude_mpm/services/socketio/handlers/project.py +4 -4
  339. claude_mpm/services/socketio/handlers/registry.py +53 -38
  340. claude_mpm/services/socketio/server/__init__.py +18 -0
  341. claude_mpm/services/socketio/server/broadcaster.py +252 -0
  342. claude_mpm/services/socketio/server/core.py +399 -0
  343. claude_mpm/services/socketio/server/main.py +323 -0
  344. claude_mpm/services/socketio_client_manager.py +160 -133
  345. claude_mpm/services/socketio_server.py +36 -1885
  346. claude_mpm/services/subprocess_launcher_service.py +316 -0
  347. claude_mpm/services/system_instructions_service.py +258 -0
  348. claude_mpm/services/ticket_manager.py +19 -533
  349. claude_mpm/services/utility_service.py +285 -0
  350. claude_mpm/services/version_control/__init__.py +18 -21
  351. claude_mpm/services/version_control/branch_strategy.py +20 -10
  352. claude_mpm/services/version_control/conflict_resolution.py +37 -13
  353. claude_mpm/services/version_control/git_operations.py +52 -21
  354. claude_mpm/services/version_control/semantic_versioning.py +92 -53
  355. claude_mpm/services/version_control/version_parser.py +145 -125
  356. claude_mpm/services/version_service.py +270 -0
  357. claude_mpm/storage/__init__.py +2 -2
  358. claude_mpm/storage/state_storage.py +177 -181
  359. claude_mpm/ticket_wrapper.py +2 -2
  360. claude_mpm/utils/__init__.py +2 -2
  361. claude_mpm/utils/agent_dependency_loader.py +453 -243
  362. claude_mpm/utils/config_manager.py +157 -118
  363. claude_mpm/utils/console.py +1 -1
  364. claude_mpm/utils/dependency_cache.py +102 -107
  365. claude_mpm/utils/dependency_manager.py +52 -47
  366. claude_mpm/utils/dependency_strategies.py +131 -96
  367. claude_mpm/utils/environment_context.py +110 -102
  368. claude_mpm/utils/error_handler.py +75 -55
  369. claude_mpm/utils/file_utils.py +80 -67
  370. claude_mpm/utils/framework_detection.py +12 -11
  371. claude_mpm/utils/import_migration_example.py +12 -60
  372. claude_mpm/utils/imports.py +48 -45
  373. claude_mpm/utils/path_operations.py +100 -93
  374. claude_mpm/utils/robust_installer.py +172 -164
  375. claude_mpm/utils/session_logging.py +30 -23
  376. claude_mpm/utils/subprocess_utils.py +99 -61
  377. claude_mpm/validation/__init__.py +1 -1
  378. claude_mpm/validation/agent_validator.py +151 -111
  379. claude_mpm/validation/frontmatter_validator.py +92 -71
  380. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +27 -1
  381. claude_mpm-4.0.3.dist-info/RECORD +402 -0
  382. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
  383. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
  384. claude_mpm/cli/commands/run_guarded.py +0 -511
  385. claude_mpm/config/memory_guardian_config.py +0 -325
  386. claude_mpm/config/memory_guardian_yaml.py +0 -335
  387. claude_mpm/core/config_paths.py +0 -150
  388. claude_mpm/core/memory_aware_runner.py +0 -353
  389. claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
  390. claude_mpm/deployment_paths.py +0 -261
  391. claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
  392. claude_mpm/models/state_models.py +0 -433
  393. claude_mpm/services/agent/__init__.py +0 -24
  394. claude_mpm/services/agent/deployment.py +0 -2548
  395. claude_mpm/services/agent/management.py +0 -598
  396. claude_mpm/services/agent/registry.py +0 -813
  397. claude_mpm/services/agents/registry/agent_registry.py +0 -813
  398. claude_mpm/services/communication/socketio.py +0 -1935
  399. claude_mpm/services/communication/websocket.py +0 -479
  400. claude_mpm/services/framework_claude_md_generator.py +0 -624
  401. claude_mpm/services/health_monitor.py +0 -893
  402. claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
  403. claude_mpm/services/infrastructure/health_monitor.py +0 -775
  404. claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
  405. claude_mpm/services/infrastructure/memory_guardian.py +0 -944
  406. claude_mpm/services/infrastructure/restart_protection.py +0 -642
  407. claude_mpm/services/infrastructure/state_manager.py +0 -774
  408. claude_mpm/services/mcp_gateway/manager.py +0 -334
  409. claude_mpm/services/optimized_hook_service.py +0 -542
  410. claude_mpm/services/project_analyzer.py +0 -864
  411. claude_mpm/services/project_registry.py +0 -608
  412. claude_mpm/services/standalone_socketio_server.py +0 -1300
  413. claude_mpm/services/ticket_manager_di.py +0 -318
  414. claude_mpm/services/ticketing_service_original.py +0 -510
  415. claude_mpm/utils/paths.py +0 -395
  416. claude_mpm/utils/platform_memory.py +0 -524
  417. claude_mpm-3.9.11.dist-info/RECORD +0 -306
  418. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
  419. {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,691 @@
1
+ """
2
+ Simplified MCP Stdio Server
3
+ ============================
4
+
5
+ A proper stdio-based MCP server that communicates via JSON-RPC over stdin/stdout.
6
+ This server is spawned on-demand by Claude Desktop/Code and exits when the connection closes.
7
+
8
+ WHY: MCP servers should be simple stdio-based processes that Claude can spawn and control.
9
+ They should NOT run as persistent background services with lock files.
10
+
11
+ DESIGN DECISION: We follow the MCP specification exactly - read from stdin, write to stdout,
12
+ use JSON-RPC protocol, and exit cleanly when stdin closes.
13
+ """
14
+
15
+ import asyncio
16
+ import logging
17
+ import sys
18
+ from typing import Any, Dict, List, Optional
19
+
20
+ # Import MCP SDK components
21
+ from mcp.server import NotificationOptions, Server
22
+ from mcp.server.models import InitializationOptions
23
+ from mcp.server.stdio import stdio_server
24
+ from mcp.types import TextContent, Tool
25
+
26
+ from claude_mpm.core.logger import get_logger
27
+
28
+ # Import unified ticket tool if available
29
+ try:
30
+ from claude_mpm.services.mcp_gateway.tools.unified_ticket_tool import (
31
+ UnifiedTicketTool,
32
+ )
33
+
34
+ TICKET_TOOLS_AVAILABLE = True
35
+ except ImportError:
36
+ TICKET_TOOLS_AVAILABLE = False
37
+
38
+
39
+ class SimpleMCPServer:
40
+ """
41
+ A simple stdio-based MCP server implementation.
42
+
43
+ WHY: This server follows the MCP specification for stdio communication,
44
+ making it compatible with Claude Desktop/Code's MCP client.
45
+
46
+ DESIGN DECISIONS:
47
+ - No persistent state or lock files
48
+ - Spawned on-demand by Claude
49
+ - Communicates via stdin/stdout
50
+ - Exits when connection closes
51
+ """
52
+
53
+ def __init__(self, name: str = "claude-mpm-gateway", version: str = "1.0.0"):
54
+ """
55
+ Initialize the MCP server.
56
+
57
+ Args:
58
+ name: Server name for identification
59
+ version: Server version
60
+ """
61
+ self.name = name
62
+ self.version = version
63
+ self.logger = get_logger("MCPStdioServer")
64
+
65
+ # Create MCP server instance
66
+ self.server = Server(name)
67
+
68
+ # Register default tools
69
+ self._register_tools()
70
+
71
+ async def _summarize_content(
72
+ self, content: str, style: str, max_length: int
73
+ ) -> str:
74
+ """
75
+ Summarize text content based on style and length constraints.
76
+
77
+ Args:
78
+ content: The text to summarize
79
+ style: Summary style (brief, detailed, bullet_points, executive)
80
+ max_length: Maximum length in words
81
+
82
+ Returns:
83
+ Summarized text
84
+ """
85
+ if not content or not content.strip():
86
+ return "No content provided to summarize."
87
+
88
+ # Split content into sentences for processing
89
+ import re
90
+
91
+ sentences = re.split(r"(?<=[.!?])\s+", content.strip())
92
+
93
+ if not sentences:
94
+ return content[: max_length * 5] # Rough estimate: 5 chars per word
95
+
96
+ if style == "brief":
97
+ # Brief: First and last portions with key sentences
98
+ return self._create_brief_summary(sentences, max_length)
99
+
100
+ elif style == "detailed":
101
+ # Detailed: More comprehensive with section preservation
102
+ return self._create_detailed_summary(sentences, content, max_length)
103
+
104
+ elif style == "bullet_points":
105
+ # Extract key points as bullet list
106
+ return self._create_bullet_summary(sentences, content, max_length)
107
+
108
+ elif style == "executive":
109
+ # Executive: Summary + key findings + recommendations
110
+ return self._create_executive_summary(sentences, content, max_length)
111
+
112
+ else:
113
+ # Default to brief
114
+ return self._create_brief_summary(sentences, max_length)
115
+
116
+ def _create_brief_summary(self, sentences: List[str], max_length: int) -> str:
117
+ """Create a brief summary by selecting most important sentences."""
118
+ if not sentences:
119
+ return ""
120
+
121
+ # If very short summary requested, just return truncated first sentence
122
+ if max_length < 10:
123
+ words = sentences[0].split()[:max_length]
124
+ if len(words) < len(sentences[0].split()):
125
+ return " ".join(words) + "..."
126
+ return " ".join(words)
127
+
128
+ if len(sentences) <= 3:
129
+ text = " ".join(sentences)
130
+ words = text.split()
131
+ if len(words) <= max_length:
132
+ return text
133
+ # Truncate to word limit
134
+ return " ".join(words[:max_length]) + "..."
135
+
136
+ # Calculate importance scores for sentences
137
+ scored_sentences = []
138
+ for i, sentence in enumerate(sentences):
139
+ score = 0
140
+
141
+ # Position scoring
142
+ if i == 0: # First sentence
143
+ score += 3
144
+ elif i == len(sentences) - 1: # Last sentence
145
+ score += 2
146
+ elif i < 3: # Early sentences
147
+ score += 1
148
+
149
+ # Content scoring
150
+ important_words = [
151
+ "important",
152
+ "key",
153
+ "main",
154
+ "critical",
155
+ "essential",
156
+ "summary",
157
+ "conclusion",
158
+ "result",
159
+ "therefore",
160
+ "however",
161
+ ]
162
+ for word in important_words:
163
+ if word in sentence.lower():
164
+ score += 1
165
+
166
+ # Length scoring (prefer medium-length sentences)
167
+ word_count = len(sentence.split())
168
+ if 10 <= word_count <= 25:
169
+ score += 1
170
+
171
+ scored_sentences.append((score, i, sentence))
172
+
173
+ # Sort by score and select top sentences
174
+ scored_sentences.sort(reverse=True, key=lambda x: x[0])
175
+
176
+ # Select sentences up to word limit
177
+ selected = []
178
+ word_count = 0
179
+ for score, orig_idx, sentence in scored_sentences:
180
+ sentence_words = len(sentence.split())
181
+ if word_count + sentence_words <= max_length:
182
+ selected.append((orig_idx, sentence))
183
+ word_count += sentence_words
184
+
185
+ # Sort by original order
186
+ selected.sort(key=lambda x: x[0])
187
+
188
+ if not selected:
189
+ # If no sentences fit, truncate the first sentence
190
+ words = sentences[0].split()[:max_length]
191
+ if len(words) < len(sentences[0].split()):
192
+ return " ".join(words) + "..."
193
+ return " ".join(words)
194
+
195
+ return " ".join(s[1] for s in selected)
196
+
197
+ def _create_detailed_summary(
198
+ self, sentences: List[str], content: str, max_length: int
199
+ ) -> str:
200
+ """Create a detailed summary preserving document structure."""
201
+ import re
202
+
203
+ # Split into paragraphs
204
+ paragraphs = content.split("\n\n")
205
+
206
+ if len(paragraphs) <= 2:
207
+ return self._create_brief_summary(sentences, max_length)
208
+
209
+ # Summarize each paragraph
210
+ summary_parts = []
211
+ words_per_para = max_length // len(paragraphs)
212
+
213
+ for para in paragraphs:
214
+ if not para.strip():
215
+ continue
216
+
217
+ para_sentences = re.split(r"(?<=[.!?])\s+", para.strip())
218
+ if para_sentences:
219
+ # Take first sentence of each paragraph
220
+ summary_parts.append(para_sentences[0])
221
+
222
+ result = " ".join(summary_parts)
223
+
224
+ # Trim to word limit
225
+ words = result.split()[:max_length]
226
+ return " ".join(words) + ("..." if len(result.split()) > max_length else "")
227
+
228
+ def _create_bullet_summary(
229
+ self, sentences: List[str], content: str, max_length: int
230
+ ) -> str:
231
+ """Extract key points as a bullet list."""
232
+ import re
233
+
234
+ # Look for existing bullet points or lists
235
+ bullet_patterns = [
236
+ re.compile(r"^\s*[-•*]\s+(.+)$", re.MULTILINE),
237
+ re.compile(r"^\s*\d+[.)]\s+(.+)$", re.MULTILINE),
238
+ re.compile(r"^([A-Z][^.!?]+):(.+)$", re.MULTILINE),
239
+ ]
240
+
241
+ points = []
242
+ for pattern in bullet_patterns:
243
+ matches = pattern.findall(content)
244
+ for match in matches:
245
+ if isinstance(match, tuple):
246
+ point = " ".join(match).strip()
247
+ else:
248
+ point = match.strip()
249
+ if point and len(point.split()) <= 20: # Keep concise points
250
+ points.append(point)
251
+
252
+ # If no bullet points found, extract key sentences
253
+ if not points:
254
+ # Use brief summary sentences as bullet points
255
+ brief = self._create_brief_summary(sentences, max_length)
256
+ points = brief.split(". ")
257
+
258
+ # Format as bullet list
259
+ result_lines = []
260
+ word_count = 0
261
+ for point in points:
262
+ point_words = len(point.split())
263
+ if word_count + point_words <= max_length:
264
+ result_lines.append(f"• {point.strip('.')}")
265
+ word_count += point_words
266
+
267
+ if not result_lines:
268
+ return "• " + " ".join(sentences[0].split()[:max_length]) + "..."
269
+
270
+ return "\n".join(result_lines)
271
+
272
+ def _create_executive_summary(
273
+ self, sentences: List[str], content: str, max_length: int
274
+ ) -> str:
275
+ """Create an executive summary with overview, findings, and recommendations."""
276
+ # Allocate words across sections
277
+ overview_words = max_length // 3
278
+ findings_words = max_length // 3
279
+ recommendations_words = max_length - overview_words - findings_words
280
+
281
+ sections = []
282
+
283
+ # Overview section
284
+ overview = self._create_brief_summary(
285
+ sentences[: len(sentences) // 2], overview_words
286
+ )
287
+ if overview:
288
+ sections.append(f"OVERVIEW:\n{overview}")
289
+
290
+ # Key Findings
291
+ import re
292
+
293
+ findings = []
294
+
295
+ # Look for sentences with conclusion/result indicators
296
+ conclusion_patterns = [
297
+ "found",
298
+ "discovered",
299
+ "shows",
300
+ "indicates",
301
+ "reveals",
302
+ "demonstrates",
303
+ "proves",
304
+ "confirms",
305
+ "suggests",
306
+ ]
307
+
308
+ for sentence in sentences:
309
+ if any(word in sentence.lower() for word in conclusion_patterns):
310
+ findings.append(sentence)
311
+ if len(" ".join(findings).split()) >= findings_words:
312
+ break
313
+
314
+ if findings:
315
+ sections.append(f"\nKEY FINDINGS:\n• " + "\n• ".join(findings[:3]))
316
+
317
+ # Recommendations (look for action-oriented sentences)
318
+ action_patterns = [
319
+ "should",
320
+ "must",
321
+ "need to",
322
+ "recommend",
323
+ "suggest",
324
+ "important to",
325
+ "critical to",
326
+ "require",
327
+ ]
328
+
329
+ recommendations = []
330
+ for sentence in sentences:
331
+ if any(word in sentence.lower() for word in action_patterns):
332
+ recommendations.append(sentence)
333
+ if len(" ".join(recommendations).split()) >= recommendations_words:
334
+ break
335
+
336
+ if recommendations:
337
+ sections.append(
338
+ f"\nRECOMMENDATIONS:\n• " + "\n• ".join(recommendations[:3])
339
+ )
340
+
341
+ # If no sections were created, fall back to brief summary
342
+ if not sections:
343
+ return self._create_brief_summary(sentences, max_length)
344
+
345
+ result = "\n".join(sections)
346
+
347
+ # Ensure we don't exceed word limit
348
+ words = result.split()[:max_length]
349
+ return " ".join(words) + ("..." if len(result.split()) > max_length else "")
350
+
351
+ def _register_tools(self):
352
+ """
353
+ Register MCP tools with the server.
354
+
355
+ WHY: Tools are the primary way MCP servers extend Claude's capabilities.
356
+ We register them using decorators on handler functions.
357
+ """
358
+ # Initialize unified ticket tool if available
359
+ self.unified_ticket_tool = None
360
+ if TICKET_TOOLS_AVAILABLE:
361
+ try:
362
+ self.unified_ticket_tool = UnifiedTicketTool()
363
+ # Initialize the unified ticket tool
364
+ asyncio.create_task(self.unified_ticket_tool.initialize())
365
+ except Exception as e:
366
+ self.logger.warning(f"Failed to initialize unified ticket tool: {e}")
367
+ self.unified_ticket_tool = None
368
+
369
+ @self.server.list_tools()
370
+ async def handle_list_tools() -> List[Tool]:
371
+ """List available tools."""
372
+ tools = [
373
+ Tool(
374
+ name="echo",
375
+ description="Echo back the provided message",
376
+ inputSchema={
377
+ "type": "object",
378
+ "properties": {
379
+ "message": {
380
+ "type": "string",
381
+ "description": "Message to echo",
382
+ }
383
+ },
384
+ "required": ["message"],
385
+ },
386
+ ),
387
+ Tool(
388
+ name="calculator",
389
+ description="Perform basic arithmetic calculations",
390
+ inputSchema={
391
+ "type": "object",
392
+ "properties": {
393
+ "expression": {
394
+ "type": "string",
395
+ "description": "Mathematical expression to evaluate",
396
+ }
397
+ },
398
+ "required": ["expression"],
399
+ },
400
+ ),
401
+ Tool(
402
+ name="system_info",
403
+ description="Get system information",
404
+ inputSchema={
405
+ "type": "object",
406
+ "properties": {
407
+ "info_type": {
408
+ "type": "string",
409
+ "enum": ["platform", "python_version", "cwd"],
410
+ "description": "Type of system information to retrieve",
411
+ }
412
+ },
413
+ "required": ["info_type"],
414
+ },
415
+ ),
416
+ Tool(
417
+ name="run_command",
418
+ description="Execute a shell command",
419
+ inputSchema={
420
+ "type": "object",
421
+ "properties": {
422
+ "command": {
423
+ "type": "string",
424
+ "description": "Shell command to execute",
425
+ },
426
+ "timeout": {
427
+ "type": "number",
428
+ "description": "Command timeout in seconds",
429
+ "default": 30,
430
+ },
431
+ },
432
+ "required": ["command"],
433
+ },
434
+ ),
435
+ Tool(
436
+ name="summarize_document",
437
+ description="Summarize documents or text content",
438
+ inputSchema={
439
+ "type": "object",
440
+ "properties": {
441
+ "content": {
442
+ "type": "string",
443
+ "description": "The text/document to summarize",
444
+ },
445
+ "style": {
446
+ "type": "string",
447
+ "enum": [
448
+ "brief",
449
+ "detailed",
450
+ "bullet_points",
451
+ "executive",
452
+ ],
453
+ "description": "Summary style",
454
+ "default": "brief",
455
+ },
456
+ "max_length": {
457
+ "type": "integer",
458
+ "description": "Maximum length of summary in words",
459
+ "default": 150,
460
+ },
461
+ },
462
+ "required": ["content"],
463
+ },
464
+ ),
465
+ ]
466
+
467
+ # Add unified ticket tool if available
468
+ if self.unified_ticket_tool:
469
+ tool_def = self.unified_ticket_tool.get_definition()
470
+ tools.append(
471
+ Tool(
472
+ name=tool_def.name,
473
+ description=tool_def.description,
474
+ inputSchema=tool_def.input_schema,
475
+ )
476
+ )
477
+
478
+ self.logger.info(f"Listing {len(tools)} available tools")
479
+ return tools
480
+
481
+ @self.server.call_tool()
482
+ async def handle_call_tool(
483
+ name: str, arguments: Dict[str, Any]
484
+ ) -> List[TextContent]:
485
+ """Handle tool invocation."""
486
+ self.logger.info(f"Invoking tool: {name} with arguments: {arguments}")
487
+
488
+ try:
489
+ if name == "echo":
490
+ message = arguments.get("message", "")
491
+ result = f"Echo: {message}"
492
+
493
+ elif name == "calculator":
494
+ expression = arguments.get("expression", "")
495
+ try:
496
+ # Safe evaluation of mathematical expressions
497
+ import ast
498
+ import operator as op
499
+
500
+ # Supported operators
501
+ ops = {
502
+ ast.Add: op.add,
503
+ ast.Sub: op.sub,
504
+ ast.Mult: op.mul,
505
+ ast.Div: op.truediv,
506
+ ast.Pow: op.pow,
507
+ ast.Mod: op.mod,
508
+ ast.USub: op.neg,
509
+ }
510
+
511
+ def eval_expr(expr):
512
+ """Safely evaluate mathematical expression."""
513
+
514
+ def _eval(node):
515
+ if isinstance(node, ast.Constant):
516
+ return node.value
517
+ elif isinstance(node, ast.BinOp):
518
+ return ops[type(node.op)](
519
+ _eval(node.left), _eval(node.right)
520
+ )
521
+ elif isinstance(node, ast.UnaryOp):
522
+ return ops[type(node.op)](_eval(node.operand))
523
+ else:
524
+ raise TypeError(f"Unsupported operation: {node}")
525
+
526
+ return _eval(ast.parse(expr, mode="eval").body)
527
+
528
+ result_value = eval_expr(expression)
529
+ result = f"{expression} = {result_value}"
530
+ except Exception as e:
531
+ result = f"Error evaluating expression: {str(e)}"
532
+
533
+ elif name == "system_info":
534
+ info_type = arguments.get("info_type", "platform")
535
+
536
+ if info_type == "platform":
537
+ import platform
538
+
539
+ result = f"Platform: {platform.system()} {platform.release()}"
540
+ elif info_type == "python_version":
541
+ import sys
542
+
543
+ result = f"Python: {sys.version}"
544
+ elif info_type == "cwd":
545
+ import os
546
+
547
+ result = f"Working Directory: {os.getcwd()}"
548
+ else:
549
+ result = f"Unknown info type: {info_type}"
550
+
551
+ elif name == "run_command":
552
+ command = arguments.get("command", "")
553
+ timeout = arguments.get("timeout", 30)
554
+
555
+ import shlex
556
+ import subprocess
557
+
558
+ try:
559
+ # Split command string into a list to avoid shell injection
560
+ command_parts = shlex.split(command)
561
+
562
+ # Use create_subprocess_exec instead of create_subprocess_shell
563
+ # to prevent command injection vulnerabilities
564
+ proc = await asyncio.create_subprocess_exec(
565
+ *command_parts,
566
+ stdout=subprocess.PIPE,
567
+ stderr=subprocess.PIPE,
568
+ )
569
+
570
+ stdout, stderr = await asyncio.wait_for(
571
+ proc.communicate(), timeout=timeout
572
+ )
573
+
574
+ if proc.returncode == 0:
575
+ result = (
576
+ stdout.decode()
577
+ if stdout
578
+ else "Command completed successfully"
579
+ )
580
+ else:
581
+ result = f"Command failed with code {proc.returncode}: {stderr.decode()}"
582
+ except asyncio.TimeoutError:
583
+ result = f"Command timed out after {timeout} seconds"
584
+ except ValueError as e:
585
+ # Handle shlex parsing errors (e.g., unmatched quotes)
586
+ result = f"Invalid command syntax: {str(e)}"
587
+ except Exception as e:
588
+ result = f"Error running command: {str(e)}"
589
+
590
+ elif name == "summarize_document":
591
+ content = arguments.get("content", "")
592
+ style = arguments.get("style", "brief")
593
+ max_length = arguments.get("max_length", 150)
594
+
595
+ result = await self._summarize_content(content, style, max_length)
596
+
597
+ elif name == "ticket" and self.unified_ticket_tool:
598
+ # Handle unified ticket tool invocations
599
+ from claude_mpm.services.mcp_gateway.core.interfaces import (
600
+ MCPToolInvocation,
601
+ )
602
+
603
+ invocation = MCPToolInvocation(
604
+ tool_name=name,
605
+ parameters=arguments,
606
+ request_id=f"req_{name}_{id(arguments)}",
607
+ )
608
+
609
+ tool_result = await self.unified_ticket_tool.invoke(invocation)
610
+
611
+ if tool_result.success:
612
+ result = (
613
+ tool_result.data
614
+ if isinstance(tool_result.data, str)
615
+ else str(tool_result.data)
616
+ )
617
+ else:
618
+ result = f"Error: {tool_result.error}"
619
+
620
+ else:
621
+ result = f"Unknown tool: {name}"
622
+
623
+ self.logger.info(f"Tool {name} completed successfully")
624
+ return [TextContent(type="text", text=result)]
625
+
626
+ except Exception as e:
627
+ error_msg = f"Error executing tool {name}: {str(e)}"
628
+ self.logger.error(error_msg)
629
+ return [TextContent(type="text", text=error_msg)]
630
+
631
+ async def run(self):
632
+ """
633
+ Run the MCP server using stdio communication.
634
+
635
+ WHY: This is the main entry point that sets up stdio communication
636
+ and runs the server until the connection is closed.
637
+ """
638
+ try:
639
+ self.logger.info(f"Starting {self.name} v{self.version}")
640
+
641
+ # Run the server with stdio transport
642
+ async with stdio_server() as (read_stream, write_stream):
643
+ self.logger.info("Stdio connection established")
644
+
645
+ # Create initialization options
646
+ init_options = InitializationOptions(
647
+ server_name=self.name,
648
+ server_version=self.version,
649
+ capabilities=self.server.get_capabilities(
650
+ notification_options=NotificationOptions(),
651
+ experimental_capabilities={},
652
+ ),
653
+ )
654
+
655
+ # Run the server
656
+ await self.server.run(read_stream, write_stream, init_options)
657
+
658
+ self.logger.info("Server shutting down normally")
659
+
660
+ except Exception as e:
661
+ self.logger.error(f"Server error: {e}")
662
+ raise
663
+
664
+
665
+ async def main():
666
+ """
667
+ Main entry point for the MCP stdio server.
668
+
669
+ WHY: This function creates and runs the server instance.
670
+ It's called when the script is executed directly.
671
+ """
672
+ # Configure logging to stderr so it doesn't interfere with stdio protocol
673
+ logging.basicConfig(
674
+ level=logging.INFO,
675
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
676
+ stream=sys.stderr,
677
+ )
678
+
679
+ # Create and run server
680
+ server = SimpleMCPServer()
681
+ await server.run()
682
+
683
+
684
+ def main_sync():
685
+ """Synchronous entry point for use as a console script."""
686
+ asyncio.run(main())
687
+
688
+
689
+ if __name__ == "__main__":
690
+ # Run the async main function
691
+ main_sync()