claude-mpm 4.0.28__py3-none-any.whl → 4.0.30__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +48 -3
  2. claude_mpm/agents/BASE_PM.md +20 -15
  3. claude_mpm/agents/INSTRUCTIONS.md +12 -2
  4. claude_mpm/agents/templates/agent-manager.json +24 -0
  5. claude_mpm/agents/templates/agent-manager.md +304 -0
  6. claude_mpm/agents/templates/documentation.json +16 -3
  7. claude_mpm/agents/templates/engineer.json +19 -5
  8. claude_mpm/agents/templates/ops.json +19 -5
  9. claude_mpm/agents/templates/qa.json +16 -3
  10. claude_mpm/agents/templates/refactoring_engineer.json +25 -7
  11. claude_mpm/agents/templates/research.json +19 -5
  12. claude_mpm/cli/__init__.py +4 -0
  13. claude_mpm/cli/commands/__init__.py +4 -0
  14. claude_mpm/cli/commands/agent_manager.py +521 -0
  15. claude_mpm/cli/commands/agents.py +2 -1
  16. claude_mpm/cli/commands/cleanup.py +1 -1
  17. claude_mpm/cli/commands/doctor.py +209 -0
  18. claude_mpm/cli/commands/mcp.py +3 -3
  19. claude_mpm/cli/commands/mcp_install_commands.py +12 -30
  20. claude_mpm/cli/commands/mcp_server_commands.py +9 -9
  21. claude_mpm/cli/commands/memory.py +1 -1
  22. claude_mpm/cli/commands/run.py +31 -2
  23. claude_mpm/cli/commands/run_config_checker.py +1 -1
  24. claude_mpm/cli/parsers/agent_manager_parser.py +247 -0
  25. claude_mpm/cli/parsers/base_parser.py +12 -1
  26. claude_mpm/cli/parsers/mcp_parser.py +1 -1
  27. claude_mpm/cli/parsers/run_parser.py +1 -1
  28. claude_mpm/cli/shared/__init__.py +1 -1
  29. claude_mpm/cli/startup_logging.py +463 -0
  30. claude_mpm/constants.py +2 -0
  31. claude_mpm/core/claude_runner.py +81 -2
  32. claude_mpm/core/constants.py +2 -2
  33. claude_mpm/core/framework_loader.py +45 -11
  34. claude_mpm/core/interactive_session.py +82 -3
  35. claude_mpm/core/output_style_manager.py +6 -6
  36. claude_mpm/core/socketio_pool.py +2 -2
  37. claude_mpm/core/unified_paths.py +128 -0
  38. claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
  39. claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
  40. claude_mpm/dashboard/static/built/dashboard.js +1 -1
  41. claude_mpm/dashboard/static/built/socket-client.js +1 -1
  42. claude_mpm/dashboard/static/css/dashboard.css +170 -0
  43. claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
  44. claude_mpm/dashboard/static/dist/dashboard.js +1 -1
  45. claude_mpm/dashboard/static/dist/socket-client.js +1 -1
  46. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +21 -3
  47. claude_mpm/dashboard/static/js/components/module-viewer.js +129 -1
  48. claude_mpm/dashboard/static/js/dashboard.js +116 -0
  49. claude_mpm/dashboard/static/js/socket-client.js +0 -1
  50. claude_mpm/hooks/claude_hooks/connection_pool.py +1 -1
  51. claude_mpm/hooks/claude_hooks/hook_handler.py +1 -1
  52. claude_mpm/scripts/mcp_server.py +2 -2
  53. claude_mpm/services/agents/agent_builder.py +455 -0
  54. claude_mpm/services/agents/deployment/agent_template_builder.py +10 -3
  55. claude_mpm/services/agents/deployment/agent_validator.py +1 -0
  56. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +69 -1
  57. claude_mpm/services/diagnostics/__init__.py +18 -0
  58. claude_mpm/services/diagnostics/checks/__init__.py +30 -0
  59. claude_mpm/services/diagnostics/checks/agent_check.py +319 -0
  60. claude_mpm/services/diagnostics/checks/base_check.py +64 -0
  61. claude_mpm/services/diagnostics/checks/claude_desktop_check.py +283 -0
  62. claude_mpm/services/diagnostics/checks/common_issues_check.py +354 -0
  63. claude_mpm/services/diagnostics/checks/configuration_check.py +300 -0
  64. claude_mpm/services/diagnostics/checks/filesystem_check.py +233 -0
  65. claude_mpm/services/diagnostics/checks/installation_check.py +255 -0
  66. claude_mpm/services/diagnostics/checks/mcp_check.py +315 -0
  67. claude_mpm/services/diagnostics/checks/monitor_check.py +282 -0
  68. claude_mpm/services/diagnostics/checks/startup_log_check.py +322 -0
  69. claude_mpm/services/diagnostics/diagnostic_runner.py +247 -0
  70. claude_mpm/services/diagnostics/doctor_reporter.py +283 -0
  71. claude_mpm/services/diagnostics/models.py +120 -0
  72. claude_mpm/services/mcp_gateway/core/interfaces.py +1 -1
  73. claude_mpm/services/mcp_gateway/main.py +1 -1
  74. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +3 -3
  75. claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
  76. claude_mpm/services/mcp_gateway/server/stdio_server.py +3 -3
  77. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +2 -2
  78. claude_mpm/services/memory/__init__.py +2 -0
  79. claude_mpm/services/socketio/handlers/connection.py +27 -33
  80. claude_mpm/services/socketio/handlers/registry.py +39 -7
  81. claude_mpm/services/socketio/server/core.py +72 -22
  82. claude_mpm/validation/frontmatter_validator.py +1 -1
  83. {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/METADATA +4 -1
  84. {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/RECORD +89 -67
  85. /claude_mpm/cli/shared/{command_base.py → base_command.py} +0 -0
  86. {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/WHEEL +0 -0
  87. {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/entry_points.txt +0 -0
  88. {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/licenses/LICENSE +0 -0
  89. {claude_mpm-4.0.28.dist-info → claude_mpm-4.0.30.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,283 @@
1
+ """
2
+ Reporter for formatting and displaying diagnostic results.
3
+
4
+ WHY: Provide clear, actionable output from diagnostic checks with proper
5
+ formatting for terminal display and JSON export.
6
+ """
7
+
8
+ import json
9
+ import sys
10
+ from typing import Dict, List, Optional
11
+
12
+ from .models import DiagnosticResult, DiagnosticStatus, DiagnosticSummary
13
+
14
+
15
+ class DoctorReporter:
16
+ """Format and display diagnostic results.
17
+
18
+ WHY: Consistent, user-friendly output that clearly shows system health
19
+ status and provides actionable fixes for any issues.
20
+ """
21
+
22
+ # Status symbols and colors
23
+ STATUS_SYMBOLS = {
24
+ DiagnosticStatus.OK: "✅",
25
+ DiagnosticStatus.WARNING: "⚠️ ",
26
+ DiagnosticStatus.ERROR: "❌",
27
+ DiagnosticStatus.SKIPPED: "⏭️ "
28
+ }
29
+
30
+ # ANSI color codes
31
+ COLORS = {
32
+ "reset": "\033[0m",
33
+ "bold": "\033[1m",
34
+ "red": "\033[91m",
35
+ "green": "\033[92m",
36
+ "yellow": "\033[93m",
37
+ "blue": "\033[94m",
38
+ "gray": "\033[90m"
39
+ }
40
+
41
+ def __init__(self, use_color: bool = True, verbose: bool = False):
42
+ """Initialize reporter.
43
+
44
+ Args:
45
+ use_color: Whether to use ANSI color codes
46
+ verbose: Whether to include detailed information
47
+ """
48
+ self.use_color = use_color and sys.stdout.isatty()
49
+ self.verbose = verbose
50
+
51
+ def report(self, summary: DiagnosticSummary, format: str = "terminal"):
52
+ """Generate and output diagnostic report.
53
+
54
+ Args:
55
+ summary: DiagnosticSummary with all results
56
+ format: Output format ("terminal", "json", "markdown")
57
+ """
58
+ if format == "json":
59
+ self._report_json(summary)
60
+ elif format == "markdown":
61
+ self._report_markdown(summary)
62
+ else:
63
+ self._report_terminal(summary)
64
+
65
+ def _report_terminal(self, summary: DiagnosticSummary):
66
+ """Generate terminal-formatted report."""
67
+ # Header
68
+ self._print_header()
69
+
70
+ # Results by category
71
+ for result in summary.results:
72
+ self._print_result(result)
73
+
74
+ # Summary
75
+ self._print_summary(summary)
76
+
77
+ # Fix suggestions
78
+ self._print_fixes(summary)
79
+
80
+ def _print_header(self):
81
+ """Print report header."""
82
+ print()
83
+ print(self._color("Claude MPM Doctor Report", "bold"))
84
+ print("=" * 40)
85
+ print()
86
+
87
+ def _print_result(self, result: DiagnosticResult, indent: int = 0):
88
+ """Print a single diagnostic result."""
89
+ indent_str = " " * indent
90
+
91
+ # Status symbol and category
92
+ symbol = self.STATUS_SYMBOLS.get(result.status, "?")
93
+ color = self._get_status_color(result.status)
94
+
95
+ # Main result line
96
+ line = f"{indent_str}{symbol} {result.category}: "
97
+
98
+ if result.status == DiagnosticStatus.OK:
99
+ line += self._color("OK", color)
100
+ elif result.status == DiagnosticStatus.WARNING:
101
+ line += self._color("Warning", color)
102
+ elif result.status == DiagnosticStatus.ERROR:
103
+ line += self._color("Error", color)
104
+ else:
105
+ line += self._color("Skipped", color)
106
+
107
+ print(line)
108
+
109
+ # Message
110
+ message_indent = " " + indent_str
111
+ print(f"{message_indent}{result.message}")
112
+
113
+ # Details (in verbose mode)
114
+ if self.verbose and result.details:
115
+ for key, value in result.details.items():
116
+ if key not in ["error", "issues"]: # Skip complex fields
117
+ print(f"{message_indent}{self._color(key, 'gray')}: {value}")
118
+
119
+ # Fix suggestion
120
+ if result.fix_command:
121
+ fix_indent = " " + indent_str
122
+ print(f"{fix_indent}{self._color('→ Fix:', 'blue')} Run '{result.fix_command}'")
123
+ if result.fix_description:
124
+ print(f"{fix_indent} {self._color(result.fix_description, 'gray')}")
125
+
126
+ # Sub-results (in verbose mode)
127
+ if self.verbose and result.sub_results:
128
+ for sub_result in result.sub_results:
129
+ self._print_result(sub_result, indent + 1)
130
+
131
+ if indent == 0:
132
+ print() # Extra line between top-level results
133
+
134
+ def _print_summary(self, summary: DiagnosticSummary):
135
+ """Print summary statistics."""
136
+ print(self._color("─" * 40, "gray"))
137
+
138
+ status_line = f"Summary: "
139
+ parts = []
140
+
141
+ if summary.ok_count > 0:
142
+ parts.append(self._color(f"{summary.ok_count} OK", "green"))
143
+ if summary.warning_count > 0:
144
+ parts.append(self._color(f"{summary.warning_count} Warning{'s' if summary.warning_count != 1 else ''}", "yellow"))
145
+ if summary.error_count > 0:
146
+ parts.append(self._color(f"{summary.error_count} Error{'s' if summary.error_count != 1 else ''}", "red"))
147
+ if summary.skipped_count > 0:
148
+ parts.append(self._color(f"{summary.skipped_count} Skipped", "gray"))
149
+
150
+ status_line += " | ".join(parts)
151
+ print(status_line)
152
+
153
+ # Overall health
154
+ overall = summary.overall_status
155
+ if overall == DiagnosticStatus.OK:
156
+ print(self._color("\n✅ System is healthy!", "green"))
157
+ elif overall == DiagnosticStatus.WARNING:
158
+ print(self._color("\n⚠️ System has minor issues that should be addressed.", "yellow"))
159
+ else:
160
+ print(self._color("\n❌ System has critical issues that need immediate attention!", "red"))
161
+
162
+ def _print_fixes(self, summary: DiagnosticSummary):
163
+ """Print consolidated fix suggestions."""
164
+ fixes = []
165
+
166
+ for result in summary.results:
167
+ if result.fix_command and result.has_issues:
168
+ fixes.append((result.category, result.fix_command, result.fix_description))
169
+
170
+ if fixes:
171
+ print()
172
+ print(self._color("Suggested Fixes:", "bold"))
173
+ print(self._color("─" * 40, "gray"))
174
+
175
+ for i, (category, command, description) in enumerate(fixes, 1):
176
+ print(f"{i}. {category}:")
177
+ print(f" {self._color(command, 'blue')}")
178
+ if description:
179
+ print(f" {self._color(description, 'gray')}")
180
+ print()
181
+
182
+ if self.verbose:
183
+ print(self._color("Run 'claude-mpm doctor --fix' to attempt automatic fixes", "gray"))
184
+ else:
185
+ print(self._color("Run 'claude-mpm doctor --verbose' for more details", "gray"))
186
+
187
+ def _report_json(self, summary: DiagnosticSummary):
188
+ """Generate JSON-formatted report."""
189
+ output = summary.to_dict()
190
+
191
+ # Add metadata
192
+ output["metadata"] = {
193
+ "tool": "claude-mpm doctor",
194
+ "version": self._get_version(),
195
+ "verbose": self.verbose
196
+ }
197
+
198
+ # Add fix suggestions
199
+ fixes = []
200
+ for result in summary.results:
201
+ if result.fix_command and result.has_issues:
202
+ fixes.append({
203
+ "category": result.category,
204
+ "command": result.fix_command,
205
+ "description": result.fix_description
206
+ })
207
+ output["fixes"] = fixes
208
+
209
+ print(json.dumps(output, indent=2))
210
+
211
+ def _report_markdown(self, summary: DiagnosticSummary):
212
+ """Generate Markdown-formatted report."""
213
+ print("# Claude MPM Doctor Report\n")
214
+
215
+ # Summary table
216
+ print("## Summary\n")
217
+ print("| Status | Count |")
218
+ print("|--------|-------|")
219
+ print(f"| ✅ OK | {summary.ok_count} |")
220
+ print(f"| ⚠️ Warning | {summary.warning_count} |")
221
+ print(f"| ❌ Error | {summary.error_count} |")
222
+ print(f"| ⏭️ Skipped | {summary.skipped_count} |")
223
+ print()
224
+
225
+ # Detailed results
226
+ print("## Diagnostic Results\n")
227
+
228
+ for result in summary.results:
229
+ symbol = self.STATUS_SYMBOLS.get(result.status, "?")
230
+ print(f"### {symbol} {result.category}\n")
231
+ print(f"**Status:** {result.status.value}")
232
+ print(f"**Message:** {result.message}\n")
233
+
234
+ if result.fix_command:
235
+ print(f"**Fix:** `{result.fix_command}`")
236
+ if result.fix_description:
237
+ print(f"_{result.fix_description}_\n")
238
+
239
+ if self.verbose and result.details:
240
+ print("**Details:**")
241
+ for key, value in result.details.items():
242
+ print(f"- {key}: {value}")
243
+ print()
244
+
245
+ # Fixes section
246
+ fixes = [(r.category, r.fix_command, r.fix_description)
247
+ for r in summary.results if r.fix_command and r.has_issues]
248
+
249
+ if fixes:
250
+ print("## Suggested Fixes\n")
251
+ for category, command, description in fixes:
252
+ print(f"- **{category}:** `{command}`")
253
+ if description:
254
+ print(f" - {description}")
255
+ print()
256
+
257
+ def _color(self, text: str, color: str) -> str:
258
+ """Apply color to text if colors are enabled."""
259
+ if not self.use_color:
260
+ return text
261
+
262
+ color_code = self.COLORS.get(color, "")
263
+ reset_code = self.COLORS["reset"]
264
+ return f"{color_code}{text}{reset_code}"
265
+
266
+ def _get_status_color(self, status: DiagnosticStatus) -> str:
267
+ """Get color for a status."""
268
+ color_map = {
269
+ DiagnosticStatus.OK: "green",
270
+ DiagnosticStatus.WARNING: "yellow",
271
+ DiagnosticStatus.ERROR: "red",
272
+ DiagnosticStatus.SKIPPED: "gray"
273
+ }
274
+ return color_map.get(status, "reset")
275
+
276
+ def _get_version(self) -> str:
277
+ """Get claude-mpm version."""
278
+ try:
279
+ from ..version_service import VersionService
280
+ service = VersionService()
281
+ return service.get_version()
282
+ except Exception:
283
+ return "unknown"
@@ -0,0 +1,120 @@
1
+ """
2
+ Data models for the diagnostic system.
3
+
4
+ WHY: Define clear data structures for diagnostic results to ensure
5
+ consistency across all checks and reporting.
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+ from enum import Enum
10
+ from typing import Any, Dict, List, Optional
11
+
12
+
13
+ class DiagnosticStatus(Enum):
14
+ """Status levels for diagnostic results."""
15
+ OK = "ok"
16
+ WARNING = "warning"
17
+ ERROR = "error"
18
+ SKIPPED = "skipped"
19
+
20
+
21
+ @dataclass
22
+ class DiagnosticResult:
23
+ """Result from a diagnostic check.
24
+
25
+ WHY: Standardized result format ensures consistent reporting
26
+ and makes it easy to aggregate and display results.
27
+ """
28
+ category: str # e.g., "Installation", "Agents", "MCP Server"
29
+ status: DiagnosticStatus
30
+ message: str
31
+ details: Dict[str, Any] = field(default_factory=dict)
32
+ fix_command: Optional[str] = None
33
+ fix_description: Optional[str] = None
34
+ sub_results: List['DiagnosticResult'] = field(default_factory=list)
35
+
36
+ def to_dict(self) -> Dict[str, Any]:
37
+ """Convert to dictionary for JSON serialization."""
38
+ return {
39
+ "category": self.category,
40
+ "status": self.status.value,
41
+ "message": self.message,
42
+ "details": self.details,
43
+ "fix_command": self.fix_command,
44
+ "fix_description": self.fix_description,
45
+ "sub_results": [r.to_dict() for r in self.sub_results]
46
+ }
47
+
48
+ @property
49
+ def has_issues(self) -> bool:
50
+ """Check if this result indicates any issues."""
51
+ return self.status in (DiagnosticStatus.WARNING, DiagnosticStatus.ERROR)
52
+
53
+ @property
54
+ def severity_level(self) -> int:
55
+ """Get numeric severity level for sorting."""
56
+ severity_map = {
57
+ DiagnosticStatus.OK: 0,
58
+ DiagnosticStatus.SKIPPED: 1,
59
+ DiagnosticStatus.WARNING: 2,
60
+ DiagnosticStatus.ERROR: 3
61
+ }
62
+ return severity_map.get(self.status, 0)
63
+
64
+
65
+ @dataclass
66
+ class DiagnosticSummary:
67
+ """Summary of all diagnostic results.
68
+
69
+ WHY: Provides a high-level overview of system health
70
+ and quick access to issues that need attention.
71
+ """
72
+ total_checks: int = 0
73
+ ok_count: int = 0
74
+ warning_count: int = 0
75
+ error_count: int = 0
76
+ skipped_count: int = 0
77
+ results: List[DiagnosticResult] = field(default_factory=list)
78
+
79
+ def add_result(self, result: DiagnosticResult):
80
+ """Add a result to the summary."""
81
+ self.results.append(result)
82
+ self.total_checks += 1
83
+
84
+ if result.status == DiagnosticStatus.OK:
85
+ self.ok_count += 1
86
+ elif result.status == DiagnosticStatus.WARNING:
87
+ self.warning_count += 1
88
+ elif result.status == DiagnosticStatus.ERROR:
89
+ self.error_count += 1
90
+ elif result.status == DiagnosticStatus.SKIPPED:
91
+ self.skipped_count += 1
92
+
93
+ @property
94
+ def has_issues(self) -> bool:
95
+ """Check if there are any warnings or errors."""
96
+ return self.warning_count > 0 or self.error_count > 0
97
+
98
+ @property
99
+ def overall_status(self) -> DiagnosticStatus:
100
+ """Get overall system status."""
101
+ if self.error_count > 0:
102
+ return DiagnosticStatus.ERROR
103
+ elif self.warning_count > 0:
104
+ return DiagnosticStatus.WARNING
105
+ else:
106
+ return DiagnosticStatus.OK
107
+
108
+ def to_dict(self) -> Dict[str, Any]:
109
+ """Convert to dictionary for JSON serialization."""
110
+ return {
111
+ "summary": {
112
+ "total_checks": self.total_checks,
113
+ "ok": self.ok_count,
114
+ "warnings": self.warning_count,
115
+ "errors": self.error_count,
116
+ "skipped": self.skipped_count,
117
+ "overall_status": self.overall_status.value
118
+ },
119
+ "results": [r.to_dict() for r in self.results]
120
+ }
@@ -413,7 +413,7 @@ class IMCPGateway(IMCPLifecycle):
413
413
  Main interface for MCP gateway implementation.
414
414
 
415
415
  Orchestrates tool registry, communication, and request handling.
416
- Acts as a protocol bridge between Claude Desktop and internal tools.
416
+ Acts as a protocol bridge between Claude Code and internal tools.
417
417
  """
418
418
 
419
419
  @abstractmethod
@@ -442,7 +442,7 @@ Examples:
442
442
  # Run with debug logging
443
443
  python -m claude_mpm.services.mcp_gateway.main --debug
444
444
 
445
- # Run as MCP server for Claude Desktop
445
+ # Run as MCP server for Claude Code
446
446
  python -m claude_mpm.services.mcp_gateway.main --stdio
447
447
  """,
448
448
  )
@@ -6,8 +6,8 @@ MCP protocol gateway using Anthropic's official MCP package.
6
6
  Handles stdio-based communication, request routing, and tool invocation.
7
7
  Acts as a bridge between Claude Code and internal tools.
8
8
 
9
- NOTE: MCP is ONLY for Claude Code - NOT for Claude Desktop.
10
- Claude Desktop uses a different system for agent deployment.
9
+ NOTE: MCP is ONLY for Claude Code - NOT for Claude Code.
10
+ Claude Code uses a different system for agent deployment.
11
11
 
12
12
  Part of ISS-0035: MCP Gateway Implementation - Core Gateway and Tool Registry
13
13
  """
@@ -339,7 +339,7 @@ class MCPGateway(BaseMCPService, IMCPGateway):
339
339
  to handle incoming requests from Claude Code.
340
340
 
341
341
  WHY: We use stdio (stdin/stdout) as it's the standard communication
342
- method for MCP servers in Claude Desktop. This ensures compatibility
342
+ method for MCP servers in Claude Code. This ensures compatibility
343
343
  and allows the server to be launched as a subprocess.
344
344
  """
345
345
  try:
@@ -24,7 +24,7 @@ class StdioHandler(BaseMCPService, IMCPCommunication):
24
24
  STDIO-based communication handler for MCP.
25
25
 
26
26
  WHY: The MCP protocol uses stdio (stdin/stdout) for communication between
27
- Claude Desktop and MCP servers. This handler manages the low-level
27
+ Claude Code and MCP servers. This handler manages the low-level
28
28
  message exchange, ensuring proper JSON-RPC formatting and error handling.
29
29
 
30
30
  DESIGN DECISIONS:
@@ -3,7 +3,7 @@ Simplified MCP Stdio Server
3
3
  ============================
4
4
 
5
5
  A proper stdio-based MCP server that communicates via JSON-RPC over stdin/stdout.
6
- This server is spawned on-demand by Claude Desktop/Code and exits when the connection closes.
6
+ This server is spawned on-demand by Claude Code/Code and exits when the connection closes.
7
7
 
8
8
  WHY: MCP servers should be simple stdio-based processes that Claude can spawn and control.
9
9
  They should NOT run as persistent background services with lock files.
@@ -45,7 +45,7 @@ def apply_backward_compatibility_patches():
45
45
  Apply backward compatibility patches for MCP protocol differences.
46
46
 
47
47
  This function patches the MCP Server to handle missing clientInfo
48
- in initialize requests from older Claude Desktop versions.
48
+ in initialize requests from older Claude Code versions.
49
49
  """
50
50
  try:
51
51
  from mcp.server import Server
@@ -114,7 +114,7 @@ class SimpleMCPServer:
114
114
  A simple stdio-based MCP server implementation.
115
115
 
116
116
  WHY: This server follows the MCP specification for stdio communication,
117
- making it compatible with Claude Desktop/Code's MCP client.
117
+ making it compatible with Claude Code/Code's MCP client.
118
118
 
119
119
  DESIGN DECISIONS:
120
120
  - No persistent state or lock files
@@ -3,9 +3,9 @@ MCP Tool Adapters for aitrackdown Ticket Management
3
3
  ====================================================
4
4
 
5
5
  Provides MCP tool wrappers for common aitrackdown operations, enabling
6
- ticket management through Claude Desktop's MCP interface.
6
+ ticket management through Claude Code's MCP interface.
7
7
 
8
- WHY: These tools allow Claude Desktop to interact with aitrackdown for
8
+ WHY: These tools allow Claude Code to interact with aitrackdown for
9
9
  ticket management without requiring direct CLI access, providing a
10
10
  seamless integration experience.
11
11
 
@@ -9,9 +9,11 @@ This module provides memory management services including:
9
9
  from .builder import MemoryBuilder
10
10
  from .optimizer import MemoryOptimizer
11
11
  from .router import MemoryRouter
12
+ from .indexed_memory import IndexedMemoryService
12
13
 
13
14
  __all__ = [
14
15
  "MemoryBuilder",
15
16
  "MemoryRouter",
16
17
  "MemoryOptimizer",
18
+ "IndexedMemoryService",
17
19
  ]
@@ -27,59 +27,53 @@ def timeout_handler(timeout_seconds: float = 5.0):
27
27
  """
28
28
  def decorator(func: Callable) -> Callable:
29
29
  @functools.wraps(func)
30
- async def wrapper(self, *args, **kwargs):
30
+ async def wrapper(*args, **kwargs):
31
31
  handler_name = func.__name__
32
32
  start_time = time.time()
33
33
 
34
34
  try:
35
35
  # Create a task with timeout
36
36
  result = await asyncio.wait_for(
37
- func(self, *args, **kwargs),
37
+ func(*args, **kwargs),
38
38
  timeout=timeout_seconds
39
39
  )
40
40
 
41
41
  elapsed = time.time() - start_time
42
42
  if elapsed > timeout_seconds * 0.8: # Warn if close to timeout
43
- self.logger.warning(
44
- f"⚠️ Handler {handler_name} took {elapsed:.2f}s "
45
- f"(close to {timeout_seconds}s timeout)"
46
- )
43
+ # Try to get logger from closure scope or fallback to print
44
+ try:
45
+ import logging
46
+ logger = logging.getLogger(__name__)
47
+ logger.warning(
48
+ f"⚠️ Handler {handler_name} took {elapsed:.2f}s "
49
+ f"(close to {timeout_seconds}s timeout)"
50
+ )
51
+ except:
52
+ print(f"⚠️ Handler {handler_name} took {elapsed:.2f}s (close to {timeout_seconds}s timeout)")
47
53
 
48
54
  return result
49
55
 
50
56
  except asyncio.TimeoutError:
51
57
  elapsed = time.time() - start_time
52
- self.logger.error(
53
- f"❌ Handler {handler_name} timed out after {elapsed:.2f}s"
54
- )
55
-
56
- # Try to send error response to client if we have their sid
57
- if args and isinstance(args[0], str): # First arg is usually sid
58
- sid = args[0]
59
- try:
60
- # Use a short timeout for error response
61
- await asyncio.wait_for(
62
- self.emit_to_client(
63
- sid,
64
- "error",
65
- {
66
- "message": f"Handler {handler_name} timed out",
67
- "handler": handler_name,
68
- "timeout": timeout_seconds
69
- }
70
- ),
71
- timeout=1.0
72
- )
73
- except:
74
- pass # Best effort error notification
58
+ # Try to get logger from closure scope or fallback to print
59
+ try:
60
+ import logging
61
+ logger = logging.getLogger(__name__)
62
+ logger.error(f"❌ Handler {handler_name} timed out after {elapsed:.2f}s")
63
+ except:
64
+ print(f"❌ Handler {handler_name} timed out after {elapsed:.2f}s")
75
65
 
76
66
  return None
77
67
 
78
68
  except Exception as e:
79
69
  elapsed = time.time() - start_time
80
- self.logger.error(
81
- f"❌ Handler {handler_name} failed after {elapsed:.2f}s: {e}"
82
- )
70
+ # Try to get logger from closure scope or fallback to print
71
+ try:
72
+ import logging
73
+ logger = logging.getLogger(__name__)
74
+ logger.error(f"❌ Handler {handler_name} failed after {elapsed:.2f}s: {e}")
75
+ except:
76
+ print(f"❌ Handler {handler_name} failed after {elapsed:.2f}s: {e}")
83
77
  raise
84
78
 
85
79
  return wrapper
@@ -325,7 +319,7 @@ class ConnectionEventHandler(BaseEventHandler):
325
319
 
326
320
  @self.sio.event
327
321
  @timeout_handler(timeout_seconds=3.0)
328
- async def disconnect(sid):
322
+ async def disconnect(sid, *args):
329
323
  """Handle client disconnection.
330
324
 
331
325
  WHY: We need to clean up client tracking when they disconnect