claude-mpm 5.1.9__py3-none-any.whl → 5.4.48__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 (248) 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/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +1 -1
  5. claude_mpm/agents/MEMORY.md +1 -1
  6. claude_mpm/agents/PM_INSTRUCTIONS.md +843 -900
  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 +2 -2
  11. claude_mpm/agents/templates/circuit-breakers.md +138 -1
  12. claude_mpm/cli/__main__.py +4 -0
  13. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  14. claude_mpm/cli/commands/agent_state_manager.py +18 -27
  15. claude_mpm/cli/commands/agents.py +9 -40
  16. claude_mpm/cli/commands/auto_configure.py +210 -25
  17. claude_mpm/cli/commands/config.py +88 -2
  18. claude_mpm/cli/commands/configure.py +1098 -159
  19. claude_mpm/cli/commands/configure_agent_display.py +25 -6
  20. claude_mpm/cli/commands/mpm_init/core.py +225 -46
  21. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  22. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  23. claude_mpm/cli/commands/postmortem.py +1 -1
  24. claude_mpm/cli/commands/profile.py +277 -0
  25. claude_mpm/cli/commands/skills.py +218 -197
  26. claude_mpm/cli/commands/summarize.py +413 -0
  27. claude_mpm/cli/executor.py +21 -3
  28. claude_mpm/cli/interactive/agent_wizard.py +2 -2
  29. claude_mpm/cli/parsers/agents_parser.py +0 -9
  30. claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
  31. claude_mpm/cli/parsers/base_parser.py +12 -0
  32. claude_mpm/cli/parsers/config_parser.py +153 -83
  33. claude_mpm/cli/parsers/profile_parser.py +148 -0
  34. claude_mpm/cli/parsers/skills_parser.py +0 -5
  35. claude_mpm/cli/startup.py +876 -149
  36. claude_mpm/commands/mpm-config.md +28 -0
  37. claude_mpm/commands/mpm-doctor.md +9 -22
  38. claude_mpm/commands/mpm-help.md +5 -287
  39. claude_mpm/commands/mpm-init.md +81 -507
  40. claude_mpm/commands/mpm-monitor.md +15 -402
  41. claude_mpm/commands/mpm-organize.md +120 -0
  42. claude_mpm/commands/mpm-postmortem.md +6 -108
  43. claude_mpm/commands/mpm-session-resume.md +12 -363
  44. claude_mpm/commands/mpm-status.md +5 -69
  45. claude_mpm/commands/mpm-ticket-view.md +52 -495
  46. claude_mpm/commands/mpm-version.md +5 -107
  47. claude_mpm/config/agent_sources.py +27 -0
  48. claude_mpm/core/config.py +2 -4
  49. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  50. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  51. claude_mpm/core/framework/loaders/instruction_loader.py +52 -11
  52. claude_mpm/core/framework_loader.py +4 -2
  53. claude_mpm/core/logger.py +13 -0
  54. claude_mpm/core/optimized_startup.py +59 -0
  55. claude_mpm/core/shared/config_loader.py +1 -1
  56. claude_mpm/core/socketio_pool.py +3 -3
  57. claude_mpm/core/unified_agent_registry.py +5 -15
  58. claude_mpm/dashboard/static/svelte-build/_app/env.js +1 -0
  59. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +1 -0
  60. claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +1 -0
  61. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +1 -0
  62. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +1 -0
  63. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CWc5urbQ.js +1 -0
  64. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +2 -0
  65. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DjhvlsAc.js +1 -0
  66. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/N4qtv3Hx.js +2 -0
  67. claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uj46x2Wr.js +1 -0
  68. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +2 -0
  69. claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +1 -0
  70. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/0.CAGBuiOw.js +1 -0
  71. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +1 -0
  72. claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +10 -0
  73. claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -0
  74. claude_mpm/dashboard/static/svelte-build/favicon.svg +7 -0
  75. claude_mpm/dashboard/static/svelte-build/index.html +36 -0
  76. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  77. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-311.pyc +0 -0
  78. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-311.pyc +0 -0
  79. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-311.pyc +0 -0
  80. claude_mpm/hooks/claude_hooks/__pycache__/installer.cpython-311.pyc +0 -0
  81. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-311.pyc +0 -0
  82. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-311.pyc +0 -0
  83. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-311.pyc +0 -0
  84. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  85. claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
  86. claude_mpm/hooks/claude_hooks/hook_handler.py +155 -1
  87. claude_mpm/hooks/claude_hooks/installer.py +33 -10
  88. claude_mpm/hooks/claude_hooks/memory_integration.py +26 -9
  89. claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
  90. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-311.pyc +0 -0
  91. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
  92. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-311.pyc +0 -0
  93. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-311.pyc +0 -0
  94. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-311.pyc +0 -0
  95. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-311.pyc +0 -0
  96. claude_mpm/hooks/claude_hooks/services/connection_manager.py +30 -6
  97. claude_mpm/hooks/kuzu_memory_hook.py +5 -5
  98. claude_mpm/hooks/memory_integration_hook.py +46 -1
  99. claude_mpm/init.py +63 -19
  100. claude_mpm/models/git_repository.py +3 -3
  101. claude_mpm/scripts/claude-hook-handler.sh +58 -18
  102. claude_mpm/scripts/launch_monitor.py +93 -13
  103. claude_mpm/services/agents/agent_builder.py +3 -3
  104. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  105. claude_mpm/services/agents/agent_review_service.py +280 -0
  106. claude_mpm/services/agents/cache_git_manager.py +6 -6
  107. claude_mpm/services/agents/deployment/agent_deployment.py +29 -7
  108. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -5
  109. claude_mpm/services/agents/deployment/agent_format_converter.py +23 -13
  110. claude_mpm/services/agents/deployment/agent_template_builder.py +32 -20
  111. claude_mpm/services/agents/deployment/agents_directory_resolver.py +2 -2
  112. claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
  113. claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
  114. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +247 -35
  115. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +392 -87
  116. claude_mpm/services/agents/git_source_manager.py +53 -4
  117. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  118. claude_mpm/services/agents/recommender.py +5 -3
  119. claude_mpm/services/agents/single_tier_deployment_service.py +2 -2
  120. claude_mpm/services/agents/sources/git_source_sync_service.py +120 -7
  121. claude_mpm/services/agents/startup_sync.py +22 -2
  122. claude_mpm/services/agents/toolchain_detector.py +10 -6
  123. claude_mpm/services/analysis/__init__.py +11 -1
  124. claude_mpm/services/analysis/clone_detector.py +1030 -0
  125. claude_mpm/services/command_deployment_service.py +81 -10
  126. claude_mpm/services/diagnostics/checks/agent_check.py +2 -2
  127. claude_mpm/services/diagnostics/checks/agent_sources_check.py +1 -1
  128. claude_mpm/services/event_bus/config.py +3 -1
  129. claude_mpm/services/git/git_operations_service.py +101 -16
  130. claude_mpm/services/monitor/daemon.py +9 -2
  131. claude_mpm/services/monitor/daemon_manager.py +39 -3
  132. claude_mpm/services/monitor/management/lifecycle.py +8 -1
  133. claude_mpm/services/monitor/server.py +698 -22
  134. claude_mpm/services/pm_skills_deployer.py +711 -0
  135. claude_mpm/services/profile_manager.py +331 -0
  136. claude_mpm/services/self_upgrade_service.py +120 -12
  137. claude_mpm/services/skills/__init__.py +3 -0
  138. claude_mpm/services/skills/git_skill_source_manager.py +130 -2
  139. claude_mpm/services/skills/selective_skill_deployer.py +704 -0
  140. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  141. claude_mpm/services/skills_deployer.py +127 -9
  142. claude_mpm/services/socketio/dashboard_server.py +1 -0
  143. claude_mpm/services/socketio/event_normalizer.py +51 -6
  144. claude_mpm/services/socketio/server/core.py +386 -108
  145. claude_mpm/services/version_control/git_operations.py +103 -0
  146. claude_mpm/skills/skill_manager.py +92 -3
  147. claude_mpm/utils/agent_dependency_loader.py +14 -2
  148. claude_mpm/utils/agent_filters.py +17 -44
  149. claude_mpm/utils/migration.py +4 -4
  150. claude_mpm/utils/robust_installer.py +47 -3
  151. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/METADATA +53 -87
  152. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/RECORD +157 -197
  153. claude_mpm-5.4.48.dist-info/entry_points.txt +5 -0
  154. claude_mpm-5.4.48.dist-info/licenses/LICENSE +94 -0
  155. claude_mpm-5.4.48.dist-info/licenses/LICENSE-FAQ.md +153 -0
  156. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  157. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  158. claude_mpm/agents/BASE_OPS.md +0 -219
  159. claude_mpm/agents/BASE_PM.md +0 -480
  160. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  161. claude_mpm/agents/BASE_QA.md +0 -167
  162. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  163. claude_mpm/agents/base_agent_loader.py +0 -601
  164. claude_mpm/cli/commands/agents_detect.py +0 -380
  165. claude_mpm/cli/commands/agents_recommend.py +0 -309
  166. claude_mpm/cli/ticket_cli.py +0 -35
  167. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  168. claude_mpm/commands/mpm-agents-detect.md +0 -177
  169. claude_mpm/commands/mpm-agents-list.md +0 -131
  170. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  171. claude_mpm/commands/mpm-config-view.md +0 -150
  172. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  173. claude_mpm/dashboard/analysis_runner.py +0 -455
  174. claude_mpm/dashboard/index.html +0 -13
  175. claude_mpm/dashboard/open_dashboard.py +0 -66
  176. claude_mpm/dashboard/static/css/activity.css +0 -1958
  177. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  178. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  179. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  180. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  181. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  182. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  183. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  184. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  185. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  186. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  187. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  188. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  189. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  190. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  191. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  192. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  193. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  194. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  195. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  196. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  197. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  198. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  199. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  200. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  201. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  202. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  203. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  204. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  205. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  206. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  207. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  208. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  209. claude_mpm/dashboard/templates/code_simple.html +0 -153
  210. claude_mpm/dashboard/templates/index.html +0 -606
  211. claude_mpm/dashboard/test_dashboard.html +0 -372
  212. claude_mpm/scripts/mcp_server.py +0 -75
  213. claude_mpm/scripts/mcp_wrapper.py +0 -39
  214. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  215. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  216. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  217. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  218. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  219. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  220. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  221. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  222. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  223. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  224. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  225. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  226. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  227. claude_mpm/services/mcp_gateway/main.py +0 -589
  228. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  229. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  230. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  231. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  232. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  233. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  234. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  235. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  236. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  237. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  238. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  239. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  240. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  241. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  242. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  243. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  244. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  245. claude_mpm-5.1.9.dist-info/entry_points.txt +0 -10
  246. claude_mpm-5.1.9.dist-info/licenses/LICENSE +0 -21
  247. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/WHEEL +0 -0
  248. {claude_mpm-5.1.9.dist-info → claude_mpm-5.4.48.dist-info}/top_level.txt +0 -0
@@ -1,414 +0,0 @@
1
- """
2
- MCP Gateway Implementation
3
- ==========================
4
-
5
- MCP protocol gateway using Anthropic's official MCP package.
6
- Handles stdio-based communication, request routing, and tool invocation.
7
- Acts as a bridge between Claude Code and internal tools.
8
-
9
- NOTE: MCP is ONLY for Claude Code - NOT for Claude Code.
10
- Claude Code uses a different system for agent deployment.
11
-
12
- Part of ISS-0035: MCP Gateway Implementation - Core Gateway and Tool Registry
13
- """
14
-
15
- import asyncio
16
- import contextlib
17
- import json
18
- import traceback
19
- from datetime import datetime, timezone
20
- from typing import Any, Callable, Dict, List, Optional, Union
21
-
22
- # Import from the official MCP package
23
- from mcp.server import Server
24
- from mcp.types import EmbeddedResource, ImageContent, TextContent, Tool
25
-
26
- from claude_mpm.services.mcp_gateway.core.base import BaseMCPService
27
- from claude_mpm.services.mcp_gateway.core.interfaces import (
28
- IMCPCommunication,
29
- IMCPGateway,
30
- IMCPToolRegistry,
31
- MCPToolInvocation,
32
- )
33
-
34
-
35
- class MCPGateway(BaseMCPService, IMCPGateway):
36
- """
37
- MCP Protocol Gateway implementation using Anthropic's official MCP package.
38
-
39
- WHY: We use the official MCP package to ensure protocol compliance and
40
- compatibility with Claude Code. The stdio-based communication model allows
41
- seamless integration with Claude Code's MCP client as a protocol bridge.
42
-
43
- DESIGN DECISIONS:
44
- - Use asyncio for all I/O operations to handle concurrent requests efficiently
45
- - Maintain request handlers in a dictionary for extensibility
46
- - Implement comprehensive error handling to prevent gateway crashes
47
- - Use structured logging for debugging and monitoring
48
- """
49
-
50
- def __init__(self, gateway_name: str = "claude-mpm-mcp", version: str = "1.0.0"):
51
- """
52
- Initialize MCP Gateway.
53
-
54
- Args:
55
- gateway_name: Name of the MCP gateway
56
- version: Gateway version
57
- """
58
- super().__init__(f"MCPGateway-{gateway_name}")
59
-
60
- # Gateway configuration
61
- self.gateway_name = gateway_name
62
- self.server_name = gateway_name # Keep for compatibility
63
- self.version = version
64
-
65
- # MCP Server instance from official package
66
- self.mcp_server = Server(gateway_name)
67
-
68
- # Dependencies (injected via setters)
69
- self._tool_registry: Optional[IMCPToolRegistry] = None
70
- self._communication: Optional[IMCPCommunication] = None
71
-
72
- # Request handlers
73
- self._handlers: Dict[str, Callable] = {}
74
-
75
- # Server capabilities
76
- self._capabilities = {
77
- "tools": {},
78
- "prompts": {},
79
- "resources": {},
80
- "experimental": {},
81
- }
82
-
83
- # Metrics
84
- self._metrics = {
85
- "requests_handled": 0,
86
- "errors": 0,
87
- "tool_invocations": 0,
88
- "start_time": None,
89
- "last_request_time": None,
90
- }
91
-
92
- # Running state
93
- self._run_task: Optional[asyncio.Task] = None
94
- self._shutdown_event = asyncio.Event()
95
-
96
- # Setup default handlers
97
- self._setup_default_handlers()
98
-
99
- def _setup_default_handlers(self) -> None:
100
- """
101
- Setup default MCP protocol handlers.
102
-
103
- WHY: The MCP protocol requires specific handlers for initialization,
104
- tool discovery, and tool invocation. We set these up to ensure
105
- protocol compliance.
106
- """
107
-
108
- # Initialize handler
109
- @self.mcp_server.list_tools()
110
- async def handle_list_tools() -> List[Tool]:
111
- """Handle tools/list request."""
112
- self.log_info("Handling tools/list request")
113
-
114
- if not self._tool_registry:
115
- self.log_warning("No tool registry available")
116
- return []
117
-
118
- tools = []
119
- for tool_def in self._tool_registry.list_tools():
120
- tool = Tool(
121
- name=tool_def.name,
122
- description=tool_def.description,
123
- inputSchema=tool_def.input_schema,
124
- )
125
- tools.append(tool)
126
-
127
- self.log_info(f"Returning {len(tools)} tools")
128
- return tools
129
-
130
- @self.mcp_server.call_tool()
131
- async def handle_call_tool(
132
- name: str, arguments: Dict[str, Any]
133
- ) -> List[Union[TextContent, ImageContent, EmbeddedResource]]:
134
- """Handle tools/call request."""
135
- self.log_info(f"Handling tools/call request for tool: {name}")
136
-
137
- if not self._tool_registry:
138
- error_msg = "No tool registry available"
139
- self.log_error(error_msg)
140
- return [TextContent(type="text", text=f"Error: {error_msg}")]
141
-
142
- # Create invocation request
143
- invocation = MCPToolInvocation(
144
- tool_name=name,
145
- parameters=arguments,
146
- request_id=f"req_{datetime.now(timezone.utc).timestamp()}",
147
- )
148
-
149
- try:
150
- # Invoke tool through registry
151
- result = await self._tool_registry.invoke_tool(invocation)
152
-
153
- # Update metrics
154
- self._metrics["tool_invocations"] += 1
155
-
156
- # Log invocation
157
- self.log_tool_invocation(name, result.success, result.execution_time)
158
-
159
- if result.success:
160
- # Return successful result
161
- if isinstance(result.data, str):
162
- return [TextContent(type="text", text=result.data)]
163
- return [
164
- TextContent(type="text", text=json.dumps(result.data, indent=2))
165
- ]
166
- # Return error
167
- return [TextContent(type="text", text=f"Error: {result.error}")]
168
-
169
- except Exception as e:
170
- error_msg = f"Failed to invoke tool {name}: {e!s}"
171
- self.log_error(error_msg)
172
- self._metrics["errors"] += 1
173
- return [TextContent(type="text", text=f"Error: {error_msg}")]
174
-
175
- def set_tool_registry(self, registry: IMCPToolRegistry) -> None:
176
- """
177
- Set the tool registry for the server.
178
-
179
- Args:
180
- registry: Tool registry to use
181
- """
182
- self._tool_registry = registry
183
- self.log_info("Tool registry set")
184
-
185
- def set_communication(self, communication: IMCPCommunication) -> None:
186
- """
187
- Set the communication handler.
188
-
189
- Args:
190
- communication: Communication handler to use
191
- """
192
- self._communication = communication
193
- self.log_info("Communication handler set")
194
-
195
- async def _do_initialize(self) -> bool:
196
- """
197
- Perform server initialization.
198
-
199
- Returns:
200
- True if initialization successful
201
- """
202
- try:
203
- self.log_info("Initializing MCP server components")
204
-
205
- # Validate dependencies
206
- if not self._tool_registry:
207
- self.log_warning("No tool registry set - server will have no tools")
208
-
209
- # Initialize metrics
210
- self._metrics["start_time"] = datetime.now(timezone.utc).isoformat()
211
-
212
- # Update capabilities based on registry
213
- if self._tool_registry:
214
- tools = self._tool_registry.list_tools()
215
- self._capabilities["tools"]["available"] = len(tools)
216
- self._capabilities["tools"]["names"] = [t.name for t in tools]
217
-
218
- self.log_info("MCP server initialization complete")
219
- return True
220
-
221
- except Exception as e:
222
- self.log_error(f"Failed to initialize MCP server: {e}")
223
- return False
224
-
225
- async def _do_start(self) -> bool:
226
- """
227
- Start the MCP server.
228
-
229
- Returns:
230
- True if startup successful
231
- """
232
- try:
233
- self.log_info("Starting MCP server")
234
-
235
- # Clear shutdown event
236
- self._shutdown_event.clear()
237
-
238
- # Start the run task
239
- self._run_task = asyncio.create_task(self.run())
240
-
241
- self.log_info("MCP server started successfully")
242
- return True
243
-
244
- except Exception as e:
245
- self.log_error(f"Failed to start MCP server: {e}")
246
- return False
247
-
248
- async def _do_shutdown(self) -> None:
249
- """
250
- Shutdown the MCP server gracefully.
251
- """
252
- self.log_info("Shutting down MCP server")
253
-
254
- # Signal shutdown
255
- self._shutdown_event.set()
256
-
257
- # Cancel run task if active
258
- if self._run_task and not self._run_task.done():
259
- self._run_task.cancel()
260
- with contextlib.suppress(asyncio.CancelledError):
261
- await self._run_task
262
-
263
- # Clean up resources
264
- if self._tool_registry:
265
- self.log_info("Cleaning up tool registry")
266
- # Tool registry cleanup if needed
267
-
268
- self.log_info("MCP server shutdown complete")
269
-
270
- async def handle_request(self, request: Dict[str, Any]) -> Dict[str, Any]:
271
- """
272
- Handle an MCP request.
273
-
274
- This method routes requests to appropriate handlers based on the method.
275
-
276
- Args:
277
- request: MCP request message
278
-
279
- Returns:
280
- Response message
281
- """
282
- try:
283
- # Update metrics
284
- self._metrics["requests_handled"] += 1
285
- self._metrics["last_request_time"] = datetime.now(timezone.utc).isoformat()
286
-
287
- # Extract request details
288
- method = request.get("method", "")
289
- params = request.get("params", {})
290
- request_id = request.get("id")
291
-
292
- self.log_debug(f"Handling request: {method}")
293
-
294
- # Check for custom handler
295
- if method in self._handlers:
296
- handler = self._handlers[method]
297
- result = await handler(params)
298
-
299
- # Build response
300
- response = {"jsonrpc": "2.0", "id": request_id, "result": result}
301
- else:
302
- # Unknown method
303
- self.log_warning(f"Unknown method: {method}")
304
- response = {
305
- "jsonrpc": "2.0",
306
- "id": request_id,
307
- "error": {"code": -32601, "message": f"Method not found: {method}"},
308
- }
309
-
310
- return response
311
-
312
- except Exception as e:
313
- self.log_error(f"Error handling request: {e}")
314
- self._metrics["errors"] += 1
315
-
316
- return {
317
- "jsonrpc": "2.0",
318
- "id": request.get("id"),
319
- "error": {"code": -32603, "message": f"Internal error: {e!s}"},
320
- }
321
-
322
- async def run(self) -> None:
323
- """
324
- Run the MCP server main loop.
325
-
326
- This method uses the official MCP Server's stdio-based communication
327
- to handle incoming requests from Claude Code.
328
-
329
- WHY: We use stdio (stdin/stdout) as it's the standard communication
330
- method for MCP servers in Claude Code. This ensures compatibility
331
- and allows the server to be launched as a subprocess.
332
- """
333
- try:
334
- self.log_info("Starting MCP server main loop")
335
-
336
- # Import the stdio server function
337
- from mcp.server.lowlevel import NotificationOptions
338
- from mcp.server.models import InitializationOptions
339
- from mcp.server.stdio import stdio_server
340
-
341
- # Create initialization options
342
- init_options = InitializationOptions(
343
- server_name=self.server_name,
344
- server_version=self.version,
345
- capabilities=self.mcp_server.get_capabilities(
346
- notification_options=NotificationOptions(),
347
- experimental_capabilities={},
348
- ),
349
- )
350
-
351
- # Run the MCP server with stdio transport
352
- async with stdio_server() as (read_stream, write_stream):
353
- self.log_info("MCP server stdio connection established")
354
-
355
- # Run the server
356
- await self.mcp_server.run(read_stream, write_stream, init_options)
357
-
358
- self.log_info("MCP server main loop ended")
359
-
360
- except Exception as e:
361
- self.log_error(f"Error in MCP server main loop: {e}")
362
- self.log_error(f"Traceback: {traceback.format_exc()}")
363
- self._metrics["errors"] += 1
364
- raise
365
-
366
- def register_handler(self, method: str, handler: Callable) -> None:
367
- """
368
- Register a custom request handler.
369
-
370
- Args:
371
- method: Method name to handle
372
- handler: Handler function
373
- """
374
- self._handlers[method] = handler
375
- self.log_info(f"Registered handler for method: {method}")
376
-
377
- def get_capabilities(self) -> Dict[str, Any]:
378
- """
379
- Get server capabilities.
380
-
381
- Returns:
382
- Dictionary of server capabilities formatted for MCP protocol
383
- """
384
- capabilities = {}
385
-
386
- # Add tool capabilities if registry is available
387
- if self._tool_registry:
388
- capabilities["tools"] = {}
389
-
390
- # Add experimental features
391
- capabilities["experimental"] = {}
392
-
393
- return capabilities
394
-
395
- def get_metrics(self) -> Dict[str, Any]:
396
- """
397
- Get server metrics.
398
-
399
- Returns:
400
- Server metrics dictionary
401
- """
402
- return self._metrics.copy()
403
-
404
- async def stop(self) -> None:
405
- """
406
- Stop the MCP service gracefully.
407
-
408
- This implements the IMCPLifecycle interface method.
409
- """
410
- await self.shutdown()
411
-
412
-
413
- # Backward compatibility alias
414
- MCPServer = MCPGateway