claude-mpm 5.0.2__py3-none-any.whl → 5.4.3__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 (184) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
  3. claude_mpm/agents/PM_INSTRUCTIONS.md +1218 -905
  4. claude_mpm/agents/agent_loader.py +10 -17
  5. claude_mpm/agents/base_agent_loader.py +10 -35
  6. claude_mpm/agents/frontmatter_validator.py +68 -0
  7. claude_mpm/agents/templates/circuit-breakers.md +431 -45
  8. claude_mpm/cli/__init__.py +0 -1
  9. claude_mpm/cli/commands/__init__.py +2 -0
  10. claude_mpm/cli/commands/agent_state_manager.py +67 -23
  11. claude_mpm/cli/commands/agents.py +446 -25
  12. claude_mpm/cli/commands/auto_configure.py +535 -233
  13. claude_mpm/cli/commands/configure.py +1500 -147
  14. claude_mpm/cli/commands/configure_agent_display.py +13 -6
  15. claude_mpm/cli/commands/mpm_init/core.py +158 -1
  16. claude_mpm/cli/commands/mpm_init/knowledge_extractor.py +481 -0
  17. claude_mpm/cli/commands/mpm_init/prompts.py +280 -0
  18. claude_mpm/cli/commands/postmortem.py +401 -0
  19. claude_mpm/cli/commands/run.py +1 -39
  20. claude_mpm/cli/commands/skills.py +322 -19
  21. claude_mpm/cli/commands/summarize.py +413 -0
  22. claude_mpm/cli/executor.py +8 -0
  23. claude_mpm/cli/interactive/agent_wizard.py +302 -195
  24. claude_mpm/cli/parsers/agents_parser.py +137 -0
  25. claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
  26. claude_mpm/cli/parsers/base_parser.py +9 -0
  27. claude_mpm/cli/parsers/skills_parser.py +7 -0
  28. claude_mpm/cli/startup.py +133 -85
  29. claude_mpm/commands/mpm-agents-auto-configure.md +2 -2
  30. claude_mpm/commands/mpm-agents-list.md +2 -2
  31. claude_mpm/commands/mpm-config-view.md +2 -2
  32. claude_mpm/commands/mpm-help.md +3 -0
  33. claude_mpm/commands/{mpm-ticket-organize.md → mpm-organize.md} +4 -5
  34. claude_mpm/commands/mpm-postmortem.md +123 -0
  35. claude_mpm/commands/mpm-session-resume.md +2 -2
  36. claude_mpm/commands/mpm-ticket-view.md +2 -2
  37. claude_mpm/config/agent_presets.py +312 -82
  38. claude_mpm/config/agent_sources.py +27 -0
  39. claude_mpm/config/skill_presets.py +392 -0
  40. claude_mpm/constants.py +1 -0
  41. claude_mpm/core/claude_runner.py +2 -25
  42. claude_mpm/core/framework/loaders/agent_loader.py +8 -5
  43. claude_mpm/core/framework/loaders/file_loader.py +54 -101
  44. claude_mpm/core/interactive_session.py +19 -5
  45. claude_mpm/core/oneshot_session.py +16 -4
  46. claude_mpm/core/output_style_manager.py +173 -43
  47. claude_mpm/core/protocols/__init__.py +23 -0
  48. claude_mpm/core/protocols/runner_protocol.py +103 -0
  49. claude_mpm/core/protocols/session_protocol.py +131 -0
  50. claude_mpm/core/shared/singleton_manager.py +11 -4
  51. claude_mpm/core/socketio_pool.py +3 -3
  52. claude_mpm/core/system_context.py +38 -0
  53. claude_mpm/core/unified_agent_registry.py +134 -16
  54. claude_mpm/core/unified_config.py +22 -0
  55. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  56. claude_mpm/hooks/claude_hooks/__pycache__/correlation_manager.cpython-313.pyc +0 -0
  57. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  58. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  59. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  60. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  61. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  62. claude_mpm/hooks/claude_hooks/correlation_manager.py +60 -0
  63. claude_mpm/hooks/claude_hooks/event_handlers.py +35 -2
  64. claude_mpm/hooks/claude_hooks/hook_handler.py +4 -0
  65. claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
  66. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  67. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  68. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  69. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  70. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  71. claude_mpm/hooks/claude_hooks/services/connection_manager.py +4 -0
  72. claude_mpm/models/agent_definition.py +7 -0
  73. claude_mpm/scripts/launch_monitor.py +93 -13
  74. claude_mpm/services/agents/agent_recommendation_service.py +279 -0
  75. claude_mpm/services/agents/cache_git_manager.py +621 -0
  76. claude_mpm/services/agents/deployment/agent_template_builder.py +3 -2
  77. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +110 -3
  78. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +518 -55
  79. claude_mpm/services/agents/git_source_manager.py +20 -0
  80. claude_mpm/services/agents/sources/git_source_sync_service.py +45 -6
  81. claude_mpm/services/agents/toolchain_detector.py +6 -5
  82. claude_mpm/services/analysis/__init__.py +35 -0
  83. claude_mpm/services/analysis/clone_detector.py +1030 -0
  84. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  85. claude_mpm/services/analysis/postmortem_service.py +765 -0
  86. claude_mpm/services/command_deployment_service.py +106 -5
  87. claude_mpm/services/core/base.py +7 -2
  88. claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
  89. claude_mpm/services/event_bus/config.py +3 -1
  90. claude_mpm/services/git/git_operations_service.py +8 -8
  91. claude_mpm/services/mcp_config_manager.py +75 -145
  92. claude_mpm/services/mcp_service_verifier.py +6 -3
  93. claude_mpm/services/monitor/daemon.py +37 -10
  94. claude_mpm/services/monitor/daemon_manager.py +134 -21
  95. claude_mpm/services/monitor/server.py +225 -19
  96. claude_mpm/services/project/project_organizer.py +4 -0
  97. claude_mpm/services/runner_configuration_service.py +16 -3
  98. claude_mpm/services/session_management_service.py +16 -4
  99. claude_mpm/services/socketio/event_normalizer.py +15 -1
  100. claude_mpm/services/socketio/server/core.py +160 -21
  101. claude_mpm/services/version_control/git_operations.py +103 -0
  102. claude_mpm/utils/agent_filters.py +261 -0
  103. claude_mpm/utils/gitignore.py +3 -0
  104. claude_mpm/utils/migration.py +372 -0
  105. claude_mpm/utils/progress.py +5 -1
  106. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/METADATA +69 -84
  107. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/RECORD +112 -153
  108. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/entry_points.txt +0 -2
  109. claude_mpm/dashboard/analysis_runner.py +0 -455
  110. claude_mpm/dashboard/index.html +0 -13
  111. claude_mpm/dashboard/open_dashboard.py +0 -66
  112. claude_mpm/dashboard/static/css/activity.css +0 -1958
  113. claude_mpm/dashboard/static/css/connection-status.css +0 -370
  114. claude_mpm/dashboard/static/css/dashboard.css +0 -4701
  115. claude_mpm/dashboard/static/js/components/activity-tree.js +0 -1871
  116. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +0 -777
  117. claude_mpm/dashboard/static/js/components/agent-inference.js +0 -956
  118. claude_mpm/dashboard/static/js/components/build-tracker.js +0 -333
  119. claude_mpm/dashboard/static/js/components/code-simple.js +0 -857
  120. claude_mpm/dashboard/static/js/components/connection-debug.js +0 -654
  121. claude_mpm/dashboard/static/js/components/diff-viewer.js +0 -891
  122. claude_mpm/dashboard/static/js/components/event-processor.js +0 -542
  123. claude_mpm/dashboard/static/js/components/event-viewer.js +0 -1155
  124. claude_mpm/dashboard/static/js/components/export-manager.js +0 -368
  125. claude_mpm/dashboard/static/js/components/file-change-tracker.js +0 -443
  126. claude_mpm/dashboard/static/js/components/file-change-viewer.js +0 -690
  127. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +0 -724
  128. claude_mpm/dashboard/static/js/components/file-viewer.js +0 -580
  129. claude_mpm/dashboard/static/js/components/hud-library-loader.js +0 -211
  130. claude_mpm/dashboard/static/js/components/hud-manager.js +0 -671
  131. claude_mpm/dashboard/static/js/components/hud-visualizer.js +0 -1718
  132. claude_mpm/dashboard/static/js/components/module-viewer.js +0 -2764
  133. claude_mpm/dashboard/static/js/components/session-manager.js +0 -579
  134. claude_mpm/dashboard/static/js/components/socket-manager.js +0 -368
  135. claude_mpm/dashboard/static/js/components/ui-state-manager.js +0 -749
  136. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +0 -1824
  137. claude_mpm/dashboard/static/js/components/working-directory.js +0 -920
  138. claude_mpm/dashboard/static/js/connection-manager.js +0 -536
  139. claude_mpm/dashboard/static/js/dashboard.js +0 -1914
  140. claude_mpm/dashboard/static/js/extension-error-handler.js +0 -164
  141. claude_mpm/dashboard/static/js/socket-client.js +0 -1474
  142. claude_mpm/dashboard/static/js/tab-isolation-fix.js +0 -185
  143. claude_mpm/dashboard/static/socket.io.min.js +0 -7
  144. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +0 -7
  145. claude_mpm/dashboard/templates/code_simple.html +0 -153
  146. claude_mpm/dashboard/templates/index.html +0 -606
  147. claude_mpm/dashboard/test_dashboard.html +0 -372
  148. claude_mpm/scripts/mcp_server.py +0 -75
  149. claude_mpm/scripts/mcp_wrapper.py +0 -39
  150. claude_mpm/services/mcp_gateway/__init__.py +0 -159
  151. claude_mpm/services/mcp_gateway/auto_configure.py +0 -369
  152. claude_mpm/services/mcp_gateway/config/__init__.py +0 -17
  153. claude_mpm/services/mcp_gateway/config/config_loader.py +0 -296
  154. claude_mpm/services/mcp_gateway/config/config_schema.py +0 -243
  155. claude_mpm/services/mcp_gateway/config/configuration.py +0 -429
  156. claude_mpm/services/mcp_gateway/core/__init__.py +0 -43
  157. claude_mpm/services/mcp_gateway/core/base.py +0 -312
  158. claude_mpm/services/mcp_gateway/core/exceptions.py +0 -253
  159. claude_mpm/services/mcp_gateway/core/interfaces.py +0 -443
  160. claude_mpm/services/mcp_gateway/core/process_pool.py +0 -971
  161. claude_mpm/services/mcp_gateway/core/singleton_manager.py +0 -315
  162. claude_mpm/services/mcp_gateway/core/startup_verification.py +0 -316
  163. claude_mpm/services/mcp_gateway/main.py +0 -589
  164. claude_mpm/services/mcp_gateway/registry/__init__.py +0 -12
  165. claude_mpm/services/mcp_gateway/registry/service_registry.py +0 -412
  166. claude_mpm/services/mcp_gateway/registry/tool_registry.py +0 -489
  167. claude_mpm/services/mcp_gateway/server/__init__.py +0 -15
  168. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +0 -414
  169. claude_mpm/services/mcp_gateway/server/stdio_handler.py +0 -372
  170. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -712
  171. claude_mpm/services/mcp_gateway/tools/__init__.py +0 -36
  172. claude_mpm/services/mcp_gateway/tools/base_adapter.py +0 -485
  173. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +0 -789
  174. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +0 -654
  175. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +0 -456
  176. claude_mpm/services/mcp_gateway/tools/hello_world.py +0 -551
  177. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +0 -555
  178. claude_mpm/services/mcp_gateway/utils/__init__.py +0 -14
  179. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +0 -160
  180. claude_mpm/services/mcp_gateway/utils/update_preferences.py +0 -170
  181. /claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +0 -0
  182. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/WHEEL +0 -0
  183. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.dist-info}/licenses/LICENSE +0 -0
  184. {claude_mpm-5.0.2.dist-info → claude_mpm-5.4.3.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