claude-mpm 3.9.8__py3-none-any.whl → 3.9.9__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/base_agent.json +1 -1
- claude_mpm/cli/__init__.py +3 -1
- claude_mpm/cli/commands/__init__.py +3 -1
- claude_mpm/cli/commands/cleanup.py +21 -1
- claude_mpm/cli/commands/mcp.py +821 -0
- claude_mpm/cli/parser.py +148 -1
- claude_mpm/config/memory_guardian_config.py +325 -0
- claude_mpm/constants.py +13 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +76 -19
- claude_mpm/models/state_models.py +433 -0
- claude_mpm/services/communication/__init__.py +2 -2
- claude_mpm/services/communication/socketio.py +18 -16
- claude_mpm/services/infrastructure/__init__.py +4 -1
- claude_mpm/services/infrastructure/logging.py +3 -3
- claude_mpm/services/infrastructure/memory_guardian.py +770 -0
- claude_mpm/services/mcp_gateway/__init__.py +28 -12
- claude_mpm/services/mcp_gateway/main.py +326 -0
- claude_mpm/services/mcp_gateway/registry/__init__.py +6 -3
- claude_mpm/services/mcp_gateway/registry/service_registry.py +397 -0
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +477 -0
- claude_mpm/services/mcp_gateway/server/__init__.py +9 -3
- claude_mpm/services/mcp_gateway/server/mcp_server.py +430 -0
- claude_mpm/services/mcp_gateway/server/mcp_server_simple.py +444 -0
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +373 -0
- claude_mpm/services/mcp_gateway/tools/__init__.py +16 -3
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +497 -0
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +729 -0
- claude_mpm/services/mcp_gateway/tools/hello_world.py +551 -0
- claude_mpm/utils/file_utils.py +293 -0
- claude_mpm/utils/platform_memory.py +524 -0
- claude_mpm/utils/subprocess_utils.py +305 -0
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/METADATA +3 -1
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/RECORD +39 -28
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_agent.md +0 -39
- claude_mpm/agents/templates/.claude-mpm/memories/qa_agent.md +0 -38
- claude_mpm/agents/templates/.claude-mpm/memories/research_agent.md +0 -39
- claude_mpm/agents/templates/.claude-mpm/memories/version_control_agent.md +0 -38
- /claude_mpm/agents/templates/{research_memory_efficient.json → backup/research_memory_efficient.json} +0 -0
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/top_level.txt +0 -0
| @@ -0,0 +1,497 @@ | |
| 1 | 
            +
            """
         | 
| 2 | 
            +
            Base Tool Adapter and Example Implementations
         | 
| 3 | 
            +
            ==============================================
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Base class for MCP tool adapters and example implementations.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Part of ISS-0035: MCP Server Implementation - Core Server and Tool Registry
         | 
| 8 | 
            +
            """
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            from abc import ABC
         | 
| 11 | 
            +
            from typing import Any, Dict, Optional
         | 
| 12 | 
            +
            import json
         | 
| 13 | 
            +
            import traceback
         | 
| 14 | 
            +
            from datetime import datetime
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            from claude_mpm.services.mcp_gateway.core.interfaces import (
         | 
| 17 | 
            +
                IMCPToolAdapter,
         | 
| 18 | 
            +
                MCPToolDefinition,
         | 
| 19 | 
            +
                MCPToolInvocation,
         | 
| 20 | 
            +
                MCPToolResult,
         | 
| 21 | 
            +
            )
         | 
| 22 | 
            +
            from claude_mpm.services.mcp_gateway.core.base import BaseMCPService
         | 
| 23 | 
            +
             | 
| 24 | 
            +
             | 
| 25 | 
            +
            class BaseToolAdapter(BaseMCPService, IMCPToolAdapter, ABC):
         | 
| 26 | 
            +
                """
         | 
| 27 | 
            +
                Base class for MCP tool adapters.
         | 
| 28 | 
            +
                
         | 
| 29 | 
            +
                WHY: This base class provides common functionality for all tool adapters,
         | 
| 30 | 
            +
                including parameter validation, error handling, and metrics tracking.
         | 
| 31 | 
            +
                Concrete tool implementations should extend this class.
         | 
| 32 | 
            +
                
         | 
| 33 | 
            +
                DESIGN DECISIONS:
         | 
| 34 | 
            +
                - Provide default parameter validation using JSON Schema
         | 
| 35 | 
            +
                - Include standard error handling and logging
         | 
| 36 | 
            +
                - Track execution metrics for monitoring
         | 
| 37 | 
            +
                - Support both sync and async tool implementations
         | 
| 38 | 
            +
                """
         | 
| 39 | 
            +
                
         | 
| 40 | 
            +
                def __init__(self, tool_definition: MCPToolDefinition):
         | 
| 41 | 
            +
                    """
         | 
| 42 | 
            +
                    Initialize the base tool adapter.
         | 
| 43 | 
            +
                    
         | 
| 44 | 
            +
                    Args:
         | 
| 45 | 
            +
                        tool_definition: Tool definition with schema and metadata
         | 
| 46 | 
            +
                    """
         | 
| 47 | 
            +
                    super().__init__(f"Tool-{tool_definition.name}")
         | 
| 48 | 
            +
                    self._definition = tool_definition
         | 
| 49 | 
            +
                    self._initialized = False
         | 
| 50 | 
            +
                    
         | 
| 51 | 
            +
                    # Metrics
         | 
| 52 | 
            +
                    self._metrics = {
         | 
| 53 | 
            +
                        "invocations": 0,
         | 
| 54 | 
            +
                        "successes": 0,
         | 
| 55 | 
            +
                        "failures": 0,
         | 
| 56 | 
            +
                        "total_execution_time": 0.0,
         | 
| 57 | 
            +
                        "average_execution_time": 0.0,
         | 
| 58 | 
            +
                        "last_invocation": None,
         | 
| 59 | 
            +
                        "last_error": None
         | 
| 60 | 
            +
                    }
         | 
| 61 | 
            +
                
         | 
| 62 | 
            +
                def get_definition(self) -> MCPToolDefinition:
         | 
| 63 | 
            +
                    """
         | 
| 64 | 
            +
                    Get the tool definition.
         | 
| 65 | 
            +
                    
         | 
| 66 | 
            +
                    Returns:
         | 
| 67 | 
            +
                        Tool definition with schema and metadata
         | 
| 68 | 
            +
                    """
         | 
| 69 | 
            +
                    return self._definition
         | 
| 70 | 
            +
                
         | 
| 71 | 
            +
                def validate_parameters(self, parameters: Dict[str, Any]) -> bool:
         | 
| 72 | 
            +
                    """
         | 
| 73 | 
            +
                    Validate tool parameters against schema.
         | 
| 74 | 
            +
                    
         | 
| 75 | 
            +
                    Default implementation performs basic JSON Schema validation.
         | 
| 76 | 
            +
                    Override for custom validation logic.
         | 
| 77 | 
            +
                    
         | 
| 78 | 
            +
                    Args:
         | 
| 79 | 
            +
                        parameters: Parameters to validate
         | 
| 80 | 
            +
                        
         | 
| 81 | 
            +
                    Returns:
         | 
| 82 | 
            +
                        True if parameters are valid
         | 
| 83 | 
            +
                    """
         | 
| 84 | 
            +
                    try:
         | 
| 85 | 
            +
                        # Get required parameters from schema
         | 
| 86 | 
            +
                        schema = self._definition.input_schema
         | 
| 87 | 
            +
                        required = schema.get("required", [])
         | 
| 88 | 
            +
                        properties = schema.get("properties", {})
         | 
| 89 | 
            +
                        
         | 
| 90 | 
            +
                        # Check required parameters
         | 
| 91 | 
            +
                        for param in required:
         | 
| 92 | 
            +
                            if param not in parameters:
         | 
| 93 | 
            +
                                self.log_error(f"Missing required parameter: {param}")
         | 
| 94 | 
            +
                                return False
         | 
| 95 | 
            +
                        
         | 
| 96 | 
            +
                        # Check parameter types (basic validation)
         | 
| 97 | 
            +
                        for param_name, param_value in parameters.items():
         | 
| 98 | 
            +
                            if param_name in properties:
         | 
| 99 | 
            +
                                expected_type = properties[param_name].get("type")
         | 
| 100 | 
            +
                                if expected_type:
         | 
| 101 | 
            +
                                    if not self._validate_type(param_value, expected_type):
         | 
| 102 | 
            +
                                        self.log_error(f"Invalid type for parameter {param_name}: expected {expected_type}")
         | 
| 103 | 
            +
                                        return False
         | 
| 104 | 
            +
                        
         | 
| 105 | 
            +
                        return True
         | 
| 106 | 
            +
                        
         | 
| 107 | 
            +
                    except Exception as e:
         | 
| 108 | 
            +
                        self.log_error(f"Error validating parameters: {e}")
         | 
| 109 | 
            +
                        return False
         | 
| 110 | 
            +
                
         | 
| 111 | 
            +
                def _validate_type(self, value: Any, expected_type: str) -> bool:
         | 
| 112 | 
            +
                    """
         | 
| 113 | 
            +
                    Validate a value against an expected JSON Schema type.
         | 
| 114 | 
            +
                    
         | 
| 115 | 
            +
                    Args:
         | 
| 116 | 
            +
                        value: Value to validate
         | 
| 117 | 
            +
                        expected_type: Expected type (string, number, boolean, array, object)
         | 
| 118 | 
            +
                        
         | 
| 119 | 
            +
                    Returns:
         | 
| 120 | 
            +
                        True if type matches
         | 
| 121 | 
            +
                    """
         | 
| 122 | 
            +
                    type_map = {
         | 
| 123 | 
            +
                        "string": str,
         | 
| 124 | 
            +
                        "number": (int, float),
         | 
| 125 | 
            +
                        "boolean": bool,
         | 
| 126 | 
            +
                        "array": list,
         | 
| 127 | 
            +
                        "object": dict,
         | 
| 128 | 
            +
                        "null": type(None)
         | 
| 129 | 
            +
                    }
         | 
| 130 | 
            +
                    
         | 
| 131 | 
            +
                    expected_python_type = type_map.get(expected_type)
         | 
| 132 | 
            +
                    if expected_python_type:
         | 
| 133 | 
            +
                        return isinstance(value, expected_python_type)
         | 
| 134 | 
            +
                    
         | 
| 135 | 
            +
                    return True  # Unknown type, allow it
         | 
| 136 | 
            +
                
         | 
| 137 | 
            +
                async def initialize(self) -> bool:
         | 
| 138 | 
            +
                    """
         | 
| 139 | 
            +
                    Initialize the tool adapter.
         | 
| 140 | 
            +
                    
         | 
| 141 | 
            +
                    Default implementation marks as initialized.
         | 
| 142 | 
            +
                    Override for custom initialization logic.
         | 
| 143 | 
            +
                    
         | 
| 144 | 
            +
                    Returns:
         | 
| 145 | 
            +
                        True if initialization successful
         | 
| 146 | 
            +
                    """
         | 
| 147 | 
            +
                    try:
         | 
| 148 | 
            +
                        self.log_info(f"Initializing tool: {self._definition.name}")
         | 
| 149 | 
            +
                        self._initialized = True
         | 
| 150 | 
            +
                        return True
         | 
| 151 | 
            +
                        
         | 
| 152 | 
            +
                    except Exception as e:
         | 
| 153 | 
            +
                        self.log_error(f"Failed to initialize tool: {e}")
         | 
| 154 | 
            +
                        return False
         | 
| 155 | 
            +
                
         | 
| 156 | 
            +
                async def shutdown(self) -> None:
         | 
| 157 | 
            +
                    """
         | 
| 158 | 
            +
                    Shutdown the tool adapter and clean up resources.
         | 
| 159 | 
            +
                    
         | 
| 160 | 
            +
                    Default implementation marks as not initialized.
         | 
| 161 | 
            +
                    Override for custom cleanup logic.
         | 
| 162 | 
            +
                    """
         | 
| 163 | 
            +
                    try:
         | 
| 164 | 
            +
                        self.log_info(f"Shutting down tool: {self._definition.name}")
         | 
| 165 | 
            +
                        self._initialized = False
         | 
| 166 | 
            +
                        
         | 
| 167 | 
            +
                    except Exception as e:
         | 
| 168 | 
            +
                        self.log_error(f"Error during tool shutdown: {e}")
         | 
| 169 | 
            +
                
         | 
| 170 | 
            +
                def get_metrics(self) -> Dict[str, Any]:
         | 
| 171 | 
            +
                    """
         | 
| 172 | 
            +
                    Get tool metrics.
         | 
| 173 | 
            +
                    
         | 
| 174 | 
            +
                    Returns:
         | 
| 175 | 
            +
                        Metrics dictionary
         | 
| 176 | 
            +
                    """
         | 
| 177 | 
            +
                    return self._metrics.copy()
         | 
| 178 | 
            +
                
         | 
| 179 | 
            +
                def _update_metrics(self, success: bool, execution_time: float) -> None:
         | 
| 180 | 
            +
                    """
         | 
| 181 | 
            +
                    Update tool metrics after invocation.
         | 
| 182 | 
            +
                    
         | 
| 183 | 
            +
                    Args:
         | 
| 184 | 
            +
                        success: Whether invocation was successful
         | 
| 185 | 
            +
                        execution_time: Execution time in seconds
         | 
| 186 | 
            +
                    """
         | 
| 187 | 
            +
                    self._metrics["invocations"] += 1
         | 
| 188 | 
            +
                    
         | 
| 189 | 
            +
                    if success:
         | 
| 190 | 
            +
                        self._metrics["successes"] += 1
         | 
| 191 | 
            +
                    else:
         | 
| 192 | 
            +
                        self._metrics["failures"] += 1
         | 
| 193 | 
            +
                    
         | 
| 194 | 
            +
                    self._metrics["total_execution_time"] += execution_time
         | 
| 195 | 
            +
                    self._metrics["average_execution_time"] = (
         | 
| 196 | 
            +
                        self._metrics["total_execution_time"] / self._metrics["invocations"]
         | 
| 197 | 
            +
                    )
         | 
| 198 | 
            +
                    self._metrics["last_invocation"] = datetime.now().isoformat()
         | 
| 199 | 
            +
             | 
| 200 | 
            +
             | 
| 201 | 
            +
            class EchoToolAdapter(BaseToolAdapter):
         | 
| 202 | 
            +
                """
         | 
| 203 | 
            +
                Example tool adapter that echoes input back.
         | 
| 204 | 
            +
                
         | 
| 205 | 
            +
                This is a simple example showing how to implement a concrete tool adapter.
         | 
| 206 | 
            +
                """
         | 
| 207 | 
            +
                
         | 
| 208 | 
            +
                def __init__(self):
         | 
| 209 | 
            +
                    """Initialize the echo tool."""
         | 
| 210 | 
            +
                    definition = MCPToolDefinition(
         | 
| 211 | 
            +
                        name="echo",
         | 
| 212 | 
            +
                        description="Echoes the input message back to the user",
         | 
| 213 | 
            +
                        input_schema={
         | 
| 214 | 
            +
                            "type": "object",
         | 
| 215 | 
            +
                            "properties": {
         | 
| 216 | 
            +
                                "message": {
         | 
| 217 | 
            +
                                    "type": "string",
         | 
| 218 | 
            +
                                    "description": "The message to echo"
         | 
| 219 | 
            +
                                },
         | 
| 220 | 
            +
                                "uppercase": {
         | 
| 221 | 
            +
                                    "type": "boolean",
         | 
| 222 | 
            +
                                    "description": "Whether to convert to uppercase",
         | 
| 223 | 
            +
                                    "default": False
         | 
| 224 | 
            +
                                }
         | 
| 225 | 
            +
                            },
         | 
| 226 | 
            +
                            "required": ["message"]
         | 
| 227 | 
            +
                        }
         | 
| 228 | 
            +
                    )
         | 
| 229 | 
            +
                    super().__init__(definition)
         | 
| 230 | 
            +
                
         | 
| 231 | 
            +
                async def invoke(self, invocation: MCPToolInvocation) -> MCPToolResult:
         | 
| 232 | 
            +
                    """
         | 
| 233 | 
            +
                    Invoke the echo tool.
         | 
| 234 | 
            +
                    
         | 
| 235 | 
            +
                    Args:
         | 
| 236 | 
            +
                        invocation: Tool invocation request
         | 
| 237 | 
            +
                        
         | 
| 238 | 
            +
                    Returns:
         | 
| 239 | 
            +
                        Tool execution result with echoed message
         | 
| 240 | 
            +
                    """
         | 
| 241 | 
            +
                    start_time = datetime.now()
         | 
| 242 | 
            +
                    
         | 
| 243 | 
            +
                    try:
         | 
| 244 | 
            +
                        # Get parameters
         | 
| 245 | 
            +
                        message = invocation.parameters.get("message", "")
         | 
| 246 | 
            +
                        uppercase = invocation.parameters.get("uppercase", False)
         | 
| 247 | 
            +
                        
         | 
| 248 | 
            +
                        # Process message
         | 
| 249 | 
            +
                        result = message.upper() if uppercase else message
         | 
| 250 | 
            +
                        
         | 
| 251 | 
            +
                        # Calculate execution time
         | 
| 252 | 
            +
                        execution_time = (datetime.now() - start_time).total_seconds()
         | 
| 253 | 
            +
                        
         | 
| 254 | 
            +
                        # Update metrics
         | 
| 255 | 
            +
                        self._update_metrics(True, execution_time)
         | 
| 256 | 
            +
                        
         | 
| 257 | 
            +
                        return MCPToolResult(
         | 
| 258 | 
            +
                            success=True,
         | 
| 259 | 
            +
                            data=result,
         | 
| 260 | 
            +
                            execution_time=execution_time,
         | 
| 261 | 
            +
                            metadata={"tool": "echo", "length": len(result)}
         | 
| 262 | 
            +
                        )
         | 
| 263 | 
            +
                        
         | 
| 264 | 
            +
                    except Exception as e:
         | 
| 265 | 
            +
                        execution_time = (datetime.now() - start_time).total_seconds()
         | 
| 266 | 
            +
                        self._update_metrics(False, execution_time)
         | 
| 267 | 
            +
                        self._metrics["last_error"] = str(e)
         | 
| 268 | 
            +
                        
         | 
| 269 | 
            +
                        return MCPToolResult(
         | 
| 270 | 
            +
                            success=False,
         | 
| 271 | 
            +
                            error=f"Echo tool failed: {str(e)}",
         | 
| 272 | 
            +
                            execution_time=execution_time
         | 
| 273 | 
            +
                        )
         | 
| 274 | 
            +
             | 
| 275 | 
            +
             | 
| 276 | 
            +
            class CalculatorToolAdapter(BaseToolAdapter):
         | 
| 277 | 
            +
                """
         | 
| 278 | 
            +
                Example calculator tool adapter.
         | 
| 279 | 
            +
                
         | 
| 280 | 
            +
                Demonstrates a more complex tool with multiple operations.
         | 
| 281 | 
            +
                """
         | 
| 282 | 
            +
                
         | 
| 283 | 
            +
                def __init__(self):
         | 
| 284 | 
            +
                    """Initialize the calculator tool."""
         | 
| 285 | 
            +
                    definition = MCPToolDefinition(
         | 
| 286 | 
            +
                        name="calculator",
         | 
| 287 | 
            +
                        description="Performs basic mathematical calculations",
         | 
| 288 | 
            +
                        input_schema={
         | 
| 289 | 
            +
                            "type": "object",
         | 
| 290 | 
            +
                            "properties": {
         | 
| 291 | 
            +
                                "operation": {
         | 
| 292 | 
            +
                                    "type": "string",
         | 
| 293 | 
            +
                                    "enum": ["add", "subtract", "multiply", "divide"],
         | 
| 294 | 
            +
                                    "description": "The mathematical operation to perform"
         | 
| 295 | 
            +
                                },
         | 
| 296 | 
            +
                                "a": {
         | 
| 297 | 
            +
                                    "type": "number",
         | 
| 298 | 
            +
                                    "description": "First operand"
         | 
| 299 | 
            +
                                },
         | 
| 300 | 
            +
                                "b": {
         | 
| 301 | 
            +
                                    "type": "number",
         | 
| 302 | 
            +
                                    "description": "Second operand"
         | 
| 303 | 
            +
                                }
         | 
| 304 | 
            +
                            },
         | 
| 305 | 
            +
                            "required": ["operation", "a", "b"]
         | 
| 306 | 
            +
                        },
         | 
| 307 | 
            +
                        output_schema={
         | 
| 308 | 
            +
                            "type": "object",
         | 
| 309 | 
            +
                            "properties": {
         | 
| 310 | 
            +
                                "result": {
         | 
| 311 | 
            +
                                    "type": "number",
         | 
| 312 | 
            +
                                    "description": "The calculation result"
         | 
| 313 | 
            +
                                },
         | 
| 314 | 
            +
                                "expression": {
         | 
| 315 | 
            +
                                    "type": "string",
         | 
| 316 | 
            +
                                    "description": "The mathematical expression"
         | 
| 317 | 
            +
                                }
         | 
| 318 | 
            +
                            }
         | 
| 319 | 
            +
                        }
         | 
| 320 | 
            +
                    )
         | 
| 321 | 
            +
                    super().__init__(definition)
         | 
| 322 | 
            +
                
         | 
| 323 | 
            +
                async def invoke(self, invocation: MCPToolInvocation) -> MCPToolResult:
         | 
| 324 | 
            +
                    """
         | 
| 325 | 
            +
                    Invoke the calculator tool.
         | 
| 326 | 
            +
                    
         | 
| 327 | 
            +
                    Args:
         | 
| 328 | 
            +
                        invocation: Tool invocation request
         | 
| 329 | 
            +
                        
         | 
| 330 | 
            +
                    Returns:
         | 
| 331 | 
            +
                        Tool execution result with calculation
         | 
| 332 | 
            +
                    """
         | 
| 333 | 
            +
                    start_time = datetime.now()
         | 
| 334 | 
            +
                    
         | 
| 335 | 
            +
                    try:
         | 
| 336 | 
            +
                        # Get parameters
         | 
| 337 | 
            +
                        operation = invocation.parameters["operation"]
         | 
| 338 | 
            +
                        a = invocation.parameters["a"]
         | 
| 339 | 
            +
                        b = invocation.parameters["b"]
         | 
| 340 | 
            +
                        
         | 
| 341 | 
            +
                        # Perform calculation
         | 
| 342 | 
            +
                        if operation == "add":
         | 
| 343 | 
            +
                            result = a + b
         | 
| 344 | 
            +
                            expression = f"{a} + {b} = {result}"
         | 
| 345 | 
            +
                        elif operation == "subtract":
         | 
| 346 | 
            +
                            result = a - b
         | 
| 347 | 
            +
                            expression = f"{a} - {b} = {result}"
         | 
| 348 | 
            +
                        elif operation == "multiply":
         | 
| 349 | 
            +
                            result = a * b
         | 
| 350 | 
            +
                            expression = f"{a} * {b} = {result}"
         | 
| 351 | 
            +
                        elif operation == "divide":
         | 
| 352 | 
            +
                            if b == 0:
         | 
| 353 | 
            +
                                raise ValueError("Division by zero")
         | 
| 354 | 
            +
                            result = a / b
         | 
| 355 | 
            +
                            expression = f"{a} / {b} = {result}"
         | 
| 356 | 
            +
                        else:
         | 
| 357 | 
            +
                            raise ValueError(f"Unknown operation: {operation}")
         | 
| 358 | 
            +
                        
         | 
| 359 | 
            +
                        # Calculate execution time
         | 
| 360 | 
            +
                        execution_time = (datetime.now() - start_time).total_seconds()
         | 
| 361 | 
            +
                        
         | 
| 362 | 
            +
                        # Update metrics
         | 
| 363 | 
            +
                        self._update_metrics(True, execution_time)
         | 
| 364 | 
            +
                        
         | 
| 365 | 
            +
                        return MCPToolResult(
         | 
| 366 | 
            +
                            success=True,
         | 
| 367 | 
            +
                            data={
         | 
| 368 | 
            +
                                "result": result,
         | 
| 369 | 
            +
                                "expression": expression
         | 
| 370 | 
            +
                            },
         | 
| 371 | 
            +
                            execution_time=execution_time,
         | 
| 372 | 
            +
                            metadata={"tool": "calculator", "operation": operation}
         | 
| 373 | 
            +
                        )
         | 
| 374 | 
            +
                        
         | 
| 375 | 
            +
                    except Exception as e:
         | 
| 376 | 
            +
                        execution_time = (datetime.now() - start_time).total_seconds()
         | 
| 377 | 
            +
                        self._update_metrics(False, execution_time)
         | 
| 378 | 
            +
                        self._metrics["last_error"] = str(e)
         | 
| 379 | 
            +
                        
         | 
| 380 | 
            +
                        return MCPToolResult(
         | 
| 381 | 
            +
                            success=False,
         | 
| 382 | 
            +
                            error=f"Calculator tool failed: {str(e)}",
         | 
| 383 | 
            +
                            execution_time=execution_time
         | 
| 384 | 
            +
                        )
         | 
| 385 | 
            +
             | 
| 386 | 
            +
             | 
| 387 | 
            +
            class SystemInfoToolAdapter(BaseToolAdapter):
         | 
| 388 | 
            +
                """
         | 
| 389 | 
            +
                Example system information tool adapter.
         | 
| 390 | 
            +
                
         | 
| 391 | 
            +
                Demonstrates async operations and system interaction.
         | 
| 392 | 
            +
                """
         | 
| 393 | 
            +
                
         | 
| 394 | 
            +
                def __init__(self):
         | 
| 395 | 
            +
                    """Initialize the system info tool."""
         | 
| 396 | 
            +
                    definition = MCPToolDefinition(
         | 
| 397 | 
            +
                        name="system_info",
         | 
| 398 | 
            +
                        description="Provides system information",
         | 
| 399 | 
            +
                        input_schema={
         | 
| 400 | 
            +
                            "type": "object",
         | 
| 401 | 
            +
                            "properties": {
         | 
| 402 | 
            +
                                "info_type": {
         | 
| 403 | 
            +
                                    "type": "string",
         | 
| 404 | 
            +
                                    "enum": ["platform", "memory", "cpu", "time"],
         | 
| 405 | 
            +
                                    "description": "Type of system information to retrieve"
         | 
| 406 | 
            +
                                }
         | 
| 407 | 
            +
                            },
         | 
| 408 | 
            +
                            "required": ["info_type"]
         | 
| 409 | 
            +
                        }
         | 
| 410 | 
            +
                    )
         | 
| 411 | 
            +
                    super().__init__(definition)
         | 
| 412 | 
            +
                
         | 
| 413 | 
            +
                async def invoke(self, invocation: MCPToolInvocation) -> MCPToolResult:
         | 
| 414 | 
            +
                    """
         | 
| 415 | 
            +
                    Invoke the system info tool.
         | 
| 416 | 
            +
                    
         | 
| 417 | 
            +
                    Args:
         | 
| 418 | 
            +
                        invocation: Tool invocation request
         | 
| 419 | 
            +
                        
         | 
| 420 | 
            +
                    Returns:
         | 
| 421 | 
            +
                        Tool execution result with system information
         | 
| 422 | 
            +
                    """
         | 
| 423 | 
            +
                    start_time = datetime.now()
         | 
| 424 | 
            +
                    
         | 
| 425 | 
            +
                    try:
         | 
| 426 | 
            +
                        import platform
         | 
| 427 | 
            +
                        import psutil
         | 
| 428 | 
            +
                        from datetime import datetime
         | 
| 429 | 
            +
                        
         | 
| 430 | 
            +
                        info_type = invocation.parameters["info_type"]
         | 
| 431 | 
            +
                        
         | 
| 432 | 
            +
                        if info_type == "platform":
         | 
| 433 | 
            +
                            result = {
         | 
| 434 | 
            +
                                "system": platform.system(),
         | 
| 435 | 
            +
                                "release": platform.release(),
         | 
| 436 | 
            +
                                "version": platform.version(),
         | 
| 437 | 
            +
                                "machine": platform.machine(),
         | 
| 438 | 
            +
                                "processor": platform.processor(),
         | 
| 439 | 
            +
                                "python_version": platform.python_version()
         | 
| 440 | 
            +
                            }
         | 
| 441 | 
            +
                        elif info_type == "memory":
         | 
| 442 | 
            +
                            mem = psutil.virtual_memory()
         | 
| 443 | 
            +
                            result = {
         | 
| 444 | 
            +
                                "total": mem.total,
         | 
| 445 | 
            +
                                "available": mem.available,
         | 
| 446 | 
            +
                                "percent": mem.percent,
         | 
| 447 | 
            +
                                "used": mem.used,
         | 
| 448 | 
            +
                                "free": mem.free
         | 
| 449 | 
            +
                            }
         | 
| 450 | 
            +
                        elif info_type == "cpu":
         | 
| 451 | 
            +
                            result = {
         | 
| 452 | 
            +
                                "count": psutil.cpu_count(),
         | 
| 453 | 
            +
                                "percent": psutil.cpu_percent(interval=0.1),
         | 
| 454 | 
            +
                                "freq": psutil.cpu_freq()._asdict() if psutil.cpu_freq() else None
         | 
| 455 | 
            +
                            }
         | 
| 456 | 
            +
                        elif info_type == "time":
         | 
| 457 | 
            +
                            result = {
         | 
| 458 | 
            +
                                "current": datetime.now().isoformat(),
         | 
| 459 | 
            +
                                "timestamp": datetime.now().timestamp(),
         | 
| 460 | 
            +
                                "timezone": str(datetime.now().astimezone().tzinfo)
         | 
| 461 | 
            +
                            }
         | 
| 462 | 
            +
                        else:
         | 
| 463 | 
            +
                            raise ValueError(f"Unknown info type: {info_type}")
         | 
| 464 | 
            +
                        
         | 
| 465 | 
            +
                        # Calculate execution time
         | 
| 466 | 
            +
                        execution_time = (datetime.now() - start_time).total_seconds()
         | 
| 467 | 
            +
                        
         | 
| 468 | 
            +
                        # Update metrics
         | 
| 469 | 
            +
                        self._update_metrics(True, execution_time)
         | 
| 470 | 
            +
                        
         | 
| 471 | 
            +
                        return MCPToolResult(
         | 
| 472 | 
            +
                            success=True,
         | 
| 473 | 
            +
                            data=result,
         | 
| 474 | 
            +
                            execution_time=execution_time,
         | 
| 475 | 
            +
                            metadata={"tool": "system_info", "info_type": info_type}
         | 
| 476 | 
            +
                        )
         | 
| 477 | 
            +
                        
         | 
| 478 | 
            +
                    except ImportError as e:
         | 
| 479 | 
            +
                        # Handle missing psutil dependency gracefully
         | 
| 480 | 
            +
                        execution_time = (datetime.now() - start_time).total_seconds()
         | 
| 481 | 
            +
                        self._update_metrics(False, execution_time)
         | 
| 482 | 
            +
                        
         | 
| 483 | 
            +
                        return MCPToolResult(
         | 
| 484 | 
            +
                            success=False,
         | 
| 485 | 
            +
                            error=f"System info tool requires psutil: {str(e)}",
         | 
| 486 | 
            +
                            execution_time=execution_time
         | 
| 487 | 
            +
                        )
         | 
| 488 | 
            +
                    except Exception as e:
         | 
| 489 | 
            +
                        execution_time = (datetime.now() - start_time).total_seconds()
         | 
| 490 | 
            +
                        self._update_metrics(False, execution_time)
         | 
| 491 | 
            +
                        self._metrics["last_error"] = str(e)
         | 
| 492 | 
            +
                        
         | 
| 493 | 
            +
                        return MCPToolResult(
         | 
| 494 | 
            +
                            success=False,
         | 
| 495 | 
            +
                            error=f"System info tool failed: {str(e)}",
         | 
| 496 | 
            +
                            execution_time=execution_time
         | 
| 497 | 
            +
                        )
         |