claude-mpm 5.0.9__py3-none-any.whl → 5.4.41__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.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (263) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +4 -0
  3. claude_mpm/agents/BASE_AGENT.md +164 -0
  4. claude_mpm/agents/{PM_INSTRUCTIONS_TEACH.md → CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md} +721 -41
  5. claude_mpm/agents/MEMORY.md +1 -1
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +468 -468
  7. claude_mpm/agents/WORKFLOW.md +5 -254
  8. claude_mpm/agents/agent_loader.py +13 -44
  9. claude_mpm/agents/base_agent.json +1 -1
  10. claude_mpm/agents/frontmatter_validator.py +70 -2
  11. claude_mpm/agents/templates/circuit-breakers.md +431 -45
  12. claude_mpm/cli/__init__.py +0 -1
  13. claude_mpm/cli/__main__.py +4 -0
  14. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  15. claude_mpm/cli/commands/agent_state_manager.py +18 -27
  16. claude_mpm/cli/commands/agents.py +175 -37
  17. claude_mpm/cli/commands/auto_configure.py +723 -236
  18. claude_mpm/cli/commands/config.py +88 -2
  19. claude_mpm/cli/commands/configure.py +1262 -157
  20. claude_mpm/cli/commands/configure_agent_display.py +25 -6
  21. claude_mpm/cli/commands/mpm_init/core.py +225 -46
  22. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  23. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  24. claude_mpm/cli/commands/postmortem.py +1 -1
  25. claude_mpm/cli/commands/profile.py +277 -0
  26. claude_mpm/cli/commands/skills.py +214 -189
  27. claude_mpm/cli/commands/summarize.py +413 -0
  28. claude_mpm/cli/executor.py +21 -3
  29. claude_mpm/cli/interactive/agent_wizard.py +85 -10
  30. claude_mpm/cli/parsers/agents_parser.py +54 -9
  31. claude_mpm/cli/parsers/auto_configure_parser.py +13 -138
  32. claude_mpm/cli/parsers/base_parser.py +12 -0
  33. claude_mpm/cli/parsers/config_parser.py +153 -83
  34. claude_mpm/cli/parsers/profile_parser.py +148 -0
  35. claude_mpm/cli/parsers/skills_parser.py +3 -2
  36. claude_mpm/cli/startup.py +879 -149
  37. claude_mpm/commands/mpm-config.md +28 -0
  38. claude_mpm/commands/mpm-doctor.md +9 -22
  39. claude_mpm/commands/mpm-help.md +5 -287
  40. claude_mpm/commands/mpm-init.md +81 -507
  41. claude_mpm/commands/mpm-monitor.md +15 -402
  42. claude_mpm/commands/mpm-organize.md +120 -0
  43. claude_mpm/commands/mpm-postmortem.md +6 -108
  44. claude_mpm/commands/mpm-session-resume.md +12 -363
  45. claude_mpm/commands/mpm-status.md +5 -69
  46. claude_mpm/commands/mpm-ticket-view.md +52 -495
  47. claude_mpm/commands/mpm-version.md +5 -107
  48. claude_mpm/config/agent_sources.py +27 -0
  49. claude_mpm/core/config.py +2 -4
  50. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  51. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  52. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  53. claude_mpm/core/framework_loader.py +4 -2
  54. claude_mpm/core/logger.py +13 -0
  55. claude_mpm/core/optimized_startup.py +59 -0
  56. claude_mpm/core/output_style_manager.py +173 -43
  57. claude_mpm/core/shared/config_loader.py +1 -1
  58. claude_mpm/core/socketio_pool.py +3 -3
  59. claude_mpm/core/unified_agent_registry.py +134 -16
  60. claude_mpm/core/unified_config.py +22 -0
  61. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  62. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
  63. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
  64. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
  65. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
  66. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
  67. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
  68. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
  69. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
  70. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
  71. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
  72. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
  73. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
  74. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
  75. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
  76. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  77. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  78. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  79. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  80. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  81. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  82. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  83. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  84. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  85. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  86. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  87. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  88. claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
  89. claude_mpm/hooks/claude_hooks/hook_handler.py +155 -1
  90. claude_mpm/hooks/claude_hooks/installer.py +33 -10
  91. claude_mpm/hooks/claude_hooks/memory_integration.py +28 -0
  92. claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
  93. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  94. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  95. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  96. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  97. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  98. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  99. claude_mpm/hooks/claude_hooks/services/connection_manager.py +30 -6
  100. claude_mpm/hooks/memory_integration_hook.py +46 -1
  101. claude_mpm/init.py +63 -19
  102. claude_mpm/models/agent_definition.py +7 -0
  103. claude_mpm/models/git_repository.py +3 -3
  104. claude_mpm/scripts/claude-hook-handler.sh +58 -18
  105. claude_mpm/scripts/launch_monitor.py +93 -13
  106. claude_mpm/scripts/start_activity_logging.py +0 -0
  107. claude_mpm/services/agents/agent_builder.py +3 -3
  108. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  109. claude_mpm/services/agents/agent_review_service.py +280 -0
  110. claude_mpm/services/agents/cache_git_manager.py +6 -6
  111. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  112. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -5
  113. claude_mpm/services/agents/deployment/agent_template_builder.py +5 -3
  114. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  115. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +320 -29
  116. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +546 -68
  117. claude_mpm/services/agents/git_source_manager.py +36 -2
  118. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  119. claude_mpm/services/agents/recommender.py +5 -3
  120. claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
  121. claude_mpm/services/agents/sources/git_source_sync_service.py +13 -6
  122. claude_mpm/services/agents/startup_sync.py +22 -2
  123. claude_mpm/services/agents/toolchain_detector.py +10 -6
  124. claude_mpm/services/analysis/__init__.py +11 -1
  125. claude_mpm/services/analysis/clone_detector.py +1030 -0
  126. claude_mpm/services/command_deployment_service.py +81 -10
  127. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  128. claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
  129. claude_mpm/services/event_bus/config.py +3 -1
  130. claude_mpm/services/git/git_operations_service.py +101 -16
  131. claude_mpm/services/monitor/daemon.py +9 -2
  132. claude_mpm/services/monitor/daemon_manager.py +39 -3
  133. claude_mpm/services/monitor/management/lifecycle.py +8 -1
  134. claude_mpm/services/monitor/server.py +698 -22
  135. claude_mpm/services/pm_skills_deployer.py +676 -0
  136. claude_mpm/services/profile_manager.py +331 -0
  137. claude_mpm/services/project/project_organizer.py +4 -0
  138. claude_mpm/services/self_upgrade_service.py +120 -12
  139. claude_mpm/services/skills/__init__.py +3 -0
  140. claude_mpm/services/skills/git_skill_source_manager.py +130 -2
  141. claude_mpm/services/skills/selective_skill_deployer.py +704 -0
  142. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  143. claude_mpm/services/skills_deployer.py +126 -9
  144. claude_mpm/services/socketio/dashboard_server.py +1 -0
  145. claude_mpm/services/socketio/event_normalizer.py +51 -6
  146. claude_mpm/services/socketio/server/core.py +386 -108
  147. claude_mpm/services/version_control/git_operations.py +103 -0
  148. claude_mpm/skills/skill_manager.py +92 -3
  149. claude_mpm/utils/agent_dependency_loader.py +14 -2
  150. claude_mpm/utils/agent_filters.py +17 -44
  151. claude_mpm/utils/gitignore.py +3 -0
  152. claude_mpm/utils/migration.py +4 -4
  153. claude_mpm/utils/robust_installer.py +47 -3
  154. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/METADATA +57 -87
  155. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/RECORD +160 -211
  156. claude_mpm-5.4.41.dist-info/entry_points.txt +5 -0
  157. claude_mpm-5.4.41.dist-info/licenses/LICENSE +94 -0
  158. claude_mpm-5.4.41.dist-info/licenses/LICENSE-FAQ.md +153 -0
  159. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  160. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  161. claude_mpm/agents/BASE_OPS.md +0 -219
  162. claude_mpm/agents/BASE_PM.md +0 -480
  163. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  164. claude_mpm/agents/BASE_QA.md +0 -167
  165. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  166. claude_mpm/agents/base_agent_loader.py +0 -601
  167. claude_mpm/cli/commands/agents_detect.py +0 -380
  168. claude_mpm/cli/commands/agents_recommend.py +0 -309
  169. claude_mpm/cli/ticket_cli.py +0 -35
  170. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  171. claude_mpm/commands/mpm-agents-detect.md +0 -177
  172. claude_mpm/commands/mpm-agents-list.md +0 -131
  173. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  174. claude_mpm/commands/mpm-config-view.md +0 -150
  175. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  176. claude_mpm/dashboard/analysis_runner.py +0 -455
  177. claude_mpm/dashboard/index.html +0 -13
  178. claude_mpm/dashboard/open_dashboard.py +0 -66
  179. claude_mpm/dashboard/static/css/activity.css +0 -1958
  180. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  181. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  182. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  183. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  184. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  185. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  186. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  187. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  188. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  189. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  190. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  191. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  192. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  193. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  194. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  195. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  196. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  197. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  198. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  199. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  200. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  201. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  202. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  203. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  204. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  205. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  206. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  207. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  208. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  209. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  210. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  211. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  212. claude_mpm/dashboard/templates/code_simple.html +0 -153
  213. claude_mpm/dashboard/templates/index.html +0 -606
  214. claude_mpm/dashboard/test_dashboard.html +0 -372
  215. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  216. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  217. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  218. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  219. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  220. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  221. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  222. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  223. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  224. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  225. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  226. claude_mpm/scripts/mcp_server.py +0 -75
  227. claude_mpm/scripts/mcp_wrapper.py +0 -39
  228. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  229. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  230. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  231. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  232. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  233. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  234. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  235. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  236. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  237. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  238. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  239. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  240. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  241. claude_mpm/services/mcp_gateway/main.py +0 -589
  242. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  243. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  244. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  245. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  246. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  247. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  248. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  249. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  250. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  251. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  252. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  253. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  254. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  255. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  256. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  257. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  258. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  259. claude_mpm-5.0.9.dist-info/entry_points.txt +0 -10
  260. claude_mpm-5.0.9.dist-info/licenses/LICENSE +0 -21
  261. /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
  262. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/WHEEL +0 -0
  263. {claude_mpm-5.0.9.dist-info → claude_mpm-5.4.41.dist-info}/top_level.txt +0 -0
@@ -1,489 +0,0 @@
1
- """
2
- MCP Tool Registry Implementation
3
- =================================
4
-
5
- Comprehensive tool registry system for managing MCP tools.
6
- Provides registration, discovery, and invocation capabilities.
7
-
8
- Part of ISS-0035: MCP Server Implementation - Core Server and Tool Registry
9
- """
10
-
11
- import asyncio
12
- import re
13
- import traceback
14
- from datetime import datetime, timezone
15
- from threading import RLock
16
- from typing import Any, Dict, List, Optional, Set
17
-
18
- from claude_mpm.services.mcp_gateway.core.base import BaseMCPService
19
- from claude_mpm.services.mcp_gateway.core.interfaces import (
20
- IMCPToolAdapter,
21
- IMCPToolRegistry,
22
- MCPToolDefinition,
23
- MCPToolInvocation,
24
- MCPToolResult,
25
- )
26
-
27
-
28
- class ToolRegistry(BaseMCPService, IMCPToolRegistry):
29
- """
30
- Thread-safe tool registry implementation.
31
-
32
- WHY: We need a centralized registry to manage all MCP tools, ensuring
33
- thread safety for concurrent access, efficient tool discovery, and
34
- proper lifecycle management.
35
-
36
- DESIGN DECISIONS:
37
- - Use RLock for thread safety to allow recursive locking
38
- - Maintain both adapters and definitions for fast access
39
- - Implement caching for frequently used tools
40
- - Track metrics for monitoring and optimization
41
- - Support pattern-based search for tool discovery
42
- """
43
-
44
- def __init__(self):
45
- """Initialize the tool registry."""
46
- super().__init__("ToolRegistry")
47
-
48
- # Thread safety
49
- self._lock = RLock()
50
-
51
- # Tool storage
52
- self._adapters: Dict[str, IMCPToolAdapter] = {}
53
- self._definitions: Dict[str, MCPToolDefinition] = {}
54
-
55
- # Tool categories for organization
56
- self._categories: Dict[str, Set[str]] = {
57
- "system": set(),
58
- "user": set(),
59
- "builtin": set(),
60
- "external": set(),
61
- }
62
-
63
- # Metrics
64
- self._metrics = {
65
- "total_tools": 0,
66
- "invocations": {}, # Per-tool invocation counts
67
- "errors": {}, # Per-tool error counts
68
- "last_invocation": {}, # Per-tool last invocation time
69
- "registration_time": {}, # Per-tool registration time
70
- }
71
-
72
- # Cache for frequently used tools (LRU-style)
73
- self._cache_size = 10
74
- self._tool_cache: List[str] = []
75
-
76
- async def _do_initialize(self) -> bool:
77
- """
78
- Initialize the tool registry.
79
-
80
- Returns:
81
- True if initialization successful
82
- """
83
- try:
84
- self.log_info("Initializing tool registry")
85
-
86
- # Clear any existing data
87
- with self._lock:
88
- self._adapters.clear()
89
- self._definitions.clear()
90
- for category in self._categories.values():
91
- category.clear()
92
- self._tool_cache.clear()
93
-
94
- self.log_info("Tool registry initialized")
95
- return True
96
-
97
- except Exception as e:
98
- self.log_error(f"Failed to initialize tool registry: {e}")
99
- return False
100
-
101
- async def _do_shutdown(self) -> None:
102
- """Shutdown the tool registry and clean up resources."""
103
- self.log_info("Shutting down tool registry")
104
-
105
- # Shutdown all tool adapters
106
- with self._lock:
107
- for tool_name, adapter in self._adapters.items():
108
- try:
109
- self.log_info(f"Shutting down tool adapter: {tool_name}")
110
- await adapter.shutdown()
111
- except Exception as e:
112
- self.log_error(f"Error shutting down tool {tool_name}: {e}")
113
-
114
- # Clear all data
115
- self._adapters.clear()
116
- self._definitions.clear()
117
- for category in self._categories.values():
118
- category.clear()
119
- self._tool_cache.clear()
120
-
121
- self.log_info("Tool registry shutdown complete")
122
-
123
- def register_tool(self, adapter: IMCPToolAdapter, category: str = "user") -> bool:
124
- """
125
- Register a tool adapter.
126
-
127
- Args:
128
- adapter: Tool adapter to register
129
- category: Tool category (system, user, builtin, external)
130
-
131
- Returns:
132
- True if registration successful
133
-
134
- WHY: We validate the adapter and its definition before registration
135
- to ensure only valid tools are added to the registry.
136
- """
137
- try:
138
- # Get tool definition
139
- definition = adapter.get_definition()
140
- tool_name = definition.name
141
-
142
- self.log_info(f"Registering tool: {tool_name} (category: {category})")
143
-
144
- with self._lock:
145
- # Check if tool already registered
146
- if tool_name in self._adapters:
147
- self.log_warning(f"Tool already registered: {tool_name}")
148
- return False
149
-
150
- # Validate category
151
- if category not in self._categories:
152
- self.log_warning(f"Invalid category: {category}, using 'user'")
153
- category = "user"
154
-
155
- # Register the tool
156
- self._adapters[tool_name] = adapter
157
- self._definitions[tool_name] = definition
158
- self._categories[category].add(tool_name)
159
-
160
- # Update metrics
161
- self._metrics["total_tools"] = len(self._adapters)
162
- self._metrics["registration_time"][tool_name] = datetime.now(
163
- timezone.utc
164
- ).isoformat()
165
- self._metrics["invocations"][tool_name] = 0
166
- self._metrics["errors"][tool_name] = 0
167
-
168
- self.log_info(f"Tool registered successfully: {tool_name}")
169
- self.log_mcp_event(
170
- "tool_registered", {"tool": tool_name, "category": category}
171
- )
172
-
173
- return True
174
-
175
- except Exception as e:
176
- self.log_error(f"Failed to register tool: {e}")
177
- self.log_error(f"Traceback: {traceback.format_exc()}")
178
- return False
179
-
180
- def unregister_tool(self, tool_name: str) -> bool:
181
- """
182
- Unregister a tool by name.
183
-
184
- Args:
185
- tool_name: Name of tool to unregister
186
-
187
- Returns:
188
- True if unregistration successful
189
- """
190
- try:
191
- self.log_info(f"Unregistering tool: {tool_name}")
192
-
193
- with self._lock:
194
- # Check if tool exists
195
- if tool_name not in self._adapters:
196
- self.log_warning(f"Tool not found: {tool_name}")
197
- return False
198
-
199
- # Get the adapter for shutdown
200
- adapter = self._adapters[tool_name]
201
-
202
- # Remove from all storage
203
- del self._adapters[tool_name]
204
- del self._definitions[tool_name]
205
-
206
- # Remove from categories
207
- for category_tools in self._categories.values():
208
- category_tools.discard(tool_name)
209
-
210
- # Remove from cache
211
- if tool_name in self._tool_cache:
212
- self._tool_cache.remove(tool_name)
213
-
214
- # Update metrics
215
- self._metrics["total_tools"] = len(self._adapters)
216
-
217
- # Shutdown adapter (outside lock to avoid deadlock)
218
- try:
219
- _task = asyncio.create_task(adapter.shutdown())
220
- # Fire-and-forget shutdown during tool unregister
221
- except Exception as e:
222
- self.log_warning(f"Error shutting down tool adapter {tool_name}: {e}")
223
-
224
- self.log_info(f"Tool unregistered successfully: {tool_name}")
225
- self.log_mcp_event("tool_unregistered", {"tool": tool_name})
226
-
227
- return True
228
-
229
- except Exception as e:
230
- self.log_error(f"Failed to unregister tool {tool_name}: {e}")
231
- return False
232
-
233
- def get_tool(self, tool_name: str) -> Optional[IMCPToolAdapter]:
234
- """
235
- Get a tool adapter by name.
236
-
237
- Args:
238
- tool_name: Name of the tool
239
-
240
- Returns:
241
- Tool adapter if found, None otherwise
242
- """
243
- with self._lock:
244
- adapter = self._adapters.get(tool_name)
245
-
246
- # Update cache if tool found
247
- if adapter and tool_name not in self._tool_cache:
248
- self._update_cache(tool_name)
249
-
250
- return adapter
251
-
252
- def list_tools(self) -> List[MCPToolDefinition]:
253
- """
254
- List all registered tools.
255
-
256
- Returns:
257
- List of tool definitions
258
- """
259
- with self._lock:
260
- return list(self._definitions.values())
261
-
262
- async def invoke_tool(self, invocation: MCPToolInvocation) -> MCPToolResult:
263
- """
264
- Invoke a tool through the registry.
265
-
266
- Args:
267
- invocation: Tool invocation request
268
-
269
- Returns:
270
- Tool execution result
271
-
272
- WHY: We handle invocation through the registry to provide centralized
273
- error handling, metrics tracking, and validation.
274
- """
275
- tool_name = invocation.tool_name
276
- start_time = datetime.now(timezone.utc)
277
-
278
- try:
279
- self.log_info(f"Invoking tool: {tool_name}")
280
-
281
- # Get the adapter
282
- adapter = self.get_tool(tool_name)
283
- if not adapter:
284
- error_msg = f"Tool not found: {tool_name}"
285
- self.log_error(error_msg)
286
- return MCPToolResult(success=False, error=error_msg)
287
-
288
- # Validate parameters
289
- if not adapter.validate_parameters(invocation.parameters):
290
- error_msg = f"Invalid parameters for tool {tool_name}"
291
- self.log_error(error_msg)
292
-
293
- with self._lock:
294
- self._metrics["errors"][tool_name] = (
295
- self._metrics["errors"].get(tool_name, 0) + 1
296
- )
297
-
298
- return MCPToolResult(success=False, error=error_msg)
299
-
300
- # Invoke the tool
301
- result = await adapter.invoke(invocation)
302
-
303
- # Calculate execution time
304
- execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
305
- result.execution_time = execution_time
306
-
307
- # Update metrics
308
- with self._lock:
309
- self._metrics["invocations"][tool_name] = (
310
- self._metrics["invocations"].get(tool_name, 0) + 1
311
- )
312
- self._metrics["last_invocation"][tool_name] = datetime.now(
313
- timezone.utc
314
- ).isoformat()
315
-
316
- if not result.success:
317
- self._metrics["errors"][tool_name] = (
318
- self._metrics["errors"].get(tool_name, 0) + 1
319
- )
320
-
321
- # Log the invocation
322
- self.log_tool_invocation(tool_name, result.success, execution_time)
323
-
324
- return result
325
-
326
- except Exception as e:
327
- error_msg = f"Exception invoking tool {tool_name}: {e!s}"
328
- self.log_error(error_msg)
329
- self.log_error(f"Traceback: {traceback.format_exc()}")
330
-
331
- # Update error metrics
332
- with self._lock:
333
- self._metrics["errors"][tool_name] = (
334
- self._metrics["errors"].get(tool_name, 0) + 1
335
- )
336
-
337
- execution_time = (datetime.now(timezone.utc) - start_time).total_seconds()
338
-
339
- return MCPToolResult(
340
- success=False, error=error_msg, execution_time=execution_time
341
- )
342
-
343
- def search_tools(self, query: str) -> List[MCPToolDefinition]:
344
- """
345
- Search for tools by query.
346
-
347
- Supports:
348
- - Exact name matching
349
- - Partial name matching
350
- - Description keyword matching
351
- - Regex patterns
352
-
353
- Args:
354
- query: Search query
355
-
356
- Returns:
357
- List of matching tool definitions
358
- """
359
- try:
360
- query_lower = query.lower()
361
- matching_tools = []
362
-
363
- with self._lock:
364
- for name, definition in self._definitions.items():
365
- # Exact match
366
- if name.lower() == query_lower:
367
- matching_tools.append(definition)
368
- continue
369
-
370
- # Partial name match
371
- if query_lower in name.lower():
372
- matching_tools.append(definition)
373
- continue
374
-
375
- # Description match
376
- if query_lower in definition.description.lower():
377
- matching_tools.append(definition)
378
- continue
379
-
380
- # Try regex match
381
- try:
382
- if re.search(query, name, re.IGNORECASE):
383
- matching_tools.append(definition)
384
- continue
385
- except re.error:
386
- # Not a valid regex, skip
387
- pass
388
-
389
- self.log_info(
390
- f"Search query '{query}' returned {len(matching_tools)} tools"
391
- )
392
- return matching_tools
393
-
394
- except Exception as e:
395
- self.log_error(f"Error searching tools: {e}")
396
- return []
397
-
398
- def get_tools_by_category(self, category: str) -> List[MCPToolDefinition]:
399
- """
400
- Get all tools in a specific category.
401
-
402
- Args:
403
- category: Category name (system, user, builtin, external)
404
-
405
- Returns:
406
- List of tool definitions in the category
407
- """
408
- with self._lock:
409
- if category not in self._categories:
410
- self.log_warning(f"Invalid category: {category}")
411
- return []
412
-
413
- tool_names = self._categories[category]
414
- return [
415
- self._definitions[name]
416
- for name in tool_names
417
- if name in self._definitions
418
- ]
419
-
420
- def _update_cache(self, tool_name: str) -> None:
421
- """
422
- Update the tool cache (LRU-style).
423
-
424
- Args:
425
- tool_name: Name of tool to add to cache
426
- """
427
- # Remove if already in cache
428
- if tool_name in self._tool_cache:
429
- self._tool_cache.remove(tool_name)
430
-
431
- # Add to front
432
- self._tool_cache.insert(0, tool_name)
433
-
434
- # Trim cache if needed
435
- if len(self._tool_cache) > self._cache_size:
436
- self._tool_cache = self._tool_cache[: self._cache_size]
437
-
438
- def get_metrics(self) -> Dict[str, Any]:
439
- """
440
- Get registry metrics.
441
-
442
- Returns:
443
- Metrics dictionary
444
- """
445
- with self._lock:
446
- return {
447
- **self._metrics,
448
- "categories": {
449
- category: len(tools) for category, tools in self._categories.items()
450
- },
451
- "cached_tools": list(self._tool_cache),
452
- }
453
-
454
- def clear_metrics(self) -> None:
455
- """Clear all metrics except registration data."""
456
- with self._lock:
457
- for tool_name in self._metrics["invocations"]:
458
- self._metrics["invocations"][tool_name] = 0
459
- self._metrics["errors"][tool_name] = 0
460
- self._metrics["last_invocation"].clear()
461
-
462
- async def initialize_all_tools(self) -> Dict[str, bool]:
463
- """
464
- Initialize all registered tool adapters.
465
-
466
- Returns:
467
- Dictionary mapping tool names to initialization success
468
- """
469
- results = {}
470
-
471
- with self._lock:
472
- adapters_copy = dict(self._adapters)
473
-
474
- for tool_name, adapter in adapters_copy.items():
475
- try:
476
- self.log_info(f"Initializing tool: {tool_name}")
477
- success = await adapter.initialize()
478
- results[tool_name] = success
479
-
480
- if success:
481
- self.log_info(f"Tool initialized successfully: {tool_name}")
482
- else:
483
- self.log_warning(f"Tool initialization failed: {tool_name}")
484
-
485
- except Exception as e:
486
- self.log_error(f"Exception initializing tool {tool_name}: {e}")
487
- results[tool_name] = False
488
-
489
- return results
@@ -1,15 +0,0 @@
1
- """
2
- MCP Gateway Server Module
3
- =========================
4
-
5
- Server components for the MCP Gateway service.
6
- """
7
-
8
- from .mcp_gateway import MCPGateway
9
- from .stdio_handler import AlternativeStdioHandler, StdioHandler
10
-
11
- __all__ = [
12
- "AlternativeStdioHandler",
13
- "MCPGateway",
14
- "StdioHandler",
15
- ]