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.
Files changed (44) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/base_agent.json +1 -1
  3. claude_mpm/cli/__init__.py +3 -1
  4. claude_mpm/cli/commands/__init__.py +3 -1
  5. claude_mpm/cli/commands/cleanup.py +21 -1
  6. claude_mpm/cli/commands/mcp.py +821 -0
  7. claude_mpm/cli/parser.py +148 -1
  8. claude_mpm/config/memory_guardian_config.py +325 -0
  9. claude_mpm/constants.py +13 -0
  10. claude_mpm/hooks/claude_hooks/hook_handler.py +76 -19
  11. claude_mpm/models/state_models.py +433 -0
  12. claude_mpm/services/communication/__init__.py +2 -2
  13. claude_mpm/services/communication/socketio.py +18 -16
  14. claude_mpm/services/infrastructure/__init__.py +4 -1
  15. claude_mpm/services/infrastructure/logging.py +3 -3
  16. claude_mpm/services/infrastructure/memory_guardian.py +770 -0
  17. claude_mpm/services/mcp_gateway/__init__.py +28 -12
  18. claude_mpm/services/mcp_gateway/main.py +326 -0
  19. claude_mpm/services/mcp_gateway/registry/__init__.py +6 -3
  20. claude_mpm/services/mcp_gateway/registry/service_registry.py +397 -0
  21. claude_mpm/services/mcp_gateway/registry/tool_registry.py +477 -0
  22. claude_mpm/services/mcp_gateway/server/__init__.py +9 -3
  23. claude_mpm/services/mcp_gateway/server/mcp_server.py +430 -0
  24. claude_mpm/services/mcp_gateway/server/mcp_server_simple.py +444 -0
  25. claude_mpm/services/mcp_gateway/server/stdio_handler.py +373 -0
  26. claude_mpm/services/mcp_gateway/tools/__init__.py +16 -3
  27. claude_mpm/services/mcp_gateway/tools/base_adapter.py +497 -0
  28. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +729 -0
  29. claude_mpm/services/mcp_gateway/tools/hello_world.py +551 -0
  30. claude_mpm/utils/file_utils.py +293 -0
  31. claude_mpm/utils/platform_memory.py +524 -0
  32. claude_mpm/utils/subprocess_utils.py +305 -0
  33. {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/METADATA +3 -1
  34. {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/RECORD +39 -28
  35. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
  36. claude_mpm/agents/templates/.claude-mpm/memories/engineer_agent.md +0 -39
  37. claude_mpm/agents/templates/.claude-mpm/memories/qa_agent.md +0 -38
  38. claude_mpm/agents/templates/.claude-mpm/memories/research_agent.md +0 -39
  39. claude_mpm/agents/templates/.claude-mpm/memories/version_control_agent.md +0 -38
  40. /claude_mpm/agents/templates/{research_memory_efficient.json → backup/research_memory_efficient.json} +0 -0
  41. {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/WHEEL +0 -0
  42. {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/entry_points.txt +0 -0
  43. {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/licenses/LICENSE +0 -0
  44. {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,397 @@
1
+ """
2
+ MCP Service Registry Implementation
3
+ ====================================
4
+
5
+ Service registry for MCP Gateway components.
6
+ Provides service discovery, registration, and dependency resolution.
7
+
8
+ Part of ISS-0035: MCP Server Implementation - Core Server and Tool Registry
9
+ """
10
+
11
+ from typing import Dict, Any, Optional, Type, TypeVar, List
12
+ from threading import RLock
13
+ import logging
14
+
15
+ from claude_mpm.services.mcp_gateway.core.interfaces import (
16
+ IMCPServer,
17
+ IMCPToolRegistry,
18
+ IMCPCommunication,
19
+ IMCPConfiguration,
20
+ IMCPToolAdapter,
21
+ IMCPLifecycle
22
+ )
23
+ from claude_mpm.services.mcp_gateway.core.base import BaseMCPService
24
+ from claude_mpm.core.logger import get_logger
25
+
26
+
27
+ T = TypeVar('T')
28
+
29
+
30
+ class MCPServiceRegistry:
31
+ """
32
+ Service registry for MCP Gateway components.
33
+
34
+ WHY: We need a centralized registry for managing MCP services,
35
+ enabling dependency injection and service discovery patterns.
36
+ This aligns with the claude-mpm service-oriented architecture.
37
+
38
+ DESIGN DECISIONS:
39
+ - Use interface-based registration for loose coupling
40
+ - Support singleton and transient service lifetimes
41
+ - Provide thread-safe service resolution
42
+ - Enable service health monitoring
43
+ - Support service dependency chains
44
+ """
45
+
46
+ def __init__(self):
47
+ """Initialize the service registry."""
48
+ self.logger = get_logger(self.__class__.__name__)
49
+
50
+ # Thread safety
51
+ self._lock = RLock()
52
+
53
+ # Service storage
54
+ self._services: Dict[Type, Any] = {}
55
+ self._singletons: Dict[Type, Any] = {}
56
+ self._factories: Dict[Type, callable] = {}
57
+
58
+ # Service metadata
59
+ self._metadata: Dict[Type, Dict[str, Any]] = {}
60
+
61
+ # Service health tracking
62
+ self._health_checks: Dict[Type, callable] = {}
63
+
64
+ def register(
65
+ self,
66
+ interface: Type[T],
67
+ implementation: Optional[Type[T]] = None,
68
+ factory: Optional[callable] = None,
69
+ singleton: bool = True,
70
+ metadata: Optional[Dict[str, Any]] = None
71
+ ) -> None:
72
+ """
73
+ Register a service in the registry.
74
+
75
+ Args:
76
+ interface: Service interface type
77
+ implementation: Service implementation class
78
+ factory: Factory function to create service instances
79
+ singleton: Whether to create a single instance
80
+ metadata: Additional service metadata
81
+
82
+ WHY: We support both direct implementation and factory patterns
83
+ to provide flexibility in service instantiation. Singleton support
84
+ enables efficient resource management.
85
+ """
86
+ with self._lock:
87
+ if implementation is None and factory is None:
88
+ raise ValueError("Either implementation or factory must be provided")
89
+
90
+ if implementation and factory:
91
+ raise ValueError("Cannot provide both implementation and factory")
92
+
93
+ self.logger.info(f"Registering service: {interface.__name__}")
94
+
95
+ # Store service registration
96
+ if implementation:
97
+ self._services[interface] = implementation
98
+ elif factory:
99
+ self._factories[interface] = factory
100
+
101
+ # Store metadata
102
+ if metadata:
103
+ self._metadata[interface] = metadata
104
+ else:
105
+ self._metadata[interface] = {"singleton": singleton}
106
+
107
+ self._metadata[interface]["singleton"] = singleton
108
+
109
+ def register_instance(self, interface: Type[T], instance: T) -> None:
110
+ """
111
+ Register a pre-created service instance.
112
+
113
+ Args:
114
+ interface: Service interface type
115
+ instance: Service instance
116
+
117
+ WHY: Sometimes we need to register pre-configured instances,
118
+ especially for services with complex initialization.
119
+ """
120
+ with self._lock:
121
+ self.logger.info(f"Registering instance: {interface.__name__}")
122
+ self._singletons[interface] = instance
123
+ self._metadata[interface] = {"singleton": True, "instance": True}
124
+
125
+ def resolve(self, interface: Type[T]) -> Optional[T]:
126
+ """
127
+ Resolve a service from the registry.
128
+
129
+ Args:
130
+ interface: Service interface type
131
+
132
+ Returns:
133
+ Service instance or None if not found
134
+
135
+ WHY: We use lazy instantiation for non-singleton services
136
+ and cache singletons for performance.
137
+ """
138
+ with self._lock:
139
+ # Check for existing singleton
140
+ if interface in self._singletons:
141
+ return self._singletons[interface]
142
+
143
+ # Check for factory
144
+ if interface in self._factories:
145
+ factory = self._factories[interface]
146
+ instance = factory()
147
+
148
+ # Cache if singleton
149
+ if self._metadata.get(interface, {}).get("singleton", False):
150
+ self._singletons[interface] = instance
151
+
152
+ return instance
153
+
154
+ # Check for implementation class
155
+ if interface in self._services:
156
+ implementation = self._services[interface]
157
+
158
+ # Create instance
159
+ try:
160
+ instance = implementation()
161
+
162
+ # Cache if singleton
163
+ if self._metadata.get(interface, {}).get("singleton", True):
164
+ self._singletons[interface] = instance
165
+
166
+ return instance
167
+
168
+ except Exception as e:
169
+ self.logger.error(f"Failed to create service {interface.__name__}: {e}")
170
+ return None
171
+
172
+ self.logger.warning(f"Service not found: {interface.__name__}")
173
+ return None
174
+
175
+ def resolve_all(self, interface: Type[T]) -> List[T]:
176
+ """
177
+ Resolve all services implementing an interface.
178
+
179
+ Args:
180
+ interface: Service interface type
181
+
182
+ Returns:
183
+ List of service instances
184
+
185
+ WHY: Some scenarios require multiple implementations of
186
+ the same interface (e.g., multiple tool adapters).
187
+ """
188
+ with self._lock:
189
+ instances = []
190
+
191
+ # Add singleton if exists
192
+ if interface in self._singletons:
193
+ instances.append(self._singletons[interface])
194
+
195
+ # Note: In a full implementation, we'd track multiple
196
+ # registrations per interface
197
+
198
+ return instances
199
+
200
+ def unregister(self, interface: Type) -> bool:
201
+ """
202
+ Unregister a service from the registry.
203
+
204
+ Args:
205
+ interface: Service interface type
206
+
207
+ Returns:
208
+ True if unregistration successful
209
+ """
210
+ with self._lock:
211
+ found = False
212
+
213
+ if interface in self._services:
214
+ del self._services[interface]
215
+ found = True
216
+
217
+ if interface in self._factories:
218
+ del self._factories[interface]
219
+ found = True
220
+
221
+ if interface in self._singletons:
222
+ # Shutdown if it's a lifecycle service
223
+ instance = self._singletons[interface]
224
+ if isinstance(instance, IMCPLifecycle):
225
+ try:
226
+ import asyncio
227
+ asyncio.create_task(instance.stop())
228
+ except Exception as e:
229
+ self.logger.warning(f"Error stopping service {interface.__name__}: {e}")
230
+
231
+ del self._singletons[interface]
232
+ found = True
233
+
234
+ if interface in self._metadata:
235
+ del self._metadata[interface]
236
+
237
+ if interface in self._health_checks:
238
+ del self._health_checks[interface]
239
+
240
+ if found:
241
+ self.logger.info(f"Unregistered service: {interface.__name__}")
242
+
243
+ return found
244
+
245
+ def register_health_check(self, interface: Type, health_check: callable) -> None:
246
+ """
247
+ Register a health check for a service.
248
+
249
+ Args:
250
+ interface: Service interface type
251
+ health_check: Health check function
252
+ """
253
+ with self._lock:
254
+ self._health_checks[interface] = health_check
255
+
256
+ async def check_health(self) -> Dict[str, Any]:
257
+ """
258
+ Check health of all registered services.
259
+
260
+ Returns:
261
+ Dictionary of service health statuses
262
+ """
263
+ health_status = {}
264
+
265
+ with self._lock:
266
+ # Check singleton services
267
+ for interface, instance in self._singletons.items():
268
+ service_name = interface.__name__
269
+
270
+ try:
271
+ # Use custom health check if available
272
+ if interface in self._health_checks:
273
+ health_check = self._health_checks[interface]
274
+ if asyncio.iscoroutinefunction(health_check):
275
+ health = await health_check(instance)
276
+ else:
277
+ health = health_check(instance)
278
+ health_status[service_name] = health
279
+
280
+ # Use built-in health check for lifecycle services
281
+ elif isinstance(instance, IMCPLifecycle):
282
+ health_status[service_name] = {
283
+ "healthy": instance.is_healthy(),
284
+ "state": instance.get_state(),
285
+ "details": instance.get_health_status()
286
+ }
287
+
288
+ # Basic health check
289
+ else:
290
+ health_status[service_name] = {
291
+ "healthy": True,
292
+ "state": "unknown"
293
+ }
294
+
295
+ except Exception as e:
296
+ health_status[service_name] = {
297
+ "healthy": False,
298
+ "error": str(e)
299
+ }
300
+
301
+ return health_status
302
+
303
+ def get_metadata(self, interface: Type) -> Optional[Dict[str, Any]]:
304
+ """
305
+ Get metadata for a service.
306
+
307
+ Args:
308
+ interface: Service interface type
309
+
310
+ Returns:
311
+ Service metadata or None
312
+ """
313
+ with self._lock:
314
+ return self._metadata.get(interface)
315
+
316
+ def list_services(self) -> List[str]:
317
+ """
318
+ List all registered services.
319
+
320
+ Returns:
321
+ List of service interface names
322
+ """
323
+ with self._lock:
324
+ services = set()
325
+ services.update(interface.__name__ for interface in self._services.keys())
326
+ services.update(interface.__name__ for interface in self._factories.keys())
327
+ services.update(interface.__name__ for interface in self._singletons.keys())
328
+ return sorted(list(services))
329
+
330
+ def clear(self) -> None:
331
+ """Clear all service registrations."""
332
+ with self._lock:
333
+ # Shutdown lifecycle services
334
+ for instance in self._singletons.values():
335
+ if isinstance(instance, IMCPLifecycle):
336
+ try:
337
+ import asyncio
338
+ asyncio.create_task(instance.stop())
339
+ except Exception as e:
340
+ self.logger.warning(f"Error stopping service: {e}")
341
+
342
+ # Clear all registrations
343
+ self._services.clear()
344
+ self._factories.clear()
345
+ self._singletons.clear()
346
+ self._metadata.clear()
347
+ self._health_checks.clear()
348
+
349
+ self.logger.info("Service registry cleared")
350
+
351
+
352
+ # Global service registry instance
353
+ _service_registry: Optional[MCPServiceRegistry] = None
354
+
355
+
356
+ def get_service_registry() -> MCPServiceRegistry:
357
+ """
358
+ Get the global MCP service registry instance.
359
+
360
+ Returns:
361
+ Service registry instance
362
+ """
363
+ global _service_registry
364
+ if _service_registry is None:
365
+ _service_registry = MCPServiceRegistry()
366
+ return _service_registry
367
+
368
+
369
+ def register_mcp_services() -> None:
370
+ """
371
+ Register all default MCP services.
372
+
373
+ This function sets up the standard MCP service configuration.
374
+ """
375
+ registry = get_service_registry()
376
+
377
+ # Register core services
378
+ # Try to use the official MCP server, fall back to simple implementation
379
+ try:
380
+ from claude_mpm.services.mcp_gateway.server.mcp_server import MCPServer
381
+ registry.register(IMCPServer, MCPServer, singleton=True)
382
+ except ImportError:
383
+ from claude_mpm.services.mcp_gateway.server.mcp_server_simple import SimpleMCPServer
384
+ registry.register(IMCPServer, SimpleMCPServer, singleton=True)
385
+
386
+ from claude_mpm.services.mcp_gateway.server.stdio_handler import StdioHandler
387
+ from claude_mpm.services.mcp_gateway.registry.tool_registry import ToolRegistry
388
+ from claude_mpm.services.mcp_gateway.config.configuration import MCPConfiguration
389
+
390
+ registry.register(IMCPCommunication, StdioHandler, singleton=True)
391
+ registry.register(IMCPToolRegistry, ToolRegistry, singleton=True)
392
+ registry.register(IMCPConfiguration, MCPConfiguration, singleton=True)
393
+
394
+ logging.info("MCP services registered")
395
+
396
+
397
+ import asyncio