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
@@ -17,6 +17,7 @@ import logging
17
17
  import os
18
18
  import sys
19
19
  import time
20
+ from datetime import timezone
20
21
  from typing import Any, Dict
21
22
 
22
23
  # Import MCP SDK components
@@ -172,7 +173,7 @@ class SimpleMCPServer:
172
173
 
173
174
  async def _summarize_content(
174
175
  self, content: str, style: str, max_length: int
175
- ) -> str:
176
+ ) -> str: # noqa: PLR0911
176
177
  """
177
178
  Summarize text content based on style and length constraints.
178
179
 
@@ -214,7 +215,7 @@ class SimpleMCPServer:
214
215
  # Default to brief
215
216
  return self._create_brief_summary(sentences, max_length)
216
217
 
217
- def _create_brief_summary(self, sentences: list[str], max_length: int) -> str:
218
+ def _create_brief_summary(self, sentences: list[str], max_length: int) -> str: # noqa: PLR0911
218
219
  """Create a brief summary by selecting most important sentences."""
219
220
  if not sentences:
220
221
  return ""
@@ -562,7 +563,7 @@ class SimpleMCPServer:
562
563
  f"Python: {sys.version.split()[0]}\n"
563
564
  f"Working Directory: {os.getcwd()}\n"
564
565
  f"Server: {self.name} v{self.version}\n"
565
- f"Timestamp: {datetime.datetime.now().isoformat()}\n"
566
+ f"Timestamp: {datetime.datetime.now(timezone.utc).isoformat()}\n"
566
567
  f"Tools Available: status, document_summarizer{', ticket' if self.unified_ticket_tool else ''}"
567
568
  )
568
569
  else:
@@ -8,7 +8,7 @@ Part of ISS-0035: MCP Server Implementation - Core Server and Tool Registry
8
8
  """
9
9
 
10
10
  from abc import ABC
11
- from datetime import datetime
11
+ from datetime import datetime, timezone
12
12
  from typing import Any, Dict
13
13
 
14
14
  from claude_mpm.services.mcp_gateway.core.base import BaseMCPService
@@ -195,7 +195,7 @@ class BaseToolAdapter(BaseMCPService, IMCPToolAdapter, ABC):
195
195
  self._metrics["average_execution_time"] = (
196
196
  self._metrics["total_execution_time"] / self._metrics["invocations"]
197
197
  )
198
- self._metrics["last_invocation"] = datetime.now().isoformat()
198
+ self._metrics["last_invocation"] = datetime.now(timezone.utc).isoformat()
199
199
 
200
200
 
201
201
  class EchoToolAdapter(BaseToolAdapter):
@@ -235,7 +235,7 @@ class EchoToolAdapter(BaseToolAdapter):
235
235
  Returns:
236
236
  Tool execution result with echoed message
237
237
  """
238
- start_time = datetime.now()
238
+ start_time = datetime.now(timezone.utc)
239
239
 
240
240
  try:
241
241
  # Get parameters
@@ -246,7 +246,7 @@ class EchoToolAdapter(BaseToolAdapter):
246
246
  result = message.upper() if uppercase else message
247
247
 
248
248
  # Calculate execution time
249
- execution_time = (datetime.now() - start_time).total_seconds()
249
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
250
250
 
251
251
  # Update metrics
252
252
  self._update_metrics(True, execution_time)
@@ -259,7 +259,7 @@ class EchoToolAdapter(BaseToolAdapter):
259
259
  )
260
260
 
261
261
  except Exception as e:
262
- execution_time = (datetime.now() - start_time).total_seconds()
262
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
263
263
  self._update_metrics(False, execution_time)
264
264
  self._metrics["last_error"] = str(e)
265
265
 
@@ -321,7 +321,7 @@ class CalculatorToolAdapter(BaseToolAdapter):
321
321
  Returns:
322
322
  Tool execution result with calculation
323
323
  """
324
- start_time = datetime.now()
324
+ start_time = datetime.now(timezone.utc)
325
325
 
326
326
  try:
327
327
  # Get parameters
@@ -348,7 +348,7 @@ class CalculatorToolAdapter(BaseToolAdapter):
348
348
  raise ValueError(f"Unknown operation: {operation}")
349
349
 
350
350
  # Calculate execution time
351
- execution_time = (datetime.now() - start_time).total_seconds()
351
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
352
352
 
353
353
  # Update metrics
354
354
  self._update_metrics(True, execution_time)
@@ -361,7 +361,7 @@ class CalculatorToolAdapter(BaseToolAdapter):
361
361
  )
362
362
 
363
363
  except Exception as e:
364
- execution_time = (datetime.now() - start_time).total_seconds()
364
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
365
365
  self._update_metrics(False, execution_time)
366
366
  self._metrics["last_error"] = str(e)
367
367
 
@@ -408,7 +408,7 @@ class SystemInfoToolAdapter(BaseToolAdapter):
408
408
  Returns:
409
409
  Tool execution result with system information
410
410
  """
411
- start_time = datetime.now()
411
+ start_time = datetime.now(timezone.utc)
412
412
 
413
413
  try:
414
414
  import platform
@@ -443,15 +443,15 @@ class SystemInfoToolAdapter(BaseToolAdapter):
443
443
  }
444
444
  elif info_type == "time":
445
445
  result = {
446
- "current": datetime.now().isoformat(),
447
- "timestamp": datetime.now().timestamp(),
448
- "timezone": str(datetime.now().astimezone().tzinfo),
446
+ "current": datetime.now(timezone.utc).isoformat(),
447
+ "timestamp": datetime.now(timezone.utc).timestamp(),
448
+ "timezone": str(datetime.now(timezone.utc).astimezone().tzinfo),
449
449
  }
450
450
  else:
451
451
  raise ValueError(f"Unknown info type: {info_type}")
452
452
 
453
453
  # Calculate execution time
454
- execution_time = (datetime.now() - start_time).total_seconds()
454
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
455
455
 
456
456
  # Update metrics
457
457
  self._update_metrics(True, execution_time)
@@ -465,7 +465,7 @@ class SystemInfoToolAdapter(BaseToolAdapter):
465
465
 
466
466
  except ImportError as e:
467
467
  # Handle missing psutil dependency gracefully
468
- execution_time = (datetime.now() - start_time).total_seconds()
468
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
469
469
  self._update_metrics(False, execution_time)
470
470
 
471
471
  return MCPToolResult(
@@ -474,7 +474,7 @@ class SystemInfoToolAdapter(BaseToolAdapter):
474
474
  execution_time=execution_time,
475
475
  )
476
476
  except Exception as e:
477
- execution_time = (datetime.now() - start_time).total_seconds()
477
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
478
478
  self._update_metrics(False, execution_time)
479
479
  self._metrics["last_error"] = str(e)
480
480
 
@@ -13,7 +13,7 @@ import mimetypes
13
13
  import os
14
14
  import re
15
15
  from collections import OrderedDict
16
- from datetime import datetime
16
+ from datetime import datetime, timezone
17
17
  from pathlib import Path
18
18
  from typing import Any, Dict, List, Optional, Tuple
19
19
 
@@ -605,7 +605,7 @@ class DocumentSummarizerTool(BaseToolAdapter):
605
605
  Returns:
606
606
  Tool execution result with summary
607
607
  """
608
- start_time = datetime.now()
608
+ start_time = datetime.now(timezone.utc)
609
609
 
610
610
  try:
611
611
  # Get parameters
@@ -628,7 +628,9 @@ class DocumentSummarizerTool(BaseToolAdapter):
628
628
  cached_result = self._cache.get(cache_key)
629
629
  if cached_result:
630
630
  cache_hit = True
631
- execution_time = (datetime.now() - start_time).total_seconds()
631
+ execution_time = (
632
+ datetime.now(timezone.utc) - start_time
633
+ ).total_seconds()
632
634
  self._update_metrics(True, execution_time)
633
635
 
634
636
  return MCPToolResult(
@@ -709,7 +711,7 @@ class DocumentSummarizerTool(BaseToolAdapter):
709
711
  self._cache.put(cache_key, result.copy(), summary_size)
710
712
 
711
713
  # Calculate execution time
712
- execution_time = (datetime.now() - start_time).total_seconds()
714
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
713
715
 
714
716
  # Update metrics
715
717
  self._update_metrics(True, execution_time)
@@ -730,7 +732,7 @@ class DocumentSummarizerTool(BaseToolAdapter):
730
732
  )
731
733
 
732
734
  except Exception as e:
733
- execution_time = (datetime.now() - start_time).total_seconds()
735
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
734
736
  self._update_metrics(False, execution_time)
735
737
  self._metrics["last_error"] = str(e)
736
738
 
@@ -10,14 +10,12 @@ Note: As of the latest architecture, external services are registered as separat
10
10
  MCP servers in Claude Desktop configuration, not as tools within the gateway.
11
11
  """
12
12
 
13
- import asyncio
14
13
  import json
15
14
  import subprocess
16
15
  import sys
17
16
  from pathlib import Path
18
- from typing import Any, Dict, List, Optional
17
+ from typing import Any, Dict, List
19
18
 
20
- from claude_mpm.services.mcp_gateway.core.base import BaseMCPService
21
19
  from claude_mpm.services.mcp_gateway.tools.base_adapter import BaseMCPToolAdapter
22
20
 
23
21
 
@@ -45,7 +43,9 @@ class ExternalMCPService(BaseMCPToolAdapter):
45
43
  self._is_installed = await self._check_installation()
46
44
 
47
45
  if not self._is_installed:
48
- self.logger.warning(f"{self.package_name} not installed, attempting installation...")
46
+ self.logger.warning(
47
+ f"{self.package_name} not installed, attempting installation..."
48
+ )
49
49
  await self._install_package()
50
50
  self._is_installed = await self._check_installation()
51
51
 
@@ -67,10 +67,15 @@ class ExternalMCPService(BaseMCPToolAdapter):
67
67
  [sys.executable, "-m", self.package_name.replace("-", "_"), "--help"],
68
68
  capture_output=True,
69
69
  text=True,
70
- timeout=5
70
+ timeout=5,
71
+ check=False,
71
72
  )
72
73
  return result.returncode == 0
73
- except (subprocess.TimeoutExpired, FileNotFoundError, subprocess.CalledProcessError):
74
+ except (
75
+ subprocess.TimeoutExpired,
76
+ FileNotFoundError,
77
+ subprocess.CalledProcessError,
78
+ ):
74
79
  return False
75
80
 
76
81
  async def _install_package(self) -> bool:
@@ -81,15 +86,15 @@ class ExternalMCPService(BaseMCPToolAdapter):
81
86
  [sys.executable, "-m", "pip", "install", self.package_name],
82
87
  capture_output=True,
83
88
  text=True,
84
- timeout=30
89
+ timeout=30,
90
+ check=False,
85
91
  )
86
92
 
87
93
  if result.returncode == 0:
88
94
  self.logger.info(f"Successfully installed {self.package_name}")
89
95
  return True
90
- else:
91
- self.logger.error(f"Failed to install {self.package_name}: {result.stderr}")
92
- return False
96
+ self.logger.error(f"Failed to install {self.package_name}: {result.stderr}")
97
+ return False
93
98
 
94
99
  except Exception as e:
95
100
  self.logger.error(f"Error installing {self.package_name}: {e}")
@@ -102,7 +107,7 @@ class ExternalMCPService(BaseMCPToolAdapter):
102
107
  "description": f"External MCP service: {self.package_name}",
103
108
  "type": "external_service",
104
109
  "package": self.package_name,
105
- "installed": self._is_installed
110
+ "installed": self._is_installed,
106
111
  }
107
112
 
108
113
 
@@ -116,77 +121,103 @@ class MCPVectorSearchService(ExternalMCPService):
116
121
  def get_definition(self) -> Dict[str, Any]:
117
122
  """Get tool definition for MCP registration."""
118
123
  base_def = super().get_definition()
119
- base_def.update({
120
- "description": "Semantic code search powered by vector embeddings",
121
- "tools": [
122
- {
123
- "name": "mcp__mcp-vector-search__search_code",
124
- "description": "Search for code using semantic similarity",
125
- "inputSchema": {
126
- "type": "object",
127
- "properties": {
128
- "query": {"type": "string", "description": "The search query"},
129
- "limit": {"type": "integer", "default": 10},
130
- "similarity_threshold": {"type": "number", "default": 0.3},
131
- "language": {"type": "string"},
132
- "file_extensions": {"type": "array", "items": {"type": "string"}},
133
- "files": {"type": "string"},
134
- "class_name": {"type": "string"},
135
- "function_name": {"type": "string"}
124
+ base_def.update(
125
+ {
126
+ "description": "Semantic code search powered by vector embeddings",
127
+ "tools": [
128
+ {
129
+ "name": "mcp__mcp-vector-search__search_code",
130
+ "description": "Search for code using semantic similarity",
131
+ "inputSchema": {
132
+ "type": "object",
133
+ "properties": {
134
+ "query": {
135
+ "type": "string",
136
+ "description": "The search query",
137
+ },
138
+ "limit": {"type": "integer", "default": 10},
139
+ "similarity_threshold": {
140
+ "type": "number",
141
+ "default": 0.3,
142
+ },
143
+ "language": {"type": "string"},
144
+ "file_extensions": {
145
+ "type": "array",
146
+ "items": {"type": "string"},
147
+ },
148
+ "files": {"type": "string"},
149
+ "class_name": {"type": "string"},
150
+ "function_name": {"type": "string"},
151
+ },
152
+ "required": ["query"],
136
153
  },
137
- "required": ["query"]
138
- }
139
- },
140
- {
141
- "name": "mcp__mcp-vector-search__search_similar",
142
- "description": "Find code similar to a specific file or function",
143
- "inputSchema": {
144
- "type": "object",
145
- "properties": {
146
- "file_path": {"type": "string", "description": "Path to the file"},
147
- "function_name": {"type": "string"},
148
- "limit": {"type": "integer", "default": 10},
149
- "similarity_threshold": {"type": "number", "default": 0.3}
154
+ },
155
+ {
156
+ "name": "mcp__mcp-vector-search__search_similar",
157
+ "description": "Find code similar to a specific file or function",
158
+ "inputSchema": {
159
+ "type": "object",
160
+ "properties": {
161
+ "file_path": {
162
+ "type": "string",
163
+ "description": "Path to the file",
164
+ },
165
+ "function_name": {"type": "string"},
166
+ "limit": {"type": "integer", "default": 10},
167
+ "similarity_threshold": {
168
+ "type": "number",
169
+ "default": 0.3,
170
+ },
171
+ },
172
+ "required": ["file_path"],
150
173
  },
151
- "required": ["file_path"]
152
- }
153
- },
154
- {
155
- "name": "mcp__mcp-vector-search__search_context",
156
- "description": "Search for code based on contextual description",
157
- "inputSchema": {
158
- "type": "object",
159
- "properties": {
160
- "description": {"type": "string", "description": "Contextual description"},
161
- "focus_areas": {"type": "array", "items": {"type": "string"}},
162
- "limit": {"type": "integer", "default": 10}
174
+ },
175
+ {
176
+ "name": "mcp__mcp-vector-search__search_context",
177
+ "description": "Search for code based on contextual description",
178
+ "inputSchema": {
179
+ "type": "object",
180
+ "properties": {
181
+ "description": {
182
+ "type": "string",
183
+ "description": "Contextual description",
184
+ },
185
+ "focus_areas": {
186
+ "type": "array",
187
+ "items": {"type": "string"},
188
+ },
189
+ "limit": {"type": "integer", "default": 10},
190
+ },
191
+ "required": ["description"],
163
192
  },
164
- "required": ["description"]
165
- }
166
- },
167
- {
168
- "name": "mcp__mcp-vector-search__get_project_status",
169
- "description": "Get project indexing status and statistics",
170
- "inputSchema": {
171
- "type": "object",
172
- "properties": {},
173
- "required": []
174
- }
175
- },
176
- {
177
- "name": "mcp__mcp-vector-search__index_project",
178
- "description": "Index or reindex the project codebase",
179
- "inputSchema": {
180
- "type": "object",
181
- "properties": {
182
- "force": {"type": "boolean", "default": False},
183
- "file_extensions": {"type": "array", "items": {"type": "string"}}
193
+ },
194
+ {
195
+ "name": "mcp__mcp-vector-search__get_project_status",
196
+ "description": "Get project indexing status and statistics",
197
+ "inputSchema": {
198
+ "type": "object",
199
+ "properties": {},
200
+ "required": [],
184
201
  },
185
- "required": []
186
- }
187
- }
188
- ]
189
- })
202
+ },
203
+ {
204
+ "name": "mcp__mcp-vector-search__index_project",
205
+ "description": "Index or reindex the project codebase",
206
+ "inputSchema": {
207
+ "type": "object",
208
+ "properties": {
209
+ "force": {"type": "boolean", "default": False},
210
+ "file_extensions": {
211
+ "type": "array",
212
+ "items": {"type": "string"},
213
+ },
214
+ },
215
+ "required": [],
216
+ },
217
+ },
218
+ ],
219
+ }
220
+ )
190
221
  return base_def
191
222
 
192
223
  async def invoke(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
@@ -197,9 +228,13 @@ class MCPVectorSearchService(ExternalMCPService):
197
228
 
198
229
  # Prepare the command
199
230
  cmd = [
200
- sys.executable, "-m", "mcp_vector_search",
201
- "--tool", actual_tool,
202
- "--args", json.dumps(arguments)
231
+ sys.executable,
232
+ "-m",
233
+ "mcp_vector_search",
234
+ "--tool",
235
+ actual_tool,
236
+ "--args",
237
+ json.dumps(arguments),
203
238
  ]
204
239
 
205
240
  # Run the command
@@ -208,7 +243,8 @@ class MCPVectorSearchService(ExternalMCPService):
208
243
  capture_output=True,
209
244
  text=True,
210
245
  timeout=30,
211
- cwd=Path.cwd() # Use current working directory for project context
246
+ cwd=Path.cwd(),
247
+ check=False, # Use current working directory for project context
212
248
  )
213
249
 
214
250
  if result.returncode == 0:
@@ -235,47 +271,61 @@ class MCPBrowserService(ExternalMCPService):
235
271
  def get_definition(self) -> Dict[str, Any]:
236
272
  """Get tool definition for MCP registration."""
237
273
  base_def = super().get_definition()
238
- base_def.update({
239
- "description": "Web browsing and content extraction capabilities",
240
- "tools": [
241
- {
242
- "name": "mcp__mcp-browser__browse",
243
- "description": "Browse a webpage and extract content",
244
- "inputSchema": {
245
- "type": "object",
246
- "properties": {
247
- "url": {"type": "string", "description": "URL to browse"},
248
- "extract": {"type": "string", "description": "What to extract"}
274
+ base_def.update(
275
+ {
276
+ "description": "Web browsing and content extraction capabilities",
277
+ "tools": [
278
+ {
279
+ "name": "mcp__mcp-browser__browse",
280
+ "description": "Browse a webpage and extract content",
281
+ "inputSchema": {
282
+ "type": "object",
283
+ "properties": {
284
+ "url": {
285
+ "type": "string",
286
+ "description": "URL to browse",
287
+ },
288
+ "extract": {
289
+ "type": "string",
290
+ "description": "What to extract",
291
+ },
292
+ },
293
+ "required": ["url"],
249
294
  },
250
- "required": ["url"]
251
- }
252
- },
253
- {
254
- "name": "mcp__mcp-browser__search",
255
- "description": "Search the web",
256
- "inputSchema": {
257
- "type": "object",
258
- "properties": {
259
- "query": {"type": "string", "description": "Search query"},
260
- "num_results": {"type": "integer", "default": 10}
295
+ },
296
+ {
297
+ "name": "mcp__mcp-browser__search",
298
+ "description": "Search the web",
299
+ "inputSchema": {
300
+ "type": "object",
301
+ "properties": {
302
+ "query": {
303
+ "type": "string",
304
+ "description": "Search query",
305
+ },
306
+ "num_results": {"type": "integer", "default": 10},
307
+ },
308
+ "required": ["query"],
261
309
  },
262
- "required": ["query"]
263
- }
264
- },
265
- {
266
- "name": "mcp__mcp-browser__screenshot",
267
- "description": "Take a screenshot of a webpage",
268
- "inputSchema": {
269
- "type": "object",
270
- "properties": {
271
- "url": {"type": "string", "description": "URL to screenshot"},
272
- "full_page": {"type": "boolean", "default": False}
310
+ },
311
+ {
312
+ "name": "mcp__mcp-browser__screenshot",
313
+ "description": "Take a screenshot of a webpage",
314
+ "inputSchema": {
315
+ "type": "object",
316
+ "properties": {
317
+ "url": {
318
+ "type": "string",
319
+ "description": "URL to screenshot",
320
+ },
321
+ "full_page": {"type": "boolean", "default": False},
322
+ },
323
+ "required": ["url"],
273
324
  },
274
- "required": ["url"]
275
- }
276
- }
277
- ]
278
- })
325
+ },
326
+ ],
327
+ }
328
+ )
279
329
  return base_def
280
330
 
281
331
  async def invoke(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
@@ -286,17 +336,18 @@ class MCPBrowserService(ExternalMCPService):
286
336
 
287
337
  # Prepare the command
288
338
  cmd = [
289
- sys.executable, "-m", "mcp_browser",
290
- "--tool", actual_tool,
291
- "--args", json.dumps(arguments)
339
+ sys.executable,
340
+ "-m",
341
+ "mcp_browser",
342
+ "--tool",
343
+ actual_tool,
344
+ "--args",
345
+ json.dumps(arguments),
292
346
  ]
293
347
 
294
348
  # Run the command
295
349
  result = subprocess.run(
296
- cmd,
297
- capture_output=True,
298
- text=True,
299
- timeout=30
350
+ cmd, capture_output=True, text=True, timeout=30, check=False
300
351
  )
301
352
 
302
353
  if result.returncode == 0:
@@ -338,10 +389,7 @@ class ExternalMCPServiceManager:
338
389
  them as tools in the gateway - they run as separate MCP servers.
339
390
  """
340
391
  # Create service instances
341
- services = [
342
- MCPVectorSearchService(),
343
- MCPBrowserService()
344
- ]
392
+ services = [MCPVectorSearchService(), MCPBrowserService()]
345
393
 
346
394
  # Initialize each service
347
395
  initialized_services = []
@@ -350,10 +398,11 @@ class ExternalMCPServiceManager:
350
398
  if await service.initialize():
351
399
  initialized_services.append(service)
352
400
  if self.logger:
353
- self.logger.info(f"Initialized external service: {service.service_name}")
354
- else:
355
- if self.logger:
356
- self.logger.warning(f"Failed to initialize: {service.service_name}")
401
+ self.logger.info(
402
+ f"Initialized external service: {service.service_name}"
403
+ )
404
+ elif self.logger:
405
+ self.logger.warning(f"Failed to initialize: {service.service_name}")
357
406
  except Exception as e:
358
407
  if self.logger:
359
408
  self.logger.error(f"Error initializing {service.service_name}: {e}")
@@ -370,7 +419,9 @@ class ExternalMCPServiceManager:
370
419
  all_tools.extend(service_def["tools"])
371
420
  return all_tools
372
421
 
373
- async def invoke_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
422
+ async def invoke_tool(
423
+ self, tool_name: str, arguments: Dict[str, Any]
424
+ ) -> Dict[str, Any]:
374
425
  """Invoke a tool from any registered external service."""
375
426
  # Find the service that handles this tool
376
427
  for service in self.services:
@@ -387,4 +438,6 @@ class ExternalMCPServiceManager:
387
438
  await service.shutdown()
388
439
  except Exception as e:
389
440
  if self.logger:
390
- self.logger.warning(f"Error shutting down {service.service_name}: {e}")
441
+ self.logger.warning(
442
+ f"Error shutting down {service.service_name}: {e}"
443
+ )