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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/PM_INSTRUCTIONS.md +390 -28
- claude_mpm/agents/templates/data_engineer.json +39 -14
- claude_mpm/cli/commands/agent_manager.py +3 -3
- claude_mpm/cli/commands/agents.py +2 -2
- claude_mpm/cli/commands/aggregate.py +1 -1
- claude_mpm/cli/commands/config.py +2 -2
- claude_mpm/cli/commands/configure.py +5 -5
- claude_mpm/cli/commands/configure_tui.py +7 -7
- claude_mpm/cli/commands/dashboard.py +1 -1
- claude_mpm/cli/commands/debug.py +5 -5
- claude_mpm/cli/commands/mcp.py +1 -1
- claude_mpm/cli/commands/mcp_command_router.py +1 -1
- claude_mpm/cli/commands/mcp_config.py +7 -10
- claude_mpm/cli/commands/mcp_external_commands.py +40 -32
- claude_mpm/cli/commands/mcp_install_commands.py +38 -10
- claude_mpm/cli/commands/mcp_setup_external.py +143 -102
- claude_mpm/cli/commands/monitor.py +2 -2
- claude_mpm/cli/commands/mpm_init_handler.py +1 -1
- claude_mpm/cli/commands/run.py +46 -2
- claude_mpm/cli/commands/search.py +41 -34
- claude_mpm/cli/interactive/agent_wizard.py +2 -2
- claude_mpm/cli/parsers/mcp_parser.py +1 -3
- claude_mpm/cli/parsers/search_parser.py +10 -4
- claude_mpm/cli/startup_logging.py +3 -5
- claude_mpm/cli/utils.py +1 -1
- claude_mpm/core/agent_registry.py +12 -8
- claude_mpm/core/agent_session_manager.py +8 -8
- claude_mpm/core/api_validator.py +4 -4
- claude_mpm/core/base_service.py +10 -10
- claude_mpm/core/cache.py +5 -5
- claude_mpm/core/config_constants.py +1 -1
- claude_mpm/core/container.py +1 -1
- claude_mpm/core/error_handler.py +2 -2
- claude_mpm/core/file_utils.py +1 -1
- claude_mpm/core/framework_loader.py +3 -3
- claude_mpm/core/hook_manager.py +8 -6
- claude_mpm/core/instruction_reinforcement_hook.py +2 -2
- claude_mpm/core/interactive_session.py +1 -1
- claude_mpm/core/lazy.py +3 -3
- claude_mpm/core/log_manager.py +16 -12
- claude_mpm/core/logger.py +16 -11
- claude_mpm/core/logging_config.py +4 -2
- claude_mpm/core/oneshot_session.py +1 -1
- claude_mpm/core/optimized_agent_loader.py +6 -6
- claude_mpm/core/output_style_manager.py +1 -1
- claude_mpm/core/pm_hook_interceptor.py +3 -3
- claude_mpm/core/service_registry.py +1 -1
- claude_mpm/core/session_manager.py +11 -9
- claude_mpm/core/socketio_pool.py +13 -13
- claude_mpm/core/types.py +2 -2
- claude_mpm/core/unified_agent_registry.py +2 -2
- claude_mpm/core/unified_paths.py +1 -1
- claude_mpm/dashboard/analysis_runner.py +4 -4
- claude_mpm/dashboard/api/simple_directory.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +4 -2
- claude_mpm/hooks/base_hook.py +2 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
- claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
- claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
- claude_mpm/hooks/claude_hooks/installer.py +3 -3
- claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
- claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +5 -5
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
- claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
- claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/hooks/tool_call_interceptor.py +2 -2
- claude_mpm/models/agent_session.py +5 -5
- claude_mpm/services/__init__.py +1 -1
- claude_mpm/services/agent_capabilities_service.py +1 -1
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/deployment/agent_deployment.py +2 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +9 -3
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +7 -5
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
- claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
- claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
- claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
- claude_mpm/services/agents/local_template_manager.py +6 -6
- claude_mpm/services/agents/management/agent_management_service.py +3 -3
- claude_mpm/services/agents/memory/content_manager.py +3 -3
- claude_mpm/services/agents/memory/memory_format_service.py +2 -2
- claude_mpm/services/agents/memory/template_generator.py +3 -3
- claude_mpm/services/agents/registry/__init__.py +1 -1
- claude_mpm/services/agents/registry/modification_tracker.py +2 -2
- claude_mpm/services/async_session_logger.py +3 -3
- claude_mpm/services/claude_session_logger.py +4 -4
- claude_mpm/services/cli/agent_listing_service.py +1 -1
- claude_mpm/services/cli/agent_validation_service.py +1 -0
- claude_mpm/services/cli/memory_crud_service.py +11 -6
- claude_mpm/services/cli/memory_output_formatter.py +1 -1
- claude_mpm/services/cli/session_manager.py +15 -11
- claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
- claude_mpm/services/core/memory_manager.py +81 -23
- claude_mpm/services/core/path_resolver.py +2 -2
- claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
- claude_mpm/services/event_aggregator.py +4 -2
- claude_mpm/services/event_bus/direct_relay.py +5 -3
- claude_mpm/services/event_bus/event_bus.py +3 -3
- claude_mpm/services/event_bus/relay.py +6 -4
- claude_mpm/services/events/consumers/dead_letter.py +5 -3
- claude_mpm/services/events/core.py +3 -3
- claude_mpm/services/events/producers/hook.py +6 -6
- claude_mpm/services/events/producers/system.py +8 -8
- claude_mpm/services/exceptions.py +5 -5
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
- claude_mpm/services/hook_installer_service.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +6 -4
- claude_mpm/services/infrastructure/daemon_manager.py +2 -2
- claude_mpm/services/infrastructure/logging.py +2 -2
- claude_mpm/services/mcp_config_manager.py +175 -30
- claude_mpm/services/mcp_gateway/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
- claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
- claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
- claude_mpm/services/mcp_gateway/core/base.py +2 -2
- claude_mpm/services/mcp_gateway/main.py +21 -7
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
- claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -3
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +190 -137
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
- claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +17 -17
- claude_mpm/services/memory/builder.py +7 -5
- claude_mpm/services/memory/indexed_memory.py +4 -4
- claude_mpm/services/memory/optimizer.py +6 -6
- claude_mpm/services/memory/router.py +3 -3
- claude_mpm/services/monitor/daemon.py +1 -1
- claude_mpm/services/monitor/daemon_manager.py +6 -6
- claude_mpm/services/monitor/event_emitter.py +2 -2
- claude_mpm/services/monitor/handlers/file.py +1 -1
- claude_mpm/services/monitor/management/lifecycle.py +1 -1
- claude_mpm/services/monitor/server.py +4 -4
- claude_mpm/services/monitor_build_service.py +2 -2
- claude_mpm/services/port_manager.py +2 -2
- claude_mpm/services/response_tracker.py +2 -2
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/socketio/client_proxy.py +2 -2
- claude_mpm/services/socketio/dashboard_server.py +4 -3
- claude_mpm/services/socketio/event_normalizer.py +12 -8
- claude_mpm/services/socketio/handlers/base.py +2 -2
- claude_mpm/services/socketio/handlers/connection.py +10 -10
- claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
- claude_mpm/services/socketio/handlers/file.py +1 -1
- claude_mpm/services/socketio/handlers/git.py +1 -1
- claude_mpm/services/socketio/handlers/hook.py +16 -15
- claude_mpm/services/socketio/migration_utils.py +1 -1
- claude_mpm/services/socketio/monitor_client.py +5 -5
- claude_mpm/services/socketio/server/broadcaster.py +9 -7
- claude_mpm/services/socketio/server/connection_manager.py +2 -2
- claude_mpm/services/socketio/server/core.py +7 -5
- claude_mpm/services/socketio/server/eventbus_integration.py +18 -11
- claude_mpm/services/socketio/server/main.py +13 -13
- claude_mpm/services/socketio_client_manager.py +4 -4
- claude_mpm/services/system_instructions_service.py +2 -2
- claude_mpm/services/ticket_services/validation_service.py +1 -1
- claude_mpm/services/utility_service.py +5 -2
- claude_mpm/services/version_control/branch_strategy.py +2 -2
- claude_mpm/services/version_control/git_operations.py +22 -20
- claude_mpm/services/version_control/semantic_versioning.py +3 -3
- claude_mpm/services/version_control/version_parser.py +7 -5
- claude_mpm/services/visualization/mermaid_generator.py +1 -1
- claude_mpm/storage/state_storage.py +1 -1
- claude_mpm/tools/code_tree_analyzer.py +19 -18
- claude_mpm/tools/code_tree_builder.py +2 -2
- claude_mpm/tools/code_tree_events.py +10 -8
- claude_mpm/tools/socketio_debug.py +3 -3
- claude_mpm/utils/agent_dependency_loader.py +2 -2
- claude_mpm/utils/dependency_strategies.py +8 -3
- claude_mpm/utils/environment_context.py +2 -2
- claude_mpm/utils/error_handler.py +2 -2
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/imports.py +1 -1
- claude_mpm/utils/log_cleanup.py +21 -7
- claude_mpm/validation/agent_validator.py +2 -2
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/METADATA +1 -1
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/RECORD +199 -199
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/WHEEL +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.3.12.dist-info → claude_mpm-4.3.13.dist-info}/licenses/LICENSE +0 -0
- {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 = (
|
|
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
|
|
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(
|
|
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 (
|
|
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
|
-
|
|
91
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
"
|
|
127
|
-
|
|
128
|
-
"
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
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,
|
|
201
|
-
"
|
|
202
|
-
"
|
|
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()
|
|
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
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
"
|
|
246
|
-
|
|
247
|
-
"
|
|
248
|
-
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
-
|
|
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,
|
|
290
|
-
"
|
|
291
|
-
"
|
|
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(
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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(
|
|
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(
|
|
441
|
+
self.logger.warning(
|
|
442
|
+
f"Error shutting down {service.service_name}: {e}"
|
|
443
|
+
)
|