claude-mpm 5.1.8__py3-none-any.whl → 5.4.22__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 (191) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/__init__.py +4 -0
  3. claude_mpm/agents/{PM_INSTRUCTIONS_TEACH.md → CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md} +721 -41
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +290 -34
  5. claude_mpm/agents/agent_loader.py +13 -44
  6. claude_mpm/agents/frontmatter_validator.py +68 -0
  7. claude_mpm/agents/templates/circuit-breakers.md +138 -1
  8. claude_mpm/cli/__main__.py +4 -0
  9. claude_mpm/cli/chrome_devtools_installer.py +175 -0
  10. claude_mpm/cli/commands/agent_state_manager.py +8 -17
  11. claude_mpm/cli/commands/agents.py +169 -31
  12. claude_mpm/cli/commands/auto_configure.py +210 -25
  13. claude_mpm/cli/commands/config.py +88 -2
  14. claude_mpm/cli/commands/configure.py +1111 -161
  15. claude_mpm/cli/commands/configure_agent_display.py +15 -6
  16. claude_mpm/cli/commands/mpm_init/core.py +160 -46
  17. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  18. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  19. claude_mpm/cli/commands/skills.py +214 -189
  20. claude_mpm/cli/commands/summarize.py +413 -0
  21. claude_mpm/cli/executor.py +11 -3
  22. claude_mpm/cli/parsers/agents_parser.py +54 -9
  23. claude_mpm/cli/parsers/auto_configure_parser.py +0 -138
  24. claude_mpm/cli/parsers/base_parser.py +5 -0
  25. claude_mpm/cli/parsers/config_parser.py +153 -83
  26. claude_mpm/cli/parsers/skills_parser.py +3 -2
  27. claude_mpm/cli/startup.py +550 -94
  28. claude_mpm/commands/mpm-config.md +265 -0
  29. claude_mpm/commands/mpm-help.md +14 -95
  30. claude_mpm/commands/mpm-organize.md +500 -0
  31. claude_mpm/config/agent_sources.py +27 -0
  32. claude_mpm/core/framework/formatters/content_formatter.py +3 -13
  33. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  34. claude_mpm/core/framework_loader.py +4 -2
  35. claude_mpm/core/logger.py +13 -0
  36. claude_mpm/core/output_style_manager.py +173 -43
  37. claude_mpm/core/socketio_pool.py +3 -3
  38. claude_mpm/core/unified_agent_registry.py +134 -16
  39. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  40. claude_mpm/hooks/claude_hooks/event_handlers.py +211 -78
  41. claude_mpm/hooks/claude_hooks/hook_handler.py +6 -0
  42. claude_mpm/hooks/claude_hooks/installer.py +33 -10
  43. claude_mpm/hooks/claude_hooks/memory_integration.py +26 -9
  44. claude_mpm/hooks/claude_hooks/response_tracking.py +2 -3
  45. claude_mpm/hooks/claude_hooks/services/connection_manager.py +4 -0
  46. claude_mpm/hooks/memory_integration_hook.py +46 -1
  47. claude_mpm/init.py +0 -19
  48. claude_mpm/models/agent_definition.py +7 -0
  49. claude_mpm/scripts/claude-hook-handler.sh +58 -18
  50. claude_mpm/scripts/launch_monitor.py +93 -13
  51. claude_mpm/scripts/start_activity_logging.py +0 -0
  52. claude_mpm/services/agents/agent_recommendation_service.py +278 -0
  53. claude_mpm/services/agents/agent_review_service.py +280 -0
  54. claude_mpm/services/agents/deployment/agent_discovery_service.py +2 -3
  55. claude_mpm/services/agents/deployment/agent_template_builder.py +4 -2
  56. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +188 -12
  57. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +531 -55
  58. claude_mpm/services/agents/git_source_manager.py +34 -0
  59. claude_mpm/services/agents/loading/base_agent_manager.py +1 -13
  60. claude_mpm/services/agents/sources/git_source_sync_service.py +8 -1
  61. claude_mpm/services/agents/toolchain_detector.py +10 -6
  62. claude_mpm/services/analysis/__init__.py +11 -1
  63. claude_mpm/services/analysis/clone_detector.py +1030 -0
  64. claude_mpm/services/command_deployment_service.py +81 -10
  65. claude_mpm/services/event_bus/config.py +3 -1
  66. claude_mpm/services/git/git_operations_service.py +93 -8
  67. claude_mpm/services/monitor/daemon.py +9 -2
  68. claude_mpm/services/monitor/daemon_manager.py +39 -3
  69. claude_mpm/services/monitor/server.py +225 -19
  70. claude_mpm/services/self_upgrade_service.py +120 -12
  71. claude_mpm/services/skills/__init__.py +3 -0
  72. claude_mpm/services/skills/git_skill_source_manager.py +32 -2
  73. claude_mpm/services/skills/selective_skill_deployer.py +704 -0
  74. claude_mpm/services/skills/skill_to_agent_mapper.py +406 -0
  75. claude_mpm/services/skills_deployer.py +126 -9
  76. claude_mpm/services/socketio/event_normalizer.py +15 -1
  77. claude_mpm/services/socketio/server/core.py +160 -21
  78. claude_mpm/services/version_control/git_operations.py +103 -0
  79. claude_mpm/utils/agent_filters.py +17 -44
  80. {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.dist-info}/METADATA +47 -84
  81. {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.dist-info}/RECORD +86 -176
  82. claude_mpm-5.4.22.dist-info/entry_points.txt +5 -0
  83. claude_mpm-5.4.22.dist-info/licenses/LICENSE +94 -0
  84. claude_mpm-5.4.22.dist-info/licenses/LICENSE-FAQ.md +153 -0
  85. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +0 -292
  86. claude_mpm/agents/BASE_DOCUMENTATION.md +0 -53
  87. claude_mpm/agents/BASE_ENGINEER.md +0 -658
  88. claude_mpm/agents/BASE_OPS.md +0 -219
  89. claude_mpm/agents/BASE_PM.md +0 -480
  90. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +0 -787
  91. claude_mpm/agents/BASE_QA.md +0 -167
  92. claude_mpm/agents/BASE_RESEARCH.md +0 -53
  93. claude_mpm/agents/base_agent.json +0 -31
  94. claude_mpm/agents/base_agent_loader.py +0 -601
  95. claude_mpm/cli/commands/agents_detect.py +0 -380
  96. claude_mpm/cli/commands/agents_recommend.py +0 -309
  97. claude_mpm/cli/ticket_cli.py +0 -35
  98. claude_mpm/commands/mpm-agents-auto-configure.md +0 -278
  99. claude_mpm/commands/mpm-agents-detect.md +0 -177
  100. claude_mpm/commands/mpm-agents-list.md +0 -131
  101. claude_mpm/commands/mpm-agents-recommend.md +0 -223
  102. claude_mpm/commands/mpm-config-view.md +0 -150
  103. claude_mpm/commands/mpm-ticket-organize.md +0 -304
  104. claude_mpm/dashboard/analysis_runner.py +0 -455
  105. claude_mpm/dashboard/index.html +0 -13
  106. claude_mpm/dashboard/open_dashboard.py +0 -66
  107. claude_mpm/dashboard/static/css/activity.css +0 -1958
  108. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  109. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  110. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  111. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  112. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  113. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  114. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  115. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  116. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  117. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  118. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  119. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  120. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  121. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  122. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  123. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  124. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  125. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  126. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  127. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  128. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  129. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  130. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  131. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  132. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  133. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  134. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  135. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  136. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  137. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  138. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  139. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  140. claude_mpm/dashboard/templates/code_simple.html +0 -153
  141. claude_mpm/dashboard/templates/index.html +0 -606
  142. claude_mpm/dashboard/test_dashboard.html +0 -372
  143. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  144. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  145. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  146. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  147. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  148. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  149. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  150. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  151. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  152. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  153. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  154. claude_mpm/scripts/mcp_server.py +0 -75
  155. claude_mpm/scripts/mcp_wrapper.py +0 -39
  156. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  157. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  158. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  159. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  160. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  161. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  162. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  163. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  164. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  165. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  166. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -977
  167. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  168. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  169. claude_mpm/services/mcp_gateway/main.py +0 -589
  170. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  171. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  172. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  173. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  174. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  175. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  176. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  177. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  178. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  179. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  180. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  181. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  182. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  183. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  184. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  185. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  186. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  187. claude_mpm-5.1.8.dist-info/entry_points.txt +0 -10
  188. claude_mpm-5.1.8.dist-info/licenses/LICENSE +0 -21
  189. /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
  190. {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.dist-info}/WHEEL +0 -0
  191. {claude_mpm-5.1.8.dist-info → claude_mpm-5.4.22.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