claude-mpm 4.3.11__py3-none-any.whl → 4.3.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/PM_INSTRUCTIONS.md +390 -28
  3. claude_mpm/agents/templates/data_engineer.json +39 -14
  4. claude_mpm/agents/templates/research.json +20 -8
  5. claude_mpm/agents/templates/web_qa.json +25 -10
  6. claude_mpm/cli/__init__.py +1 -0
  7. claude_mpm/cli/commands/agent_manager.py +3 -3
  8. claude_mpm/cli/commands/agents.py +2 -2
  9. claude_mpm/cli/commands/aggregate.py +1 -1
  10. claude_mpm/cli/commands/config.py +2 -2
  11. claude_mpm/cli/commands/configure.py +5 -5
  12. claude_mpm/cli/commands/configure_tui.py +7 -7
  13. claude_mpm/cli/commands/dashboard.py +1 -1
  14. claude_mpm/cli/commands/debug.py +5 -5
  15. claude_mpm/cli/commands/mcp.py +1 -1
  16. claude_mpm/cli/commands/mcp_command_router.py +12 -1
  17. claude_mpm/cli/commands/mcp_config.py +154 -0
  18. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  19. claude_mpm/cli/commands/mcp_install_commands.py +93 -24
  20. claude_mpm/cli/commands/mcp_setup_external.py +870 -0
  21. claude_mpm/cli/commands/monitor.py +2 -2
  22. claude_mpm/cli/commands/mpm_init_handler.py +1 -1
  23. claude_mpm/cli/commands/run.py +114 -0
  24. claude_mpm/cli/commands/search.py +292 -0
  25. claude_mpm/cli/interactive/agent_wizard.py +2 -2
  26. claude_mpm/cli/parsers/base_parser.py +13 -0
  27. claude_mpm/cli/parsers/mcp_parser.py +15 -0
  28. claude_mpm/cli/parsers/run_parser.py +5 -0
  29. claude_mpm/cli/parsers/search_parser.py +245 -0
  30. claude_mpm/cli/startup_logging.py +3 -5
  31. claude_mpm/cli/utils.py +1 -1
  32. claude_mpm/constants.py +1 -0
  33. claude_mpm/core/agent_registry.py +12 -8
  34. claude_mpm/core/agent_session_manager.py +8 -8
  35. claude_mpm/core/api_validator.py +4 -4
  36. claude_mpm/core/base_service.py +10 -10
  37. claude_mpm/core/cache.py +5 -5
  38. claude_mpm/core/config_constants.py +1 -1
  39. claude_mpm/core/container.py +1 -1
  40. claude_mpm/core/error_handler.py +2 -2
  41. claude_mpm/core/file_utils.py +1 -1
  42. claude_mpm/core/framework_loader.py +3 -3
  43. claude_mpm/core/hook_manager.py +8 -6
  44. claude_mpm/core/instruction_reinforcement_hook.py +2 -2
  45. claude_mpm/core/interactive_session.py +1 -1
  46. claude_mpm/core/lazy.py +3 -3
  47. claude_mpm/core/log_manager.py +16 -12
  48. claude_mpm/core/logger.py +16 -11
  49. claude_mpm/core/logging_config.py +4 -2
  50. claude_mpm/core/oneshot_session.py +1 -1
  51. claude_mpm/core/optimized_agent_loader.py +6 -6
  52. claude_mpm/core/output_style_manager.py +1 -1
  53. claude_mpm/core/pm_hook_interceptor.py +3 -3
  54. claude_mpm/core/service_registry.py +1 -1
  55. claude_mpm/core/session_manager.py +11 -9
  56. claude_mpm/core/socketio_pool.py +13 -13
  57. claude_mpm/core/types.py +2 -2
  58. claude_mpm/core/unified_agent_registry.py +9 -2
  59. claude_mpm/core/unified_paths.py +1 -1
  60. claude_mpm/dashboard/analysis_runner.py +4 -4
  61. claude_mpm/dashboard/api/simple_directory.py +1 -1
  62. claude_mpm/generators/agent_profile_generator.py +4 -2
  63. claude_mpm/hooks/base_hook.py +2 -2
  64. claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
  65. claude_mpm/hooks/claude_hooks/event_handlers.py +12 -12
  66. claude_mpm/hooks/claude_hooks/hook_handler.py +4 -4
  67. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +3 -3
  68. claude_mpm/hooks/claude_hooks/hook_handler_original.py +15 -14
  69. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +4 -4
  70. claude_mpm/hooks/claude_hooks/installer.py +3 -3
  71. claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
  72. claude_mpm/hooks/claude_hooks/response_tracking.py +3 -3
  73. claude_mpm/hooks/claude_hooks/services/connection_manager.py +5 -5
  74. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +3 -3
  75. claude_mpm/hooks/claude_hooks/services/state_manager.py +8 -7
  76. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
  77. claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
  78. claude_mpm/hooks/memory_integration_hook.py +1 -1
  79. claude_mpm/hooks/tool_call_interceptor.py +2 -2
  80. claude_mpm/models/agent_session.py +5 -5
  81. claude_mpm/services/__init__.py +1 -1
  82. claude_mpm/services/agent_capabilities_service.py +1 -1
  83. claude_mpm/services/agents/agent_builder.py +3 -3
  84. claude_mpm/services/agents/deployment/agent_deployment.py +29 -13
  85. claude_mpm/services/agents/deployment/agent_discovery_service.py +22 -6
  86. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +7 -5
  87. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +3 -1
  88. claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
  89. claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
  90. claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
  91. claude_mpm/services/agents/deployment/agent_template_builder.py +1 -1
  92. claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
  93. claude_mpm/services/agents/deployment/deployment_wrapper.py +2 -3
  94. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +6 -4
  95. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +1 -1
  96. claude_mpm/services/agents/loading/agent_profile_loader.py +5 -3
  97. claude_mpm/services/agents/loading/base_agent_manager.py +2 -2
  98. claude_mpm/services/agents/local_template_manager.py +6 -6
  99. claude_mpm/services/agents/management/agent_management_service.py +3 -3
  100. claude_mpm/services/agents/memory/content_manager.py +3 -3
  101. claude_mpm/services/agents/memory/memory_format_service.py +2 -2
  102. claude_mpm/services/agents/memory/template_generator.py +3 -3
  103. claude_mpm/services/agents/registry/__init__.py +1 -1
  104. claude_mpm/services/agents/registry/modification_tracker.py +2 -2
  105. claude_mpm/services/async_session_logger.py +3 -3
  106. claude_mpm/services/claude_session_logger.py +4 -4
  107. claude_mpm/services/cli/agent_cleanup_service.py +5 -0
  108. claude_mpm/services/cli/agent_listing_service.py +1 -1
  109. claude_mpm/services/cli/agent_validation_service.py +1 -0
  110. claude_mpm/services/cli/memory_crud_service.py +11 -6
  111. claude_mpm/services/cli/memory_output_formatter.py +1 -1
  112. claude_mpm/services/cli/session_manager.py +15 -11
  113. claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
  114. claude_mpm/services/core/memory_manager.py +81 -23
  115. claude_mpm/services/core/path_resolver.py +2 -2
  116. claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
  117. claude_mpm/services/event_aggregator.py +4 -2
  118. claude_mpm/services/event_bus/direct_relay.py +5 -3
  119. claude_mpm/services/event_bus/event_bus.py +3 -3
  120. claude_mpm/services/event_bus/relay.py +6 -4
  121. claude_mpm/services/events/consumers/dead_letter.py +5 -3
  122. claude_mpm/services/events/core.py +3 -3
  123. claude_mpm/services/events/producers/hook.py +6 -6
  124. claude_mpm/services/events/producers/system.py +8 -8
  125. claude_mpm/services/exceptions.py +5 -5
  126. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -3
  127. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
  128. claude_mpm/services/hook_installer_service.py +1 -1
  129. claude_mpm/services/infrastructure/context_preservation.py +6 -4
  130. claude_mpm/services/infrastructure/daemon_manager.py +2 -2
  131. claude_mpm/services/infrastructure/logging.py +2 -2
  132. claude_mpm/services/mcp_config_manager.py +439 -0
  133. claude_mpm/services/mcp_gateway/__init__.py +1 -1
  134. claude_mpm/services/mcp_gateway/auto_configure.py +3 -3
  135. claude_mpm/services/mcp_gateway/config/config_loader.py +1 -1
  136. claude_mpm/services/mcp_gateway/config/configuration.py +18 -1
  137. claude_mpm/services/mcp_gateway/core/base.py +2 -2
  138. claude_mpm/services/mcp_gateway/main.py +52 -0
  139. claude_mpm/services/mcp_gateway/registry/tool_registry.py +10 -8
  140. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +4 -4
  141. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  142. claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -3
  143. claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
  144. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +7 -5
  145. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +443 -0
  146. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +5 -5
  147. claude_mpm/services/mcp_gateway/tools/hello_world.py +9 -9
  148. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +16 -16
  149. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +17 -17
  150. claude_mpm/services/memory/builder.py +7 -5
  151. claude_mpm/services/memory/indexed_memory.py +4 -4
  152. claude_mpm/services/memory/optimizer.py +6 -6
  153. claude_mpm/services/memory/router.py +3 -3
  154. claude_mpm/services/monitor/daemon.py +1 -1
  155. claude_mpm/services/monitor/daemon_manager.py +6 -6
  156. claude_mpm/services/monitor/event_emitter.py +2 -2
  157. claude_mpm/services/monitor/handlers/file.py +1 -1
  158. claude_mpm/services/monitor/management/lifecycle.py +1 -1
  159. claude_mpm/services/monitor/server.py +4 -4
  160. claude_mpm/services/monitor_build_service.py +2 -2
  161. claude_mpm/services/port_manager.py +2 -2
  162. claude_mpm/services/response_tracker.py +2 -2
  163. claude_mpm/services/session_management_service.py +3 -2
  164. claude_mpm/services/socketio/client_proxy.py +2 -2
  165. claude_mpm/services/socketio/dashboard_server.py +4 -3
  166. claude_mpm/services/socketio/event_normalizer.py +12 -8
  167. claude_mpm/services/socketio/handlers/base.py +2 -2
  168. claude_mpm/services/socketio/handlers/connection.py +10 -10
  169. claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
  170. claude_mpm/services/socketio/handlers/file.py +1 -1
  171. claude_mpm/services/socketio/handlers/git.py +1 -1
  172. claude_mpm/services/socketio/handlers/hook.py +16 -15
  173. claude_mpm/services/socketio/migration_utils.py +1 -1
  174. claude_mpm/services/socketio/monitor_client.py +5 -5
  175. claude_mpm/services/socketio/server/broadcaster.py +9 -7
  176. claude_mpm/services/socketio/server/connection_manager.py +2 -2
  177. claude_mpm/services/socketio/server/core.py +7 -5
  178. claude_mpm/services/socketio/server/eventbus_integration.py +18 -11
  179. claude_mpm/services/socketio/server/main.py +13 -13
  180. claude_mpm/services/socketio_client_manager.py +4 -4
  181. claude_mpm/services/system_instructions_service.py +2 -2
  182. claude_mpm/services/ticket_services/validation_service.py +1 -1
  183. claude_mpm/services/utility_service.py +5 -2
  184. claude_mpm/services/version_control/branch_strategy.py +2 -2
  185. claude_mpm/services/version_control/git_operations.py +22 -20
  186. claude_mpm/services/version_control/semantic_versioning.py +3 -3
  187. claude_mpm/services/version_control/version_parser.py +7 -5
  188. claude_mpm/services/visualization/mermaid_generator.py +1 -1
  189. claude_mpm/storage/state_storage.py +1 -1
  190. claude_mpm/tools/code_tree_analyzer.py +19 -18
  191. claude_mpm/tools/code_tree_builder.py +2 -2
  192. claude_mpm/tools/code_tree_events.py +10 -8
  193. claude_mpm/tools/socketio_debug.py +3 -3
  194. claude_mpm/utils/agent_dependency_loader.py +2 -2
  195. claude_mpm/utils/dependency_strategies.py +8 -3
  196. claude_mpm/utils/environment_context.py +2 -2
  197. claude_mpm/utils/error_handler.py +2 -2
  198. claude_mpm/utils/file_utils.py +1 -1
  199. claude_mpm/utils/imports.py +1 -1
  200. claude_mpm/utils/log_cleanup.py +21 -7
  201. claude_mpm/validation/agent_validator.py +2 -2
  202. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/METADATA +4 -1
  203. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/RECORD +207 -200
  204. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/WHEEL +0 -0
  205. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/entry_points.txt +0 -0
  206. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/licenses/LICENSE +0 -0
  207. {claude_mpm-4.3.11.dist-info → claude_mpm-4.3.13.dist-info}/top_level.txt +0 -0
@@ -20,7 +20,7 @@ import asyncio
20
20
  import os
21
21
  import platform
22
22
  import sys
23
- from datetime import datetime
23
+ from datetime import datetime, timezone
24
24
  from typing import Any, Dict
25
25
 
26
26
  import psutil
@@ -86,7 +86,7 @@ class HealthCheckTool(BaseToolAdapter):
86
86
  Returns:
87
87
  Tool execution result with health check results
88
88
  """
89
- start_time = datetime.now()
89
+ start_time = datetime.now(timezone.utc)
90
90
 
91
91
  try:
92
92
  # Get parameters
@@ -98,7 +98,7 @@ class HealthCheckTool(BaseToolAdapter):
98
98
  results = await self._perform_health_checks(check_type, detailed, timeout)
99
99
 
100
100
  # Calculate execution time
101
- execution_time = (datetime.now() - start_time).total_seconds()
101
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
102
102
 
103
103
  # Update metrics
104
104
  self._update_metrics(True, execution_time)
@@ -115,7 +115,7 @@ class HealthCheckTool(BaseToolAdapter):
115
115
  )
116
116
 
117
117
  except Exception as e:
118
- execution_time = (datetime.now() - start_time).total_seconds()
118
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
119
119
  self._update_metrics(False, execution_time)
120
120
 
121
121
  return MCPToolResult(
@@ -130,7 +130,7 @@ class HealthCheckTool(BaseToolAdapter):
130
130
  ) -> Dict[str, Any]:
131
131
  """Perform the requested health checks."""
132
132
  results = {
133
- "timestamp": datetime.now().isoformat(),
133
+ "timestamp": datetime.now(timezone.utc).isoformat(),
134
134
  "check_type": check_type,
135
135
  "detailed": detailed,
136
136
  "overall_status": "unknown",
@@ -27,7 +27,7 @@ import json
27
27
  import platform
28
28
  import re
29
29
  import sys
30
- from datetime import datetime
30
+ from datetime import datetime, timezone
31
31
  from typing import Any, Dict, List, Optional
32
32
 
33
33
  from claude_mpm.services.mcp_gateway.core.interfaces import (
@@ -204,7 +204,7 @@ class HelloWorldTool(BaseToolAdapter):
204
204
  self.greeting_history: List[Dict[str, Any]] = []
205
205
  self.max_history_size = 100
206
206
 
207
- def validate_parameters(self, parameters: Dict[str, Any]) -> bool:
207
+ def validate_parameters(self, parameters: Dict[str, Any]) -> bool: # noqa: PLR0911
208
208
  """
209
209
  Enhanced parameter validation with detailed error messages.
210
210
 
@@ -305,7 +305,7 @@ class HelloWorldTool(BaseToolAdapter):
305
305
  Returns:
306
306
  Tool execution result with greeting
307
307
  """
308
- start_time = datetime.now()
308
+ start_time = datetime.now(timezone.utc)
309
309
 
310
310
  try:
311
311
  # Validate parameters
@@ -353,13 +353,13 @@ class HelloWorldTool(BaseToolAdapter):
353
353
  greeting = " ".join([greeting] * repeat)
354
354
 
355
355
  # Calculate execution time
356
- execution_time = (datetime.now() - start_time).total_seconds()
356
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
357
357
 
358
358
  # Build response data
359
359
  response_data = {
360
360
  "greeting": greeting,
361
361
  "mode": mode,
362
- "timestamp": datetime.now().isoformat(),
362
+ "timestamp": datetime.now(timezone.utc).isoformat(),
363
363
  }
364
364
 
365
365
  # Add metadata if requested
@@ -389,7 +389,7 @@ class HelloWorldTool(BaseToolAdapter):
389
389
  )
390
390
 
391
391
  except Exception as e:
392
- execution_time = (datetime.now() - start_time).total_seconds()
392
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
393
393
  self._update_metrics(False, execution_time)
394
394
  self._metrics["last_error"] = str(e)
395
395
 
@@ -409,11 +409,11 @@ class HelloWorldTool(BaseToolAdapter):
409
409
 
410
410
  async def _time_based_greeting(self) -> str:
411
411
  """Generate a greeting based on current time."""
412
- current_hour = datetime.now().hour
412
+ current_hour = datetime.now(timezone.utc).hour
413
413
 
414
414
  for (start, end), greeting in self.TIME_GREETINGS.items():
415
415
  if start <= current_hour < end:
416
- return f"{greeting}! It's {datetime.now().strftime('%I:%M %p')}."
416
+ return f"{greeting}! It's {datetime.now(timezone.utc).strftime('%I:%M %p')}."
417
417
 
418
418
  return "Hello! Time is a curious thing."
419
419
 
@@ -482,7 +482,7 @@ class HelloWorldTool(BaseToolAdapter):
482
482
  execution_time: Time taken to generate greeting
483
483
  """
484
484
  entry = {
485
- "timestamp": datetime.now().isoformat(),
485
+ "timestamp": datetime.now(timezone.utc).isoformat(),
486
486
  "mode": mode,
487
487
  "greeting": greeting[:100], # Truncate long greetings
488
488
  "execution_time": execution_time,
@@ -18,7 +18,7 @@ DESIGN DECISIONS:
18
18
 
19
19
  import asyncio
20
20
  import json
21
- from datetime import datetime
21
+ from datetime import datetime, timezone
22
22
 
23
23
  from claude_mpm.services.mcp_gateway.core.interfaces import (
24
24
  MCPToolDefinition,
@@ -89,7 +89,7 @@ class TicketCreateTool(BaseToolAdapter):
89
89
  Returns:
90
90
  Tool execution result with created ticket ID
91
91
  """
92
- start_time = datetime.now()
92
+ start_time = datetime.now(timezone.utc)
93
93
 
94
94
  try:
95
95
  params = invocation.parameters
@@ -120,7 +120,7 @@ class TicketCreateTool(BaseToolAdapter):
120
120
 
121
121
  stdout, stderr = await process.communicate()
122
122
 
123
- execution_time = (datetime.now() - start_time).total_seconds()
123
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
124
124
 
125
125
  if process.returncode == 0:
126
126
  # Parse ticket ID from output
@@ -160,7 +160,7 @@ class TicketCreateTool(BaseToolAdapter):
160
160
  )
161
161
 
162
162
  except Exception as e:
163
- execution_time = (datetime.now() - start_time).total_seconds()
163
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
164
164
  self._update_metrics(False, execution_time)
165
165
 
166
166
  return MCPToolResult(
@@ -232,7 +232,7 @@ class TicketListTool(BaseToolAdapter):
232
232
  Returns:
233
233
  Tool execution result with list of tickets
234
234
  """
235
- start_time = datetime.now()
235
+ start_time = datetime.now(timezone.utc)
236
236
 
237
237
  try:
238
238
  params = invocation.parameters
@@ -252,7 +252,7 @@ class TicketListTool(BaseToolAdapter):
252
252
 
253
253
  stdout, stderr = await process.communicate()
254
254
 
255
- execution_time = (datetime.now() - start_time).total_seconds()
255
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
256
256
 
257
257
  if process.returncode == 0:
258
258
  try:
@@ -285,7 +285,7 @@ class TicketListTool(BaseToolAdapter):
285
285
  )
286
286
 
287
287
  except Exception as e:
288
- execution_time = (datetime.now() - start_time).total_seconds()
288
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
289
289
  self._update_metrics(False, execution_time)
290
290
 
291
291
  return MCPToolResult(
@@ -352,7 +352,7 @@ class TicketUpdateTool(BaseToolAdapter):
352
352
  Returns:
353
353
  Tool execution result
354
354
  """
355
- start_time = datetime.now()
355
+ start_time = datetime.now(timezone.utc)
356
356
 
357
357
  try:
358
358
  params = invocation.parameters
@@ -387,7 +387,7 @@ class TicketUpdateTool(BaseToolAdapter):
387
387
 
388
388
  stdout, stderr = await process.communicate()
389
389
 
390
- execution_time = (datetime.now() - start_time).total_seconds()
390
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
391
391
 
392
392
  if process.returncode == 0:
393
393
  self._update_metrics(True, execution_time)
@@ -414,7 +414,7 @@ class TicketUpdateTool(BaseToolAdapter):
414
414
  )
415
415
 
416
416
  except Exception as e:
417
- execution_time = (datetime.now() - start_time).total_seconds()
417
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
418
418
  self._update_metrics(False, execution_time)
419
419
 
420
420
  return MCPToolResult(
@@ -466,7 +466,7 @@ class TicketViewTool(BaseToolAdapter):
466
466
  Returns:
467
467
  Tool execution result with ticket details
468
468
  """
469
- start_time = datetime.now()
469
+ start_time = datetime.now(timezone.utc)
470
470
 
471
471
  try:
472
472
  params = invocation.parameters
@@ -483,7 +483,7 @@ class TicketViewTool(BaseToolAdapter):
483
483
 
484
484
  stdout, stderr = await process.communicate()
485
485
 
486
- execution_time = (datetime.now() - start_time).total_seconds()
486
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
487
487
 
488
488
  if process.returncode == 0:
489
489
  output = stdout.decode().strip()
@@ -518,7 +518,7 @@ class TicketViewTool(BaseToolAdapter):
518
518
  )
519
519
 
520
520
  except Exception as e:
521
- execution_time = (datetime.now() - start_time).total_seconds()
521
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
522
522
  self._update_metrics(False, execution_time)
523
523
 
524
524
  return MCPToolResult(
@@ -572,7 +572,7 @@ class TicketSearchTool(BaseToolAdapter):
572
572
  Returns:
573
573
  Tool execution result with matching tickets
574
574
  """
575
- start_time = datetime.now()
575
+ start_time = datetime.now(timezone.utc)
576
576
 
577
577
  try:
578
578
  params = invocation.parameters
@@ -592,7 +592,7 @@ class TicketSearchTool(BaseToolAdapter):
592
592
 
593
593
  stdout, stderr = await process.communicate()
594
594
 
595
- execution_time = (datetime.now() - start_time).total_seconds()
595
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
596
596
 
597
597
  if process.returncode == 0:
598
598
  try:
@@ -625,7 +625,7 @@ class TicketSearchTool(BaseToolAdapter):
625
625
  )
626
626
 
627
627
  except Exception as e:
628
- execution_time = (datetime.now() - start_time).total_seconds()
628
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
629
629
  self._update_metrics(False, execution_time)
630
630
 
631
631
  return MCPToolResult(
@@ -21,7 +21,7 @@ DESIGN DECISIONS:
21
21
  import asyncio
22
22
  import json
23
23
  import re
24
- from datetime import datetime
24
+ from datetime import datetime, timezone
25
25
  from typing import Any, Dict, Optional
26
26
 
27
27
  from claude_mpm.services.mcp_gateway.core.interfaces import (
@@ -192,7 +192,7 @@ class UnifiedTicketTool(BaseToolAdapter):
192
192
 
193
193
  def _validate_parameters(
194
194
  self, operation: str, params: Dict[str, Any]
195
- ) -> Optional[str]:
195
+ ) -> Optional[str]: # noqa: PLR0911
196
196
  """
197
197
  Validate parameters based on the operation type.
198
198
 
@@ -242,7 +242,7 @@ class UnifiedTicketTool(BaseToolAdapter):
242
242
  Returns:
243
243
  Tool execution result with created ticket ID
244
244
  """
245
- start_time = datetime.now()
245
+ start_time = datetime.now(timezone.utc)
246
246
 
247
247
  try:
248
248
  # Build aitrackdown command
@@ -269,7 +269,7 @@ class UnifiedTicketTool(BaseToolAdapter):
269
269
  )
270
270
 
271
271
  stdout, stderr = await process.communicate()
272
- execution_time = (datetime.now() - start_time).total_seconds()
272
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
273
273
 
274
274
  if process.returncode == 0:
275
275
  # Parse ticket ID from output
@@ -305,7 +305,7 @@ class UnifiedTicketTool(BaseToolAdapter):
305
305
  )
306
306
 
307
307
  except Exception as e:
308
- execution_time = (datetime.now() - start_time).total_seconds()
308
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
309
309
  self._update_metrics(False, execution_time)
310
310
 
311
311
  return MCPToolResult(
@@ -324,7 +324,7 @@ class UnifiedTicketTool(BaseToolAdapter):
324
324
  Returns:
325
325
  Tool execution result with list of tickets
326
326
  """
327
- start_time = datetime.now()
327
+ start_time = datetime.now(timezone.utc)
328
328
 
329
329
  try:
330
330
  limit = params.get("limit", 10)
@@ -342,7 +342,7 @@ class UnifiedTicketTool(BaseToolAdapter):
342
342
  )
343
343
 
344
344
  stdout, stderr = await process.communicate()
345
- execution_time = (datetime.now() - start_time).total_seconds()
345
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
346
346
 
347
347
  if process.returncode == 0:
348
348
  try:
@@ -375,7 +375,7 @@ class UnifiedTicketTool(BaseToolAdapter):
375
375
  )
376
376
 
377
377
  except Exception as e:
378
- execution_time = (datetime.now() - start_time).total_seconds()
378
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
379
379
  self._update_metrics(False, execution_time)
380
380
 
381
381
  return MCPToolResult(
@@ -394,7 +394,7 @@ class UnifiedTicketTool(BaseToolAdapter):
394
394
  Returns:
395
395
  Tool execution result
396
396
  """
397
- start_time = datetime.now()
397
+ start_time = datetime.now(timezone.utc)
398
398
 
399
399
  try:
400
400
  ticket_id = params["ticket_id"]
@@ -426,7 +426,7 @@ class UnifiedTicketTool(BaseToolAdapter):
426
426
  )
427
427
 
428
428
  stdout, stderr = await process.communicate()
429
- execution_time = (datetime.now() - start_time).total_seconds()
429
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
430
430
 
431
431
  if process.returncode == 0:
432
432
  self._update_metrics(True, execution_time)
@@ -453,7 +453,7 @@ class UnifiedTicketTool(BaseToolAdapter):
453
453
  )
454
454
 
455
455
  except Exception as e:
456
- execution_time = (datetime.now() - start_time).total_seconds()
456
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
457
457
  self._update_metrics(False, execution_time)
458
458
 
459
459
  return MCPToolResult(
@@ -472,7 +472,7 @@ class UnifiedTicketTool(BaseToolAdapter):
472
472
  Returns:
473
473
  Tool execution result with ticket details
474
474
  """
475
- start_time = datetime.now()
475
+ start_time = datetime.now(timezone.utc)
476
476
 
477
477
  try:
478
478
  ticket_id = params["ticket_id"]
@@ -487,7 +487,7 @@ class UnifiedTicketTool(BaseToolAdapter):
487
487
  )
488
488
 
489
489
  stdout, stderr = await process.communicate()
490
- execution_time = (datetime.now() - start_time).total_seconds()
490
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
491
491
 
492
492
  if process.returncode == 0:
493
493
  output = stdout.decode().strip()
@@ -522,7 +522,7 @@ class UnifiedTicketTool(BaseToolAdapter):
522
522
  )
523
523
 
524
524
  except Exception as e:
525
- execution_time = (datetime.now() - start_time).total_seconds()
525
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
526
526
  self._update_metrics(False, execution_time)
527
527
 
528
528
  return MCPToolResult(
@@ -541,7 +541,7 @@ class UnifiedTicketTool(BaseToolAdapter):
541
541
  Returns:
542
542
  Tool execution result with matching tickets
543
543
  """
544
- start_time = datetime.now()
544
+ start_time = datetime.now(timezone.utc)
545
545
 
546
546
  try:
547
547
  query = params["query"]
@@ -559,7 +559,7 @@ class UnifiedTicketTool(BaseToolAdapter):
559
559
  )
560
560
 
561
561
  stdout, stderr = await process.communicate()
562
- execution_time = (datetime.now() - start_time).total_seconds()
562
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
563
563
 
564
564
  if process.returncode == 0:
565
565
  try:
@@ -588,7 +588,7 @@ class UnifiedTicketTool(BaseToolAdapter):
588
588
  )
589
589
 
590
590
  except Exception as e:
591
- execution_time = (datetime.now() - start_time).total_seconds()
591
+ execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
592
592
  self._update_metrics(False, execution_time)
593
593
 
594
594
  return MCPToolResult(
@@ -24,7 +24,7 @@ while preserving essential information.
24
24
 
25
25
  import os
26
26
  import re
27
- from datetime import datetime
27
+ from datetime import datetime, timezone
28
28
  from pathlib import Path
29
29
  from typing import Any, Dict, List, Optional
30
30
 
@@ -234,7 +234,7 @@ class MemoryBuilder(LoggerMixin):
234
234
  try:
235
235
  results = {
236
236
  "success": True,
237
- "timestamp": datetime.now().isoformat(),
237
+ "timestamp": datetime.now(timezone.utc).isoformat(),
238
238
  "files_processed": 0,
239
239
  "memories_created": 0,
240
240
  "memories_updated": 0,
@@ -293,7 +293,7 @@ class MemoryBuilder(LoggerMixin):
293
293
  return {
294
294
  "success": False,
295
295
  "error": str(e),
296
- "timestamp": datetime.now().isoformat(),
296
+ "timestamp": datetime.now(timezone.utc).isoformat(),
297
297
  }
298
298
 
299
299
  def extract_from_text(self, text: str, source: str) -> List[Dict[str, Any]]:
@@ -777,7 +777,9 @@ class MemoryBuilder(LoggerMixin):
777
777
  return True
778
778
 
779
779
  last_processed_time = datetime.fromisoformat(last_processed[file_key])
780
- file_modified_time = datetime.fromtimestamp(file_path.stat().st_mtime)
780
+ file_modified_time = datetime.fromtimestamp(
781
+ file_path.stat().st_mtime, tz=timezone.utc
782
+ )
781
783
 
782
784
  return file_modified_time > last_processed_time
783
785
 
@@ -805,7 +807,7 @@ class MemoryBuilder(LoggerMixin):
805
807
 
806
808
  # Update timestamp
807
809
  file_key = str(file_path.relative_to(self.project_root))
808
- last_processed[file_key] = datetime.now().isoformat()
810
+ last_processed[file_key] = datetime.now(timezone.utc).isoformat()
809
811
 
810
812
  # Save back
811
813
  import json
@@ -23,7 +23,7 @@ import re
23
23
  import time
24
24
  from collections import Counter, defaultdict
25
25
  from dataclasses import dataclass, field
26
- from datetime import datetime, timedelta
26
+ from datetime import datetime, timedelta, timezone
27
27
  from typing import Any, Dict, List, Optional, Set, Tuple
28
28
 
29
29
  from ...core.cache import get_file_cache
@@ -388,7 +388,7 @@ class IndexedMemoryService:
388
388
  agent_id=agent_id,
389
389
  content=content,
390
390
  category=category,
391
- timestamp=datetime.now(),
391
+ timestamp=datetime.now(timezone.utc),
392
392
  tags=tags or [],
393
393
  metadata=metadata or {},
394
394
  )
@@ -510,7 +510,7 @@ class IndexedMemoryService:
510
510
  start_time = time.time()
511
511
 
512
512
  # Calculate time range
513
- now = datetime.now()
513
+ now = datetime.now(timezone.utc)
514
514
  if hours:
515
515
  min_time = now - timedelta(hours=hours)
516
516
  elif days:
@@ -563,7 +563,7 @@ class IndexedMemoryService:
563
563
 
564
564
  def _generate_id(self, agent_id: str, content: str) -> str:
565
565
  """Generate unique ID for memory entry."""
566
- timestamp = datetime.now().isoformat()
566
+ timestamp = datetime.now(timezone.utc).isoformat()
567
567
  hash_input = f"{agent_id}:{content[:100]}:{timestamp}"
568
568
  return hashlib.md5(hash_input.encode()).hexdigest()[:12]
569
569
 
@@ -24,7 +24,7 @@ information than lose important insights.
24
24
 
25
25
  import os
26
26
  import re
27
- from datetime import datetime
27
+ from datetime import datetime, timezone
28
28
  from difflib import SequenceMatcher
29
29
  from pathlib import Path
30
30
  from typing import Any, Dict, List, Optional, Tuple
@@ -164,7 +164,7 @@ class MemoryOptimizer(LoggerMixin):
164
164
  else 0
165
165
  ),
166
166
  "backup_created": str(backup_path),
167
- "timestamp": datetime.now().isoformat(),
167
+ "timestamp": datetime.now(timezone.utc).isoformat(),
168
168
  **optimization_stats,
169
169
  }
170
170
 
@@ -230,7 +230,7 @@ class MemoryOptimizer(LoggerMixin):
230
230
 
231
231
  return {
232
232
  "success": True,
233
- "timestamp": datetime.now().isoformat(),
233
+ "timestamp": datetime.now(timezone.utc).isoformat(),
234
234
  "agents": results,
235
235
  "summary": {
236
236
  **total_stats,
@@ -545,7 +545,7 @@ class MemoryOptimizer(LoggerMixin):
545
545
 
546
546
  # Update timestamp
547
547
  content = "\n".join(content_lines)
548
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
548
+ timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
549
549
  return re.sub(
550
550
  r"<!-- Last Updated: .+ \| Auto-updated by: .+ -->",
551
551
  f"<!-- Last Updated: {timestamp} | Auto-updated by: optimizer -->",
@@ -561,7 +561,7 @@ class MemoryOptimizer(LoggerMixin):
561
561
  Returns:
562
562
  Path to backup file
563
563
  """
564
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
564
+ timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
565
565
  backup_name = f"{memory_file.stem}_backup_{timestamp}{memory_file.suffix}"
566
566
  backup_path = memory_file.parent / backup_name
567
567
 
@@ -647,7 +647,7 @@ class MemoryOptimizer(LoggerMixin):
647
647
 
648
648
  return {
649
649
  "success": True,
650
- "timestamp": datetime.now().isoformat(),
650
+ "timestamp": datetime.now(timezone.utc).isoformat(),
651
651
  "agents_analyzed": len(agents_analysis),
652
652
  "agents": agents_analysis,
653
653
  }
@@ -21,7 +21,7 @@ users understand why content was assigned to specific agents.
21
21
  """
22
22
 
23
23
  import re
24
- from datetime import datetime
24
+ from datetime import datetime, timezone
25
25
  from typing import Any, Dict, List, Optional, Tuple
26
26
 
27
27
  from claude_mpm.core.config import Config
@@ -622,7 +622,7 @@ class MemoryRouter(LoggerMixin):
622
622
  "confidence": confidence,
623
623
  "reasoning": reasoning,
624
624
  "agent_scores": agent_scores,
625
- "timestamp": datetime.now().isoformat(),
625
+ "timestamp": datetime.now(timezone.utc).isoformat(),
626
626
  "content_length": len(content),
627
627
  }
628
628
 
@@ -639,7 +639,7 @@ class MemoryRouter(LoggerMixin):
639
639
  "confidence": 0.1,
640
640
  "reasoning": f"Error during analysis, defaulting to {self.DEFAULT_AGENT}",
641
641
  "error": str(e),
642
- "timestamp": datetime.now().isoformat(),
642
+ "timestamp": datetime.now(timezone.utc).isoformat(),
643
643
  "content_length": len(content) if content else 0,
644
644
  }
645
645
 
@@ -121,7 +121,7 @@ class UnifiedMonitorDaemon:
121
121
  """
122
122
  return self.daemon_manager.cleanup_port_conflicts()
123
123
 
124
- def _start_daemon(self, force_restart: bool = False) -> bool:
124
+ def _start_daemon(self, force_restart: bool = False) -> bool: # noqa: PLR0911
125
125
  """Start as background daemon process.
126
126
 
127
127
  Args:
@@ -163,7 +163,7 @@ class DaemonManager:
163
163
  test_sock.bind(("::1", self.port))
164
164
  test_sock.close()
165
165
  return True
166
- except:
166
+ except Exception:
167
167
  # Both IPv4 and IPv6 failed - port is in use
168
168
  return False
169
169
 
@@ -434,10 +434,10 @@ class DaemonManager:
434
434
  # It's likely our service, try to find PID
435
435
  pid = self._find_service_pid()
436
436
  return True, pid
437
- except:
437
+ except Exception:
438
438
  pass
439
439
 
440
- except:
440
+ except Exception:
441
441
  pass
442
442
 
443
443
  return False, None
@@ -465,7 +465,7 @@ class DaemonManager:
465
465
  if pids:
466
466
  return int(pids[0].strip())
467
467
 
468
- except:
468
+ except Exception:
469
469
  pass
470
470
 
471
471
  return None
@@ -615,7 +615,7 @@ class DaemonManager:
615
615
  f"Monitor daemon successfully started on port {self.port}"
616
616
  )
617
617
  return True
618
- except:
618
+ except Exception:
619
619
  pass # PID file not ready yet
620
620
 
621
621
  time.sleep(0.5)
@@ -958,5 +958,5 @@ class DaemonManager:
958
958
  with open("/tmp/daemon_debug_error.txt", "a") as debug:
959
959
  debug.write(f"Error reporting error: {e}\n")
960
960
  debug.write(f"Status file: {self.startup_status_file}\n")
961
- except:
961
+ except Exception:
962
962
  pass
@@ -10,7 +10,7 @@ WHY: Eliminates HTTP overhead for in-process events while maintaining external A
10
10
 
11
11
  import asyncio
12
12
  import weakref
13
- from datetime import datetime
13
+ from datetime import datetime, timezone
14
14
  from typing import Any, Dict, Optional, Set
15
15
 
16
16
  import aiohttp
@@ -203,7 +203,7 @@ class AsyncEventEmitter:
203
203
  "namespace": namespace,
204
204
  "event": event,
205
205
  "data": data,
206
- "timestamp": datetime.now().isoformat(),
206
+ "timestamp": datetime.now(timezone.utc).isoformat(),
207
207
  "source": "async_emitter",
208
208
  }
209
209
 
@@ -109,7 +109,7 @@ class FileHandler:
109
109
  file_path: str,
110
110
  working_dir: Optional[str] = None,
111
111
  max_size: int = 1024 * 1024,
112
- ) -> Dict[str, Any]:
112
+ ) -> Dict[str, Any]: # noqa: PLR0911
113
113
  """Safely read file content with security checks.
114
114
 
115
115
  WHY: File reading must be secure to prevent directory traversal attacks
@@ -514,7 +514,7 @@ class DaemonLifecycle:
514
514
  error_msg = f"Port {self.port} is already in use or cannot be bound: {e}"
515
515
  return False, error_msg
516
516
 
517
- def is_our_service(self, host: str = "localhost") -> Tuple[bool, Optional[int]]:
517
+ def is_our_service(self, host: str = "localhost") -> Tuple[bool, Optional[int]]: # noqa: PLR0911
518
518
  """Check if the service on the port is our Socket.IO service.
519
519
 
520
520
  This uses multiple detection methods: