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,430 @@ | |
| 1 | 
            +
            """
         | 
| 2 | 
            +
            MCP Server Implementation
         | 
| 3 | 
            +
            =========================
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Main MCP server implementation using Anthropic's official MCP package.
         | 
| 6 | 
            +
            Handles stdio-based communication, request routing, and tool invocation.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            Part of ISS-0035: MCP Server Implementation - Core Server and Tool Registry
         | 
| 9 | 
            +
            """
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            import asyncio
         | 
| 12 | 
            +
            import json
         | 
| 13 | 
            +
            import sys
         | 
| 14 | 
            +
            from typing import Any, Dict, List, Optional, Callable, Set
         | 
| 15 | 
            +
            from datetime import datetime
         | 
| 16 | 
            +
            import traceback
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            try:
         | 
| 19 | 
            +
                # Import from the MCP package
         | 
| 20 | 
            +
                from mcp.server import Server, NotificationOptions
         | 
| 21 | 
            +
                from mcp.types import (
         | 
| 22 | 
            +
                    InitializeResult,
         | 
| 23 | 
            +
                    Tool,
         | 
| 24 | 
            +
                    TextContent,
         | 
| 25 | 
            +
                    ImageContent,
         | 
| 26 | 
            +
                    EmbeddedResource
         | 
| 27 | 
            +
                )
         | 
| 28 | 
            +
            except ImportError as e:
         | 
| 29 | 
            +
                # If specific imports fail, we'll create mock implementations
         | 
| 30 | 
            +
                print(f"Warning: MCP imports failed: {e}")
         | 
| 31 | 
            +
                Server = None
         | 
| 32 | 
            +
                NotificationOptions = None
         | 
| 33 | 
            +
                InitializeResult = None
         | 
| 34 | 
            +
                Tool = None
         | 
| 35 | 
            +
                TextContent = None
         | 
| 36 | 
            +
                ImageContent = None
         | 
| 37 | 
            +
                EmbeddedResource = None
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            from claude_mpm.services.mcp_gateway.core.interfaces import (
         | 
| 40 | 
            +
                IMCPServer,
         | 
| 41 | 
            +
                IMCPToolRegistry,
         | 
| 42 | 
            +
                IMCPCommunication,
         | 
| 43 | 
            +
                MCPToolInvocation,
         | 
| 44 | 
            +
                MCPToolResult,
         | 
| 45 | 
            +
            )
         | 
| 46 | 
            +
            from claude_mpm.services.mcp_gateway.core.base import BaseMCPService, MCPServiceState
         | 
| 47 | 
            +
             | 
| 48 | 
            +
             | 
| 49 | 
            +
            class MCPServer(BaseMCPService, IMCPServer):
         | 
| 50 | 
            +
                """
         | 
| 51 | 
            +
                Main MCP Server implementation using Anthropic's official MCP package.
         | 
| 52 | 
            +
                
         | 
| 53 | 
            +
                WHY: We use the official MCP package to ensure protocol compliance and
         | 
| 54 | 
            +
                compatibility with Claude Code. The stdio-based communication model allows
         | 
| 55 | 
            +
                seamless integration with Claude Desktop's MCP client.
         | 
| 56 | 
            +
                
         | 
| 57 | 
            +
                DESIGN DECISIONS:
         | 
| 58 | 
            +
                - Use asyncio for all I/O operations to handle concurrent requests efficiently
         | 
| 59 | 
            +
                - Maintain request handlers in a dictionary for extensibility
         | 
| 60 | 
            +
                - Implement comprehensive error handling to prevent server crashes
         | 
| 61 | 
            +
                - Use structured logging for debugging and monitoring
         | 
| 62 | 
            +
                """
         | 
| 63 | 
            +
                
         | 
| 64 | 
            +
                def __init__(self, server_name: str = "claude-mpm-mcp", version: str = "1.0.0"):
         | 
| 65 | 
            +
                    """
         | 
| 66 | 
            +
                    Initialize MCP Server.
         | 
| 67 | 
            +
                    
         | 
| 68 | 
            +
                    Args:
         | 
| 69 | 
            +
                        server_name: Name of the MCP server
         | 
| 70 | 
            +
                        version: Server version
         | 
| 71 | 
            +
                    """
         | 
| 72 | 
            +
                    super().__init__(f"MCPServer-{server_name}")
         | 
| 73 | 
            +
                    
         | 
| 74 | 
            +
                    # Server configuration
         | 
| 75 | 
            +
                    self.server_name = server_name
         | 
| 76 | 
            +
                    self.version = version
         | 
| 77 | 
            +
                    
         | 
| 78 | 
            +
                    # MCP Server instance from official package
         | 
| 79 | 
            +
                    self.mcp_server = Server(server_name)
         | 
| 80 | 
            +
                    
         | 
| 81 | 
            +
                    # Dependencies (injected via setters)
         | 
| 82 | 
            +
                    self._tool_registry: Optional[IMCPToolRegistry] = None
         | 
| 83 | 
            +
                    self._communication: Optional[IMCPCommunication] = None
         | 
| 84 | 
            +
                    
         | 
| 85 | 
            +
                    # Request handlers
         | 
| 86 | 
            +
                    self._handlers: Dict[str, Callable] = {}
         | 
| 87 | 
            +
                    
         | 
| 88 | 
            +
                    # Server capabilities
         | 
| 89 | 
            +
                    self._capabilities = {
         | 
| 90 | 
            +
                        "tools": {},
         | 
| 91 | 
            +
                        "prompts": {},
         | 
| 92 | 
            +
                        "resources": {},
         | 
| 93 | 
            +
                        "experimental": {}
         | 
| 94 | 
            +
                    }
         | 
| 95 | 
            +
                    
         | 
| 96 | 
            +
                    # Metrics
         | 
| 97 | 
            +
                    self._metrics = {
         | 
| 98 | 
            +
                        "requests_handled": 0,
         | 
| 99 | 
            +
                        "errors": 0,
         | 
| 100 | 
            +
                        "tool_invocations": 0,
         | 
| 101 | 
            +
                        "start_time": None,
         | 
| 102 | 
            +
                        "last_request_time": None
         | 
| 103 | 
            +
                    }
         | 
| 104 | 
            +
                    
         | 
| 105 | 
            +
                    # Running state
         | 
| 106 | 
            +
                    self._run_task: Optional[asyncio.Task] = None
         | 
| 107 | 
            +
                    self._shutdown_event = asyncio.Event()
         | 
| 108 | 
            +
                    
         | 
| 109 | 
            +
                    # Setup default handlers
         | 
| 110 | 
            +
                    self._setup_default_handlers()
         | 
| 111 | 
            +
                
         | 
| 112 | 
            +
                def _setup_default_handlers(self) -> None:
         | 
| 113 | 
            +
                    """
         | 
| 114 | 
            +
                    Setup default MCP protocol handlers.
         | 
| 115 | 
            +
                    
         | 
| 116 | 
            +
                    WHY: The MCP protocol requires specific handlers for initialization,
         | 
| 117 | 
            +
                    tool discovery, and tool invocation. We set these up to ensure
         | 
| 118 | 
            +
                    protocol compliance.
         | 
| 119 | 
            +
                    """
         | 
| 120 | 
            +
                    # Initialize handler
         | 
| 121 | 
            +
                    @self.mcp_server.list_tools()
         | 
| 122 | 
            +
                    async def handle_list_tools() -> List[Tool]:
         | 
| 123 | 
            +
                        """Handle tools/list request."""
         | 
| 124 | 
            +
                        self.log_info("Handling tools/list request")
         | 
| 125 | 
            +
                        
         | 
| 126 | 
            +
                        if not self._tool_registry:
         | 
| 127 | 
            +
                            self.log_warning("No tool registry available")
         | 
| 128 | 
            +
                            return []
         | 
| 129 | 
            +
                        
         | 
| 130 | 
            +
                        tools = []
         | 
| 131 | 
            +
                        for tool_def in self._tool_registry.list_tools():
         | 
| 132 | 
            +
                            tool = Tool(
         | 
| 133 | 
            +
                                name=tool_def.name,
         | 
| 134 | 
            +
                                description=tool_def.description,
         | 
| 135 | 
            +
                                inputSchema=tool_def.input_schema
         | 
| 136 | 
            +
                            )
         | 
| 137 | 
            +
                            tools.append(tool)
         | 
| 138 | 
            +
                        
         | 
| 139 | 
            +
                        self.log_info(f"Returning {len(tools)} tools")
         | 
| 140 | 
            +
                        return tools
         | 
| 141 | 
            +
                    
         | 
| 142 | 
            +
                    @self.mcp_server.call_tool()
         | 
| 143 | 
            +
                    async def handle_call_tool(name: str, arguments: Dict[str, Any]) -> List[TextContent | ImageContent | EmbeddedResource]:
         | 
| 144 | 
            +
                        """Handle tools/call request."""
         | 
| 145 | 
            +
                        self.log_info(f"Handling tools/call request for tool: {name}")
         | 
| 146 | 
            +
                        
         | 
| 147 | 
            +
                        if not self._tool_registry:
         | 
| 148 | 
            +
                            error_msg = "No tool registry available"
         | 
| 149 | 
            +
                            self.log_error(error_msg)
         | 
| 150 | 
            +
                            return [TextContent(type="text", text=f"Error: {error_msg}")]
         | 
| 151 | 
            +
                        
         | 
| 152 | 
            +
                        # Create invocation request
         | 
| 153 | 
            +
                        invocation = MCPToolInvocation(
         | 
| 154 | 
            +
                            tool_name=name,
         | 
| 155 | 
            +
                            parameters=arguments,
         | 
| 156 | 
            +
                            request_id=f"req_{datetime.now().timestamp()}"
         | 
| 157 | 
            +
                        )
         | 
| 158 | 
            +
                        
         | 
| 159 | 
            +
                        try:
         | 
| 160 | 
            +
                            # Invoke tool through registry
         | 
| 161 | 
            +
                            result = await self._tool_registry.invoke_tool(invocation)
         | 
| 162 | 
            +
                            
         | 
| 163 | 
            +
                            # Update metrics
         | 
| 164 | 
            +
                            self._metrics["tool_invocations"] += 1
         | 
| 165 | 
            +
                            
         | 
| 166 | 
            +
                            # Log invocation
         | 
| 167 | 
            +
                            self.log_tool_invocation(name, result.success, result.execution_time)
         | 
| 168 | 
            +
                            
         | 
| 169 | 
            +
                            if result.success:
         | 
| 170 | 
            +
                                # Return successful result
         | 
| 171 | 
            +
                                if isinstance(result.data, str):
         | 
| 172 | 
            +
                                    return [TextContent(type="text", text=result.data)]
         | 
| 173 | 
            +
                                else:
         | 
| 174 | 
            +
                                    return [TextContent(type="text", text=json.dumps(result.data, indent=2))]
         | 
| 175 | 
            +
                            else:
         | 
| 176 | 
            +
                                # Return error
         | 
| 177 | 
            +
                                return [TextContent(type="text", text=f"Error: {result.error}")]
         | 
| 178 | 
            +
                                
         | 
| 179 | 
            +
                        except Exception as e:
         | 
| 180 | 
            +
                            error_msg = f"Failed to invoke tool {name}: {str(e)}"
         | 
| 181 | 
            +
                            self.log_error(error_msg)
         | 
| 182 | 
            +
                            self._metrics["errors"] += 1
         | 
| 183 | 
            +
                            return [TextContent(type="text", text=f"Error: {error_msg}")]
         | 
| 184 | 
            +
                
         | 
| 185 | 
            +
                def set_tool_registry(self, registry: IMCPToolRegistry) -> None:
         | 
| 186 | 
            +
                    """
         | 
| 187 | 
            +
                    Set the tool registry for the server.
         | 
| 188 | 
            +
                    
         | 
| 189 | 
            +
                    Args:
         | 
| 190 | 
            +
                        registry: Tool registry to use
         | 
| 191 | 
            +
                    """
         | 
| 192 | 
            +
                    self._tool_registry = registry
         | 
| 193 | 
            +
                    self.log_info("Tool registry set")
         | 
| 194 | 
            +
                
         | 
| 195 | 
            +
                def set_communication(self, communication: IMCPCommunication) -> None:
         | 
| 196 | 
            +
                    """
         | 
| 197 | 
            +
                    Set the communication handler.
         | 
| 198 | 
            +
                    
         | 
| 199 | 
            +
                    Args:
         | 
| 200 | 
            +
                        communication: Communication handler to use
         | 
| 201 | 
            +
                    """
         | 
| 202 | 
            +
                    self._communication = communication
         | 
| 203 | 
            +
                    self.log_info("Communication handler set")
         | 
| 204 | 
            +
                
         | 
| 205 | 
            +
                async def _do_initialize(self) -> bool:
         | 
| 206 | 
            +
                    """
         | 
| 207 | 
            +
                    Perform server initialization.
         | 
| 208 | 
            +
                    
         | 
| 209 | 
            +
                    Returns:
         | 
| 210 | 
            +
                        True if initialization successful
         | 
| 211 | 
            +
                    """
         | 
| 212 | 
            +
                    try:
         | 
| 213 | 
            +
                        self.log_info("Initializing MCP server components")
         | 
| 214 | 
            +
                        
         | 
| 215 | 
            +
                        # Validate dependencies
         | 
| 216 | 
            +
                        if not self._tool_registry:
         | 
| 217 | 
            +
                            self.log_warning("No tool registry set - server will have no tools")
         | 
| 218 | 
            +
                        
         | 
| 219 | 
            +
                        # Initialize metrics
         | 
| 220 | 
            +
                        self._metrics["start_time"] = datetime.now().isoformat()
         | 
| 221 | 
            +
                        
         | 
| 222 | 
            +
                        # Update capabilities based on registry
         | 
| 223 | 
            +
                        if self._tool_registry:
         | 
| 224 | 
            +
                            tools = self._tool_registry.list_tools()
         | 
| 225 | 
            +
                            self._capabilities["tools"]["available"] = len(tools)
         | 
| 226 | 
            +
                            self._capabilities["tools"]["names"] = [t.name for t in tools]
         | 
| 227 | 
            +
                        
         | 
| 228 | 
            +
                        self.log_info("MCP server initialization complete")
         | 
| 229 | 
            +
                        return True
         | 
| 230 | 
            +
                        
         | 
| 231 | 
            +
                    except Exception as e:
         | 
| 232 | 
            +
                        self.log_error(f"Failed to initialize MCP server: {e}")
         | 
| 233 | 
            +
                        return False
         | 
| 234 | 
            +
                
         | 
| 235 | 
            +
                async def _do_start(self) -> bool:
         | 
| 236 | 
            +
                    """
         | 
| 237 | 
            +
                    Start the MCP server.
         | 
| 238 | 
            +
                    
         | 
| 239 | 
            +
                    Returns:
         | 
| 240 | 
            +
                        True if startup successful
         | 
| 241 | 
            +
                    """
         | 
| 242 | 
            +
                    try:
         | 
| 243 | 
            +
                        self.log_info("Starting MCP server")
         | 
| 244 | 
            +
                        
         | 
| 245 | 
            +
                        # Clear shutdown event
         | 
| 246 | 
            +
                        self._shutdown_event.clear()
         | 
| 247 | 
            +
                        
         | 
| 248 | 
            +
                        # Start the run task
         | 
| 249 | 
            +
                        self._run_task = asyncio.create_task(self.run())
         | 
| 250 | 
            +
                        
         | 
| 251 | 
            +
                        self.log_info("MCP server started successfully")
         | 
| 252 | 
            +
                        return True
         | 
| 253 | 
            +
                        
         | 
| 254 | 
            +
                    except Exception as e:
         | 
| 255 | 
            +
                        self.log_error(f"Failed to start MCP server: {e}")
         | 
| 256 | 
            +
                        return False
         | 
| 257 | 
            +
                
         | 
| 258 | 
            +
                async def _do_shutdown(self) -> None:
         | 
| 259 | 
            +
                    """
         | 
| 260 | 
            +
                    Shutdown the MCP server gracefully.
         | 
| 261 | 
            +
                    """
         | 
| 262 | 
            +
                    self.log_info("Shutting down MCP server")
         | 
| 263 | 
            +
                    
         | 
| 264 | 
            +
                    # Signal shutdown
         | 
| 265 | 
            +
                    self._shutdown_event.set()
         | 
| 266 | 
            +
                    
         | 
| 267 | 
            +
                    # Cancel run task if active
         | 
| 268 | 
            +
                    if self._run_task and not self._run_task.done():
         | 
| 269 | 
            +
                        self._run_task.cancel()
         | 
| 270 | 
            +
                        try:
         | 
| 271 | 
            +
                            await self._run_task
         | 
| 272 | 
            +
                        except asyncio.CancelledError:
         | 
| 273 | 
            +
                            pass
         | 
| 274 | 
            +
                    
         | 
| 275 | 
            +
                    # Clean up resources
         | 
| 276 | 
            +
                    if self._tool_registry:
         | 
| 277 | 
            +
                        self.log_info("Cleaning up tool registry")
         | 
| 278 | 
            +
                        # Tool registry cleanup if needed
         | 
| 279 | 
            +
                    
         | 
| 280 | 
            +
                    self.log_info("MCP server shutdown complete")
         | 
| 281 | 
            +
                
         | 
| 282 | 
            +
                async def handle_request(self, request: Dict[str, Any]) -> Dict[str, Any]:
         | 
| 283 | 
            +
                    """
         | 
| 284 | 
            +
                    Handle an MCP request.
         | 
| 285 | 
            +
                    
         | 
| 286 | 
            +
                    This method routes requests to appropriate handlers based on the method.
         | 
| 287 | 
            +
                    
         | 
| 288 | 
            +
                    Args:
         | 
| 289 | 
            +
                        request: MCP request message
         | 
| 290 | 
            +
                        
         | 
| 291 | 
            +
                    Returns:
         | 
| 292 | 
            +
                        Response message
         | 
| 293 | 
            +
                    """
         | 
| 294 | 
            +
                    try:
         | 
| 295 | 
            +
                        # Update metrics
         | 
| 296 | 
            +
                        self._metrics["requests_handled"] += 1
         | 
| 297 | 
            +
                        self._metrics["last_request_time"] = datetime.now().isoformat()
         | 
| 298 | 
            +
                        
         | 
| 299 | 
            +
                        # Extract request details
         | 
| 300 | 
            +
                        method = request.get("method", "")
         | 
| 301 | 
            +
                        params = request.get("params", {})
         | 
| 302 | 
            +
                        request_id = request.get("id")
         | 
| 303 | 
            +
                        
         | 
| 304 | 
            +
                        self.log_debug(f"Handling request: {method}")
         | 
| 305 | 
            +
                        
         | 
| 306 | 
            +
                        # Check for custom handler
         | 
| 307 | 
            +
                        if method in self._handlers:
         | 
| 308 | 
            +
                            handler = self._handlers[method]
         | 
| 309 | 
            +
                            result = await handler(params)
         | 
| 310 | 
            +
                            
         | 
| 311 | 
            +
                            # Build response
         | 
| 312 | 
            +
                            response = {
         | 
| 313 | 
            +
                                "jsonrpc": "2.0",
         | 
| 314 | 
            +
                                "id": request_id,
         | 
| 315 | 
            +
                                "result": result
         | 
| 316 | 
            +
                            }
         | 
| 317 | 
            +
                        else:
         | 
| 318 | 
            +
                            # Unknown method
         | 
| 319 | 
            +
                            self.log_warning(f"Unknown method: {method}")
         | 
| 320 | 
            +
                            response = {
         | 
| 321 | 
            +
                                "jsonrpc": "2.0",
         | 
| 322 | 
            +
                                "id": request_id,
         | 
| 323 | 
            +
                                "error": {
         | 
| 324 | 
            +
                                    "code": -32601,
         | 
| 325 | 
            +
                                    "message": f"Method not found: {method}"
         | 
| 326 | 
            +
                                }
         | 
| 327 | 
            +
                            }
         | 
| 328 | 
            +
                        
         | 
| 329 | 
            +
                        return response
         | 
| 330 | 
            +
                        
         | 
| 331 | 
            +
                    except Exception as e:
         | 
| 332 | 
            +
                        self.log_error(f"Error handling request: {e}")
         | 
| 333 | 
            +
                        self._metrics["errors"] += 1
         | 
| 334 | 
            +
                        
         | 
| 335 | 
            +
                        return {
         | 
| 336 | 
            +
                            "jsonrpc": "2.0",
         | 
| 337 | 
            +
                            "id": request.get("id"),
         | 
| 338 | 
            +
                            "error": {
         | 
| 339 | 
            +
                                "code": -32603,
         | 
| 340 | 
            +
                                "message": f"Internal error: {str(e)}"
         | 
| 341 | 
            +
                            }
         | 
| 342 | 
            +
                        }
         | 
| 343 | 
            +
                
         | 
| 344 | 
            +
                async def run(self) -> None:
         | 
| 345 | 
            +
                    """
         | 
| 346 | 
            +
                    Run the MCP server main loop.
         | 
| 347 | 
            +
                    
         | 
| 348 | 
            +
                    This method uses the official MCP Server's stdio-based communication
         | 
| 349 | 
            +
                    to handle incoming requests from Claude Code.
         | 
| 350 | 
            +
                    
         | 
| 351 | 
            +
                    WHY: We use stdio (stdin/stdout) as it's the standard communication
         | 
| 352 | 
            +
                    method for MCP servers in Claude Desktop. This ensures compatibility
         | 
| 353 | 
            +
                    and allows the server to be launched as a subprocess.
         | 
| 354 | 
            +
                    """
         | 
| 355 | 
            +
                    try:
         | 
| 356 | 
            +
                        self.log_info("Starting MCP server main loop")
         | 
| 357 | 
            +
                        
         | 
| 358 | 
            +
                        # Create initialization options
         | 
| 359 | 
            +
                        init_options = InitializeResult(
         | 
| 360 | 
            +
                            protocolVersion="2024-11-05",
         | 
| 361 | 
            +
                            capabilities=self.get_capabilities(),
         | 
| 362 | 
            +
                            serverInfo={
         | 
| 363 | 
            +
                                "name": self.server_name,
         | 
| 364 | 
            +
                                "version": self.version
         | 
| 365 | 
            +
                            }
         | 
| 366 | 
            +
                        )
         | 
| 367 | 
            +
                        
         | 
| 368 | 
            +
                        # Run the MCP server with stdio transport
         | 
| 369 | 
            +
                        async with self.mcp_server.run(
         | 
| 370 | 
            +
                            transport="stdio",
         | 
| 371 | 
            +
                            init_options=init_options
         | 
| 372 | 
            +
                        ) as connection:
         | 
| 373 | 
            +
                            self.log_info(f"MCP server running with connection: {connection}")
         | 
| 374 | 
            +
                            
         | 
| 375 | 
            +
                            # Wait for shutdown signal
         | 
| 376 | 
            +
                            await self._shutdown_event.wait()
         | 
| 377 | 
            +
                            
         | 
| 378 | 
            +
                        self.log_info("MCP server main loop ended")
         | 
| 379 | 
            +
                        
         | 
| 380 | 
            +
                    except Exception as e:
         | 
| 381 | 
            +
                        self.log_error(f"Error in MCP server main loop: {e}")
         | 
| 382 | 
            +
                        self.log_error(f"Traceback: {traceback.format_exc()}")
         | 
| 383 | 
            +
                        self._metrics["errors"] += 1
         | 
| 384 | 
            +
                        raise
         | 
| 385 | 
            +
                
         | 
| 386 | 
            +
                def register_handler(self, method: str, handler: Callable) -> None:
         | 
| 387 | 
            +
                    """
         | 
| 388 | 
            +
                    Register a custom request handler.
         | 
| 389 | 
            +
                    
         | 
| 390 | 
            +
                    Args:
         | 
| 391 | 
            +
                        method: Method name to handle
         | 
| 392 | 
            +
                        handler: Handler function
         | 
| 393 | 
            +
                    """
         | 
| 394 | 
            +
                    self._handlers[method] = handler
         | 
| 395 | 
            +
                    self.log_info(f"Registered handler for method: {method}")
         | 
| 396 | 
            +
                
         | 
| 397 | 
            +
                def get_capabilities(self) -> Dict[str, Any]:
         | 
| 398 | 
            +
                    """
         | 
| 399 | 
            +
                    Get server capabilities.
         | 
| 400 | 
            +
                    
         | 
| 401 | 
            +
                    Returns:
         | 
| 402 | 
            +
                        Dictionary of server capabilities formatted for MCP protocol
         | 
| 403 | 
            +
                    """
         | 
| 404 | 
            +
                    capabilities = {}
         | 
| 405 | 
            +
                    
         | 
| 406 | 
            +
                    # Add tool capabilities if registry is available
         | 
| 407 | 
            +
                    if self._tool_registry:
         | 
| 408 | 
            +
                        capabilities["tools"] = {}
         | 
| 409 | 
            +
                    
         | 
| 410 | 
            +
                    # Add experimental features
         | 
| 411 | 
            +
                    capabilities["experimental"] = {}
         | 
| 412 | 
            +
                    
         | 
| 413 | 
            +
                    return capabilities
         | 
| 414 | 
            +
                
         | 
| 415 | 
            +
                def get_metrics(self) -> Dict[str, Any]:
         | 
| 416 | 
            +
                    """
         | 
| 417 | 
            +
                    Get server metrics.
         | 
| 418 | 
            +
                    
         | 
| 419 | 
            +
                    Returns:
         | 
| 420 | 
            +
                        Server metrics dictionary
         | 
| 421 | 
            +
                    """
         | 
| 422 | 
            +
                    return self._metrics.copy()
         | 
| 423 | 
            +
                
         | 
| 424 | 
            +
                async def stop(self) -> None:
         | 
| 425 | 
            +
                    """
         | 
| 426 | 
            +
                    Stop the MCP service gracefully.
         | 
| 427 | 
            +
                    
         | 
| 428 | 
            +
                    This implements the IMCPLifecycle interface method.
         | 
| 429 | 
            +
                    """
         | 
| 430 | 
            +
                    await self.shutdown()
         |