claude-mpm 4.3.12__py3-none-any.whl → 4.3.13__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 (199) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/PM_INSTRUCTIONS.md +390 -28
  3. claude_mpm/agents/templates/data_engineer.json +39 -14
  4. claude_mpm/cli/commands/agent_manager.py +3 -3
  5. claude_mpm/cli/commands/agents.py +2 -2
  6. claude_mpm/cli/commands/aggregate.py +1 -1
  7. claude_mpm/cli/commands/config.py +2 -2
  8. claude_mpm/cli/commands/configure.py +5 -5
  9. claude_mpm/cli/commands/configure_tui.py +7 -7
  10. claude_mpm/cli/commands/dashboard.py +1 -1
  11. claude_mpm/cli/commands/debug.py +5 -5
  12. claude_mpm/cli/commands/mcp.py +1 -1
  13. claude_mpm/cli/commands/mcp_command_router.py +1 -1
  14. claude_mpm/cli/commands/mcp_config.py +7 -10
  15. claude_mpm/cli/commands/mcp_external_commands.py +40 -32
  16. claude_mpm/cli/commands/mcp_install_commands.py +38 -10
  17. claude_mpm/cli/commands/mcp_setup_external.py +143 -102
  18. claude_mpm/cli/commands/monitor.py +2 -2
  19. claude_mpm/cli/commands/mpm_init_handler.py +1 -1
  20. claude_mpm/cli/commands/run.py +46 -2
  21. claude_mpm/cli/commands/search.py +41 -34
  22. claude_mpm/cli/interactive/agent_wizard.py +2 -2
  23. claude_mpm/cli/parsers/mcp_parser.py +1 -3
  24. claude_mpm/cli/parsers/search_parser.py +10 -4
  25. claude_mpm/cli/startup_logging.py +3 -5
  26. claude_mpm/cli/utils.py +1 -1
  27. claude_mpm/core/agent_registry.py +12 -8
  28. claude_mpm/core/agent_session_manager.py +8 -8
  29. claude_mpm/core/api_validator.py +4 -4
  30. claude_mpm/core/base_service.py +10 -10
  31. claude_mpm/core/cache.py +5 -5
  32. claude_mpm/core/config_constants.py +1 -1
  33. claude_mpm/core/container.py +1 -1
  34. claude_mpm/core/error_handler.py +2 -2
  35. claude_mpm/core/file_utils.py +1 -1
  36. claude_mpm/core/framework_loader.py +3 -3
  37. claude_mpm/core/hook_manager.py +8 -6
  38. claude_mpm/core/instruction_reinforcement_hook.py +2 -2
  39. claude_mpm/core/interactive_session.py +1 -1
  40. claude_mpm/core/lazy.py +3 -3
  41. claude_mpm/core/log_manager.py +16 -12
  42. claude_mpm/core/logger.py +16 -11
  43. claude_mpm/core/logging_config.py +4 -2
  44. claude_mpm/core/oneshot_session.py +1 -1
  45. claude_mpm/core/optimized_agent_loader.py +6 -6
  46. claude_mpm/core/output_style_manager.py +1 -1
  47. claude_mpm/core/pm_hook_interceptor.py +3 -3
  48. claude_mpm/core/service_registry.py +1 -1
  49. claude_mpm/core/session_manager.py +11 -9
  50. claude_mpm/core/socketio_pool.py +13 -13
  51. claude_mpm/core/types.py +2 -2
  52. claude_mpm/core/unified_agent_registry.py +2 -2
  53. claude_mpm/core/unified_paths.py +1 -1
  54. claude_mpm/dashboard/analysis_runner.py +4 -4
  55. claude_mpm/dashboard/api/simple_directory.py +1 -1
  56. claude_mpm/generators/agent_profile_generator.py +4 -2
  57. claude_mpm/hooks/base_hook.py +2 -2
  58. claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
  59. claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
  60. claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
  61. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
  62. claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
  63. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
  64. claude_mpm/hooks/claude_hooks/installer.py +3 -3
  65. claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
  66. claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
  67. claude_mpm/hooks/claude_hooks/services/connection_manager.py +5 -5
  68. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
  69. claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
  70. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
  71. claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
  72. claude_mpm/hooks/memory_integration_hook.py +1 -1
  73. claude_mpm/hooks/tool_call_interceptor.py +2 -2
  74. claude_mpm/models/agent_session.py +5 -5
  75. claude_mpm/services/__init__.py +1 -1
  76. claude_mpm/services/agent_capabilities_service.py +1 -1
  77. claude_mpm/services/agents/agent_builder.py +3 -3
  78. claude_mpm/services/agents/deployment/agent_deployment.py +2 -1
  79. claude_mpm/services/agents/deployment/agent_discovery_service.py +9 -3
  80. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +7 -5
  81. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
  82. claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
  83. claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
  84. claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
  85. claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
  86. claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
  87. claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
  88. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
  89. claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
  90. claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
  91. claude_mpm/services/agents/local_template_manager.py +6 -6
  92. claude_mpm/services/agents/management/agent_management_service.py +3 -3
  93. claude_mpm/services/agents/memory/content_manager.py +3 -3
  94. claude_mpm/services/agents/memory/memory_format_service.py +2 -2
  95. claude_mpm/services/agents/memory/template_generator.py +3 -3
  96. claude_mpm/services/agents/registry/__init__.py +1 -1
  97. claude_mpm/services/agents/registry/modification_tracker.py +2 -2
  98. claude_mpm/services/async_session_logger.py +3 -3
  99. claude_mpm/services/claude_session_logger.py +4 -4
  100. claude_mpm/services/cli/agent_listing_service.py +1 -1
  101. claude_mpm/services/cli/agent_validation_service.py +1 -0
  102. claude_mpm/services/cli/memory_crud_service.py +11 -6
  103. claude_mpm/services/cli/memory_output_formatter.py +1 -1
  104. claude_mpm/services/cli/session_manager.py +15 -11
  105. claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
  106. claude_mpm/services/core/memory_manager.py +81 -23
  107. claude_mpm/services/core/path_resolver.py +2 -2
  108. claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
  109. claude_mpm/services/event_aggregator.py +4 -2
  110. claude_mpm/services/event_bus/direct_relay.py +5 -3
  111. claude_mpm/services/event_bus/event_bus.py +3 -3
  112. claude_mpm/services/event_bus/relay.py +6 -4
  113. claude_mpm/services/events/consumers/dead_letter.py +5 -3
  114. claude_mpm/services/events/core.py +3 -3
  115. claude_mpm/services/events/producers/hook.py +6 -6
  116. claude_mpm/services/events/producers/system.py +8 -8
  117. claude_mpm/services/exceptions.py +5 -5
  118. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
  119. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
  120. claude_mpm/services/hook_installer_service.py +1 -1
  121. claude_mpm/services/infrastructure/context_preservation.py +6 -4
  122. claude_mpm/services/infrastructure/daemon_manager.py +2 -2
  123. claude_mpm/services/infrastructure/logging.py +2 -2
  124. claude_mpm/services/mcp_config_manager.py +175 -30
  125. claude_mpm/services/mcp_gateway/__init__.py +1 -1
  126. claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
  127. claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
  128. claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
  129. claude_mpm/services/mcp_gateway/core/base.py +2 -2
  130. claude_mpm/services/mcp_gateway/main.py +21 -7
  131. claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
  132. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
  133. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  134. claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -3
  135. claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
  136. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
  137. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +190 -137
  138. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
  139. claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
  140. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
  141. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +17 -17
  142. claude_mpm/services/memory/builder.py +7 -5
  143. claude_mpm/services/memory/indexed_memory.py +4 -4
  144. claude_mpm/services/memory/optimizer.py +6 -6
  145. claude_mpm/services/memory/router.py +3 -3
  146. claude_mpm/services/monitor/daemon.py +1 -1
  147. claude_mpm/services/monitor/daemon_manager.py +6 -6
  148. claude_mpm/services/monitor/event_emitter.py +2 -2
  149. claude_mpm/services/monitor/handlers/file.py +1 -1
  150. claude_mpm/services/monitor/management/lifecycle.py +1 -1
  151. claude_mpm/services/monitor/server.py +4 -4
  152. claude_mpm/services/monitor_build_service.py +2 -2
  153. claude_mpm/services/port_manager.py +2 -2
  154. claude_mpm/services/response_tracker.py +2 -2
  155. claude_mpm/services/session_management_service.py +3 -2
  156. claude_mpm/services/socketio/client_proxy.py +2 -2
  157. claude_mpm/services/socketio/dashboard_server.py +4 -3
  158. claude_mpm/services/socketio/event_normalizer.py +12 -8
  159. claude_mpm/services/socketio/handlers/base.py +2 -2
  160. claude_mpm/services/socketio/handlers/connection.py +10 -10
  161. claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
  162. claude_mpm/services/socketio/handlers/file.py +1 -1
  163. claude_mpm/services/socketio/handlers/git.py +1 -1
  164. claude_mpm/services/socketio/handlers/hook.py +16 -15
  165. claude_mpm/services/socketio/migration_utils.py +1 -1
  166. claude_mpm/services/socketio/monitor_client.py +5 -5
  167. claude_mpm/services/socketio/server/broadcaster.py +9 -7
  168. claude_mpm/services/socketio/server/connection_manager.py +2 -2
  169. claude_mpm/services/socketio/server/core.py +7 -5
  170. claude_mpm/services/socketio/server/eventbus_integration.py +18 -11
  171. claude_mpm/services/socketio/server/main.py +13 -13
  172. claude_mpm/services/socketio_client_manager.py +4 -4
  173. claude_mpm/services/system_instructions_service.py +2 -2
  174. claude_mpm/services/ticket_services/validation_service.py +1 -1
  175. claude_mpm/services/utility_service.py +5 -2
  176. claude_mpm/services/version_control/branch_strategy.py +2 -2
  177. claude_mpm/services/version_control/git_operations.py +22 -20
  178. claude_mpm/services/version_control/semantic_versioning.py +3 -3
  179. claude_mpm/services/version_control/version_parser.py +7 -5
  180. claude_mpm/services/visualization/mermaid_generator.py +1 -1
  181. claude_mpm/storage/state_storage.py +1 -1
  182. claude_mpm/tools/code_tree_analyzer.py +19 -18
  183. claude_mpm/tools/code_tree_builder.py +2 -2
  184. claude_mpm/tools/code_tree_events.py +10 -8
  185. claude_mpm/tools/socketio_debug.py +3 -3
  186. claude_mpm/utils/agent_dependency_loader.py +2 -2
  187. claude_mpm/utils/dependency_strategies.py +8 -3
  188. claude_mpm/utils/environment_context.py +2 -2
  189. claude_mpm/utils/error_handler.py +2 -2
  190. claude_mpm/utils/file_utils.py +1 -1
  191. claude_mpm/utils/imports.py +1 -1
  192. claude_mpm/utils/log_cleanup.py +21 -7
  193. claude_mpm/validation/agent_validator.py +2 -2
  194. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/METADATA +1 -1
  195. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/RECORD +199 -199
  196. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/WHEEL +0 -0
  197. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/entry_points.txt +0 -0
  198. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/licenses/LICENSE +0 -0
  199. {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/top_level.txt +0 -0
@@ -5,11 +5,11 @@ This module handles the registration of external MCP services
5
5
  """
6
6
 
7
7
  import json
8
- import os
9
8
  import subprocess
10
9
  import sys
10
+ from datetime import datetime, timezone
11
11
  from pathlib import Path
12
- from typing import Dict, Optional, List, Tuple
12
+ from typing import Dict, Optional, Tuple
13
13
 
14
14
 
15
15
  class MCPExternalServicesSetup:
@@ -26,21 +26,23 @@ class MCPExternalServicesSetup:
26
26
  """
27
27
  # Detect best command paths for services
28
28
  mcp_browser_config = self._get_best_service_config("mcp-browser", project_path)
29
- mcp_vector_search_config = self._get_best_service_config("mcp-vector-search", project_path)
29
+ mcp_vector_search_config = self._get_best_service_config(
30
+ "mcp-vector-search", project_path
31
+ )
30
32
 
31
33
  return {
32
34
  "mcp-vector-search": {
33
35
  "package_name": "mcp-vector-search",
34
36
  "module_name": "mcp_vector_search",
35
37
  "description": "Semantic code search with vector embeddings",
36
- "config": mcp_vector_search_config
38
+ "config": mcp_vector_search_config,
37
39
  },
38
40
  "mcp-browser": {
39
41
  "package_name": "mcp-browser",
40
42
  "module_name": "mcp_browser",
41
43
  "description": "Web browsing and content extraction",
42
- "config": mcp_browser_config
43
- }
44
+ "config": mcp_browser_config,
45
+ },
44
46
  }
45
47
 
46
48
  def _get_best_service_config(self, service_name: str, project_path: Path) -> Dict:
@@ -85,7 +87,9 @@ class MCPExternalServicesSetup:
85
87
  # Fall back to system Python
86
88
  return self._get_system_config(service_name, project_path)
87
89
 
88
- def _get_local_dev_config(self, service_name: str, project_path: Path) -> Optional[Dict]:
90
+ def _get_local_dev_config(
91
+ self, service_name: str, project_path: Path
92
+ ) -> Optional[Dict]:
89
93
  """Get configuration for a locally developed service.
90
94
 
91
95
  Checks common development locations like ~/Projects/managed/
@@ -128,8 +132,10 @@ class MCPExternalServicesSetup:
128
132
  "command": str(mcp_browser_binary),
129
133
  "args": ["mcp"],
130
134
  "env": {
131
- "MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")
132
- }
135
+ "MCP_BROWSER_HOME": str(
136
+ Path.home() / ".mcp-browser"
137
+ )
138
+ },
133
139
  }
134
140
 
135
141
  # Then check for mcp-server.py
@@ -140,9 +146,11 @@ class MCPExternalServicesSetup:
140
146
  "command": str(venv_python),
141
147
  "args": [str(mcp_server)],
142
148
  "env": {
143
- "MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser"),
144
- "PYTHONPATH": str(dev_path)
145
- }
149
+ "MCP_BROWSER_HOME": str(
150
+ Path.home() / ".mcp-browser"
151
+ ),
152
+ "PYTHONPATH": str(dev_path),
153
+ },
146
154
  }
147
155
 
148
156
  # Check if the package is installed in this venv
@@ -151,7 +159,8 @@ class MCPExternalServicesSetup:
151
159
  result = subprocess.run(
152
160
  [str(venv_python), "-c", f"import {module_name}"],
153
161
  capture_output=True,
154
- timeout=5
162
+ timeout=5,
163
+ check=False,
155
164
  )
156
165
  if result.returncode == 0:
157
166
  # Use special configuration for local dev
@@ -159,21 +168,27 @@ class MCPExternalServicesSetup:
159
168
  return {
160
169
  "type": "stdio",
161
170
  "command": str(venv_python),
162
- "args": ["-m", "mcp_vector_search.mcp.server", str(project_path)],
163
- "env": {}
171
+ "args": [
172
+ "-m",
173
+ "mcp_vector_search.mcp.server",
174
+ str(project_path),
175
+ ],
176
+ "env": {},
164
177
  }
165
- elif service_name == "mcp-browser":
178
+ if service_name == "mcp-browser":
166
179
  # Fallback for mcp-browser without mcp-server.py
167
180
  return {
168
181
  "type": "stdio",
169
182
  "command": str(venv_python),
170
183
  "args": ["-m", "mcp_browser", "mcp"],
171
184
  "env": {
172
- "MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser"),
173
- "PYTHONPATH": str(dev_path)
174
- }
185
+ "MCP_BROWSER_HOME": str(
186
+ Path.home() / ".mcp-browser"
187
+ ),
188
+ "PYTHONPATH": str(dev_path),
189
+ },
175
190
  }
176
- except:
191
+ except Exception:
177
192
  continue
178
193
 
179
194
  return None
@@ -203,11 +218,14 @@ class MCPExternalServicesSetup:
203
218
  result = subprocess.run(
204
219
  [str(venv_python), "-c", f"import {module_name}"],
205
220
  capture_output=True,
206
- timeout=5
221
+ timeout=5,
222
+ check=False,
207
223
  )
208
224
  if result.returncode == 0:
209
- return self._create_service_config(service_name, str(venv_python), project_path)
210
- except:
225
+ return self._create_service_config(
226
+ service_name, str(venv_python), project_path
227
+ )
228
+ except Exception:
211
229
  continue
212
230
 
213
231
  return None
@@ -224,7 +242,9 @@ class MCPExternalServicesSetup:
224
242
  """
225
243
  return self._create_service_config(service_name, sys.executable, project_path)
226
244
 
227
- def _create_service_config(self, service_name: str, python_path: str, project_path: Path) -> Dict:
245
+ def _create_service_config(
246
+ self, service_name: str, python_path: str, project_path: Path
247
+ ) -> Dict:
228
248
  """Create service configuration for the given Python executable.
229
249
 
230
250
  Args:
@@ -243,32 +263,30 @@ class MCPExternalServicesSetup:
243
263
  "type": "stdio",
244
264
  "command": str(binary_path),
245
265
  "args": ["mcp"],
246
- "env": {"MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")}
247
- }
248
- else:
249
- # Use Python module invocation
250
- return {
251
- "type": "stdio",
252
- "command": python_path,
253
- "args": ["-m", "mcp_browser", "mcp"],
254
- "env": {"MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")}
266
+ "env": {"MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")},
255
267
  }
256
- elif service_name == "mcp-vector-search":
268
+ # Use Python module invocation
257
269
  return {
258
270
  "type": "stdio",
259
271
  "command": python_path,
260
- "args": ["-m", "mcp_vector_search.mcp.server", str(project_path)],
261
- "env": {}
272
+ "args": ["-m", "mcp_browser", "mcp"],
273
+ "env": {"MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")},
262
274
  }
263
- else:
264
- # Generic configuration for other services
265
- module_name = service_name.replace("-", "_")
275
+ if service_name == "mcp-vector-search":
266
276
  return {
267
277
  "type": "stdio",
268
278
  "command": python_path,
269
- "args": ["-m", module_name],
270
- "env": {}
279
+ "args": ["-m", "mcp_vector_search.mcp.server", str(project_path)],
280
+ "env": {},
271
281
  }
282
+ # Generic configuration for other services
283
+ module_name = service_name.replace("-", "_")
284
+ return {
285
+ "type": "stdio",
286
+ "command": python_path,
287
+ "args": ["-m", module_name],
288
+ "env": {},
289
+ }
272
290
 
273
291
  def detect_mcp_installations(self) -> Dict[str, Dict]:
274
292
  """Detect all MCP service installations and their locations.
@@ -293,7 +311,7 @@ class MCPExternalServicesSetup:
293
311
  installations[service_name] = {
294
312
  "type": "local_dev",
295
313
  "path": local_dev_config["command"],
296
- "config": local_dev_config
314
+ "config": local_dev_config,
297
315
  }
298
316
  continue
299
317
 
@@ -305,7 +323,7 @@ class MCPExternalServicesSetup:
305
323
  installations[service_name] = {
306
324
  "type": "pipx",
307
325
  "path": pipx_config["command"],
308
- "config": pipx_config
326
+ "config": pipx_config,
309
327
  }
310
328
  continue
311
329
 
@@ -314,7 +332,7 @@ class MCPExternalServicesSetup:
314
332
  installations[service_name] = {
315
333
  "type": "venv",
316
334
  "path": venv_config["command"],
317
- "config": venv_config
335
+ "config": venv_config,
318
336
  }
319
337
  continue
320
338
 
@@ -325,13 +343,13 @@ class MCPExternalServicesSetup:
325
343
  installations[service_name] = {
326
344
  "type": "system",
327
345
  "path": system_config["command"],
328
- "config": system_config
346
+ "config": system_config,
329
347
  }
330
348
  else:
331
349
  installations[service_name] = {
332
350
  "type": "not_installed",
333
351
  "path": None,
334
- "config": None
352
+ "config": None,
335
353
  }
336
354
 
337
355
  return installations
@@ -354,13 +372,13 @@ class MCPExternalServicesSetup:
354
372
  for service_name, info in installations.items():
355
373
  print(f"\n{service_name}:")
356
374
  if info["type"] == "not_installed":
357
- print(f" āŒ Not installed")
375
+ print(" āŒ Not installed")
358
376
  else:
359
377
  type_emoji = {
360
378
  "local_dev": "šŸ”§",
361
379
  "pipx": "šŸ“¦",
362
380
  "venv": "šŸ",
363
- "system": "šŸ’»"
381
+ "system": "šŸ’»",
364
382
  }.get(info["type"], "ā“")
365
383
  print(f" {type_emoji} Type: {info['type']}")
366
384
  print(f" šŸ“ Path: {info['path']}")
@@ -380,7 +398,9 @@ class MCPExternalServicesSetup:
380
398
 
381
399
  # Check if already configured
382
400
  if service_name in config.get("mcpServers", {}) and not force:
383
- print(f"\nāš ļø {service_name} already configured, skipping (use --force to override)")
401
+ print(
402
+ f"\nāš ļø {service_name} already configured, skipping (use --force to override)"
403
+ )
384
404
  continue
385
405
 
386
406
  # Update configuration
@@ -394,14 +414,14 @@ class MCPExternalServicesSetup:
394
414
  # Save configuration if updated
395
415
  if updated:
396
416
  if self._save_config(config, config_path):
397
- print("\nāœ… Successfully updated .mcp.json with detected configurations")
417
+ print(
418
+ "\nāœ… Successfully updated .mcp.json with detected configurations"
419
+ )
398
420
  return True
399
- else:
400
- print("\nāŒ Failed to save configuration")
401
- return False
402
- else:
403
- print("\nšŸ“Œ No updates needed")
404
- return True
421
+ print("\nāŒ Failed to save configuration")
422
+ return False
423
+ print("\nšŸ“Œ No updates needed")
424
+ return True
405
425
 
406
426
  def __init__(self, logger):
407
427
  """Initialize the external services setup handler."""
@@ -439,30 +459,30 @@ class MCPExternalServicesSetup:
439
459
 
440
460
  # Setup each external service
441
461
  success_count = 0
442
- for service_name, service_info in self.get_project_services(project_path).items():
462
+ for service_name, service_info in self.get_project_services(
463
+ project_path
464
+ ).items():
443
465
  if self._setup_service(config, service_name, service_info, force):
444
466
  success_count += 1
445
467
 
446
468
  # Save the updated configuration
447
469
  if success_count > 0:
448
470
  if self._save_config(config, config_path):
449
- print(f"\nāœ… Successfully configured {success_count} external services in .mcp.json")
450
- print(f"\nšŸ“Œ Note: Claude Desktop will automatically load these services")
451
- print(f" when you open this project directory in Claude Desktop.")
471
+ print(
472
+ f"\nāœ… Successfully configured {success_count} external services in .mcp.json"
473
+ )
474
+ print(
475
+ "\nšŸ“Œ Note: Claude Desktop will automatically load these services"
476
+ )
477
+ print(" when you open this project directory in Claude Desktop.")
452
478
  return True
453
- else:
454
- print("āŒ Failed to save configuration")
455
- return False
456
- else:
457
- print("\nāš ļø No external services were configured")
479
+ print("āŒ Failed to save configuration")
458
480
  return False
481
+ print("\nāš ļø No external services were configured")
482
+ return False
459
483
 
460
484
  def _setup_service(
461
- self,
462
- config: Dict,
463
- service_name: str,
464
- service_info: Dict,
465
- force: bool
485
+ self, config: Dict, service_name: str, service_info: Dict, force: bool
466
486
  ) -> bool:
467
487
  """Setup a single external MCP service.
468
488
 
@@ -485,12 +505,19 @@ class MCPExternalServicesSetup:
485
505
  print(f" Current args: {existing_config.get('args')}")
486
506
 
487
507
  # Check if it's using a local development path
488
- command = str(existing_config.get('command', ''))
489
- if any(path in command for path in ["/Projects/managed/", "/Projects/", "/Development/"]):
508
+ command = str(existing_config.get("command", ""))
509
+ if any(
510
+ path in command
511
+ for path in ["/Projects/managed/", "/Projects/", "/Development/"]
512
+ ):
490
513
  print(" šŸ“ Using local development version")
491
- response = input(" Keep local development version? (Y/n): ").strip().lower()
514
+ response = (
515
+ input(" Keep local development version? (Y/n): ").strip().lower()
516
+ )
492
517
  if response not in ["n", "no"]:
493
- print(f" āœ… Keeping existing local configuration for {service_name}")
518
+ print(
519
+ f" āœ… Keeping existing local configuration for {service_name}"
520
+ )
494
521
  return True # Consider it successfully configured
495
522
  else:
496
523
  response = input(" Overwrite? (y/N): ").strip().lower()
@@ -503,9 +530,11 @@ class MCPExternalServicesSetup:
503
530
  if not self._check_python_package(module_name):
504
531
  print(f" āš ļø Python package {service_info['package_name']} not installed")
505
532
  print(f" ā„¹ļø Installing {service_info['package_name']}...")
506
- if not self._install_python_package(service_info['package_name']):
533
+ if not self._install_python_package(service_info["package_name"]):
507
534
  print(f" āŒ Failed to install {service_info['package_name']}")
508
- print(f" ā„¹ļø Install manually with: pip install {service_info['package_name']}")
535
+ print(
536
+ f" ā„¹ļø Install manually with: pip install {service_info['package_name']}"
537
+ )
509
538
  return False
510
539
 
511
540
  # Add service configuration
@@ -518,7 +547,6 @@ class MCPExternalServicesSetup:
518
547
 
519
548
  return True
520
549
 
521
-
522
550
  def check_and_install_pip_packages(self) -> bool:
523
551
  """Check and install Python packages for external services.
524
552
 
@@ -529,7 +557,7 @@ class MCPExternalServicesSetup:
529
557
 
530
558
  packages_to_check = [
531
559
  ("mcp-vector-search", "mcp_vector_search"),
532
- ("mcp-browser", "mcp_browser")
560
+ ("mcp-browser", "mcp_browser"),
533
561
  ]
534
562
 
535
563
  all_installed = True
@@ -557,6 +585,7 @@ class MCPExternalServicesSetup:
557
585
  """
558
586
  try:
559
587
  import importlib.util
588
+
560
589
  spec = importlib.util.find_spec(module_name)
561
590
  return spec is not None
562
591
  except (ImportError, ModuleNotFoundError):
@@ -576,7 +605,8 @@ class MCPExternalServicesSetup:
576
605
  [sys.executable, "-m", "pip", "install", package_name],
577
606
  capture_output=True,
578
607
  text=True,
579
- timeout=60
608
+ timeout=60,
609
+ check=False,
580
610
  )
581
611
  return result.returncode == 0
582
612
  except (subprocess.TimeoutExpired, subprocess.CalledProcessError):
@@ -601,7 +631,7 @@ class MCPExternalServicesSetup:
601
631
  return config
602
632
  else:
603
633
  # Create new configuration
604
- print(f" šŸ“ Creating new .mcp.json file")
634
+ print(" šŸ“ Creating new .mcp.json file")
605
635
  return {"mcpServers": {}}
606
636
  except (OSError, json.JSONDecodeError) as e:
607
637
  print(f"āŒ Error loading config: {e}")
@@ -625,8 +655,13 @@ class MCPExternalServicesSetup:
625
655
  # Create backup if file exists
626
656
  if config_path.exists():
627
657
  from datetime import datetime
628
- backup_path = config_path.parent / f".mcp.backup.{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
658
+
659
+ backup_path = (
660
+ config_path.parent
661
+ / f".mcp.backup.{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}.json"
662
+ )
629
663
  import shutil
664
+
630
665
  shutil.copy2(config_path, backup_path)
631
666
  print(f" šŸ“ Created backup: {backup_path}")
632
667
 
@@ -665,16 +700,19 @@ class MCPExternalServicesSetup:
665
700
  result = subprocess.run(
666
701
  [str(python_path), "-c", "import mcp_browser.cli.main"],
667
702
  capture_output=True,
668
- timeout=5
703
+ timeout=5,
704
+ check=False,
669
705
  )
670
706
  if result.returncode == 0:
671
707
  return {
672
708
  "type": "stdio",
673
709
  "command": str(python_path),
674
710
  "args": ["-m", "mcp_browser.cli.main", "mcp"],
675
- "env": {"MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")}
711
+ "env": {
712
+ "MCP_BROWSER_HOME": str(Path.home() / ".mcp-browser")
713
+ },
676
714
  }
677
- except:
715
+ except Exception:
678
716
  pass
679
717
  elif package_name == "mcp-vector-search":
680
718
  # mcp-vector-search uses Python module invocation
@@ -685,16 +723,21 @@ class MCPExternalServicesSetup:
685
723
  result = subprocess.run(
686
724
  [str(python_path), "-c", "import mcp_vector_search"],
687
725
  capture_output=True,
688
- timeout=5
726
+ timeout=5,
727
+ check=False,
689
728
  )
690
729
  if result.returncode == 0:
691
730
  return {
692
731
  "type": "stdio",
693
732
  "command": str(python_path),
694
- "args": ["-m", "mcp_vector_search.mcp.server", str(project_path)],
695
- "env": {}
733
+ "args": [
734
+ "-m",
735
+ "mcp_vector_search.mcp.server",
736
+ str(project_path),
737
+ ],
738
+ "env": {},
696
739
  }
697
- except:
740
+ except Exception:
698
741
  pass
699
742
 
700
743
  return None
@@ -774,10 +817,8 @@ class MCPExternalServicesSetup:
774
817
  print("\nšŸ“Œ Note: Claude Desktop will automatically use this configuration")
775
818
  print(" when you open this project directory.")
776
819
  return True
777
- else:
778
- print("āŒ Failed to save configuration")
779
- return False
780
-
820
+ print("āŒ Failed to save configuration")
821
+ return False
781
822
 
782
823
  def list_external_services(self) -> None:
783
824
  """List all available external MCP services and their status."""
@@ -794,10 +835,10 @@ class MCPExternalServicesSetup:
794
835
  with open(mcp_config_path) as f:
795
836
  mcp_config = json.load(f)
796
837
  print(f"\nšŸ“ Project MCP config: {mcp_config_path}")
797
- except:
798
- print(f"\nāš ļø Could not read project .mcp.json")
838
+ except Exception:
839
+ print("\nāš ļø Could not read project .mcp.json")
799
840
  else:
800
- print(f"\nšŸ“ No .mcp.json found in project directory")
841
+ print("\nšŸ“ No .mcp.json found in project directory")
801
842
 
802
843
  # Get service configurations for this project
803
844
  services = self.get_project_services(project_path)
@@ -809,21 +850,21 @@ class MCPExternalServicesSetup:
809
850
 
810
851
  # Check if configured in .mcp.json
811
852
  if mcp_config.get("mcpServers", {}).get(service_name):
812
- print(f" Project Status: āœ… Configured in .mcp.json")
853
+ print(" Project Status: āœ… Configured in .mcp.json")
813
854
  service_config = mcp_config["mcpServers"][service_name]
814
855
  print(f" Command: {service_config.get('command')}")
815
- if service_config.get('args'):
856
+ if service_config.get("args"):
816
857
  print(f" Args: {service_config.get('args')}")
817
858
  else:
818
- print(f" Project Status: āŒ Not configured in .mcp.json")
859
+ print(" Project Status: āŒ Not configured in .mcp.json")
819
860
 
820
861
  # Check installation type
821
862
  is_installed, install_type = self._check_pipx_installation(service_name)
822
863
  if is_installed:
823
864
  if install_type == "pipx":
824
- print(f" Installation: āœ… Installed via pipx (recommended)")
865
+ print(" Installation: āœ… Installed via pipx (recommended)")
825
866
  else:
826
- print(f" Installation: āœ… Installed via pip")
867
+ print(" Installation: āœ… Installed via pip")
827
868
  else:
828
- print(f" Installation: āŒ Not installed")
829
- print(f" Install with: pipx install {service_info['package_name']}")
869
+ print(" Installation: āŒ Not installed")
870
+ print(f" Install with: pipx install {service_info['package_name']}")
@@ -37,7 +37,7 @@ class MonitorCommand(BaseCommand):
37
37
 
38
38
  return None
39
39
 
40
- def run(self, args) -> CommandResult:
40
+ def run(self, args) -> CommandResult: # noqa: PLR0911
41
41
  """Execute the monitor command using unified monitoring daemon."""
42
42
  try:
43
43
  self.logger.info("Monitor command using unified monitoring daemon")
@@ -142,7 +142,7 @@ class MonitorCommand(BaseCommand):
142
142
  return CommandResult.error_result(
143
143
  f"Port {port} is already in use. Try 'claude-mpm monitor stop' first or use a different port."
144
144
  )
145
- except:
145
+ except Exception:
146
146
  pass
147
147
 
148
148
  return CommandResult.error_result(
@@ -11,7 +11,7 @@ from rich.console import Console
11
11
  console = Console()
12
12
 
13
13
 
14
- def manage_mpm_init(args):
14
+ def manage_mpm_init(args): # noqa: PLR0911
15
15
  """
16
16
  Handle mpm-init command execution.
17
17
 
@@ -569,6 +569,41 @@ class RunCommand(BaseCommand):
569
569
  return False
570
570
 
571
571
 
572
+ def _ensure_mcp_services_configured(logger):
573
+ """
574
+ Ensure MCP services are configured in .mcp.json on startup.
575
+
576
+ This function automatically configures the core MCP services
577
+ (mcp-vector-search, mcp-browser, mcp-ticketer) if they're not
578
+ already configured in the project's .mcp.json file.
579
+
580
+ Args:
581
+ logger: Logger instance for output
582
+ """
583
+ try:
584
+ from ...services.mcp_config_manager import MCPConfigManager
585
+
586
+ logger.debug("Checking MCP service configuration...")
587
+ manager = MCPConfigManager()
588
+
589
+ # Check and auto-configure missing MCP services
590
+ success, message = manager.ensure_mcp_services_configured()
591
+
592
+ if success:
593
+ if "already configured" not in message.lower():
594
+ logger.info(message)
595
+ print(f"āœ… {message}")
596
+ else:
597
+ logger.debug(message)
598
+ else:
599
+ logger.warning(f"MCP auto-configuration issue: {message}")
600
+ # Don't fail the session, just warn
601
+
602
+ except Exception as e:
603
+ logger.debug(f"MCP auto-configuration skipped: {e}")
604
+ # Don't fail the session if auto-configuration fails
605
+
606
+
572
607
  def _handle_reload_agents(logger):
573
608
  """
574
609
  Handle the --reload-agents flag by deleting all local claude-mpm system agents.
@@ -583,8 +618,10 @@ def _handle_reload_agents(logger):
583
618
  logger.info("Reloading system agents - cleaning existing deployments...")
584
619
 
585
620
  # Import the cleanup service
621
+ from ...services.agents.deployment.agent_deployment import (
622
+ AgentDeploymentService,
623
+ )
586
624
  from ...services.cli.agent_cleanup_service import AgentCleanupService
587
- from ...services.agents.deployment.agent_deployment import AgentDeploymentService
588
625
 
589
626
  # Create services
590
627
  deployment_service = AgentDeploymentService()
@@ -599,7 +636,11 @@ def _handle_reload_agents(logger):
599
636
  # Check if cleanup was successful based on the result structure
600
637
  # The service returns a dict with 'removed', 'preserved', and possibly 'errors' keys
601
638
  # If it has 'success' key, use it; otherwise infer from the result
602
- success = result.get("success", True) if "success" in result else not result.get("errors")
639
+ success = (
640
+ result.get("success", True)
641
+ if "success" in result
642
+ else not result.get("errors")
643
+ )
603
644
 
604
645
  if success:
605
646
  removed_count = result.get("cleaned_count", len(result.get("removed", [])))
@@ -694,6 +735,9 @@ def run_session_legacy(args):
694
735
  if getattr(args, "reload_agents", False):
695
736
  _handle_reload_agents(logger)
696
737
 
738
+ # Auto-configure MCP services on startup
739
+ _ensure_mcp_services_configured(logger)
740
+
697
741
  try:
698
742
  from ...core.claude_runner import ClaudeRunner, create_simple_context
699
743
  except ImportError: