@evolith/smart-cli 0.0.1-beta → 0.0.3-beta

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 (199) hide show
  1. package/ARCHITECTURE.md +667 -89
  2. package/dist/app.module.js +2 -2
  3. package/dist/app.module.js.map +1 -1
  4. package/dist/app.module.spec.d.ts +1 -0
  5. package/dist/app.module.spec.js +305 -0
  6. package/dist/app.module.spec.js.map +1 -0
  7. package/dist/application/services/index.d.ts +14 -5
  8. package/dist/application/services/index.js +41 -3
  9. package/dist/application/services/index.js.map +1 -1
  10. package/dist/application/services/phase-transition.use-case.spec.d.ts +1 -0
  11. package/dist/application/services/phase-transition.use-case.spec.js +297 -0
  12. package/dist/application/services/phase-transition.use-case.spec.js.map +1 -0
  13. package/dist/commands/adr/adr.command.spec.d.ts +1 -0
  14. package/dist/commands/adr/adr.command.spec.js +409 -0
  15. package/dist/commands/adr/adr.command.spec.js.map +1 -0
  16. package/dist/commands/architecture/scaffold.command.spec.d.ts +1 -0
  17. package/dist/commands/architecture/scaffold.command.spec.js +207 -0
  18. package/dist/commands/architecture/scaffold.command.spec.js.map +1 -0
  19. package/dist/commands/completion/completion.command.spec.d.ts +1 -0
  20. package/dist/commands/completion/completion.command.spec.js +240 -0
  21. package/dist/commands/completion/completion.command.spec.js.map +1 -0
  22. package/dist/commands/docs/docs.command.d.ts +5 -0
  23. package/dist/commands/docs/docs.command.js +159 -3
  24. package/dist/commands/docs/docs.command.js.map +1 -1
  25. package/dist/commands/docs/docs.command.spec.d.ts +1 -0
  26. package/dist/commands/docs/docs.command.spec.js +87 -0
  27. package/dist/commands/docs/docs.command.spec.js.map +1 -0
  28. package/dist/commands/drift/drift.command.d.ts +24 -0
  29. package/dist/commands/drift/drift.command.js +250 -0
  30. package/dist/commands/drift/drift.command.js.map +1 -0
  31. package/dist/commands/drift/drift.command.spec.d.ts +1 -0
  32. package/dist/commands/drift/drift.command.spec.js +327 -0
  33. package/dist/commands/drift/drift.command.spec.js.map +1 -0
  34. package/dist/commands/history/history.command.spec.d.ts +1 -0
  35. package/dist/commands/history/history.command.spec.js +392 -0
  36. package/dist/commands/history/history.command.spec.js.map +1 -0
  37. package/dist/commands/init/agents.command.spec.d.ts +1 -0
  38. package/dist/commands/init/agents.command.spec.js +550 -0
  39. package/dist/commands/init/agents.command.spec.js.map +1 -0
  40. package/dist/commands/init/init.command.spec.d.ts +1 -0
  41. package/dist/commands/init/init.command.spec.js +272 -0
  42. package/dist/commands/init/init.command.spec.js.map +1 -0
  43. package/dist/commands/init/upgrade.command.d.ts +10 -0
  44. package/dist/commands/init/upgrade.command.js +134 -1
  45. package/dist/commands/init/upgrade.command.js.map +1 -1
  46. package/dist/commands/init/upgrade.command.spec.d.ts +1 -0
  47. package/dist/commands/init/upgrade.command.spec.js +378 -0
  48. package/dist/commands/init/upgrade.command.spec.js.map +1 -0
  49. package/dist/commands/mcp/mcp-serve.command.spec.d.ts +1 -0
  50. package/dist/commands/mcp/mcp-serve.command.spec.js +58 -0
  51. package/dist/commands/mcp/mcp-serve.command.spec.js.map +1 -0
  52. package/dist/commands/sdlc/gate-status.command.d.ts +5 -0
  53. package/dist/commands/sdlc/gate-status.command.js +114 -0
  54. package/dist/commands/sdlc/gate-status.command.js.map +1 -0
  55. package/dist/commands/sdlc/generate-domain.command.spec.d.ts +1 -0
  56. package/dist/commands/sdlc/generate-domain.command.spec.js +47 -0
  57. package/dist/commands/sdlc/generate-domain.command.spec.js.map +1 -0
  58. package/dist/commands/sdlc/handoff.command.spec.d.ts +1 -0
  59. package/dist/commands/sdlc/handoff.command.spec.js +395 -0
  60. package/dist/commands/sdlc/handoff.command.spec.js.map +1 -0
  61. package/dist/commands/sdlc/sdlc.command.js +3 -1
  62. package/dist/commands/sdlc/sdlc.command.js.map +1 -1
  63. package/dist/commands/sdlc/sdlc.command.spec.d.ts +1 -0
  64. package/dist/commands/sdlc/sdlc.command.spec.js +45 -0
  65. package/dist/commands/sdlc/sdlc.command.spec.js.map +1 -0
  66. package/dist/commands/standards/standards.command.spec.d.ts +1 -0
  67. package/dist/commands/standards/standards.command.spec.js +311 -0
  68. package/dist/commands/standards/standards.command.spec.js.map +1 -0
  69. package/dist/commands/validate/validate.command.d.ts +4 -0
  70. package/dist/commands/validate/validate.command.js +39 -0
  71. package/dist/commands/validate/validate.command.js.map +1 -1
  72. package/dist/commands/validate/validate.command.spec.d.ts +1 -0
  73. package/dist/commands/validate/validate.command.spec.js +368 -0
  74. package/dist/commands/validate/validate.command.spec.js.map +1 -0
  75. package/dist/core/abstractions/providers/logger.provider.spec.d.ts +1 -0
  76. package/dist/core/abstractions/providers/logger.provider.spec.js +212 -0
  77. package/dist/core/abstractions/providers/logger.provider.spec.js.map +1 -0
  78. package/dist/core/agents/agent-ruleset-builder.d.ts +30 -0
  79. package/dist/core/agents/agent-ruleset-builder.js +75 -0
  80. package/dist/core/agents/agent-ruleset-builder.js.map +1 -0
  81. package/dist/core/agents/agent-ruleset-builder.spec.d.ts +1 -0
  82. package/dist/core/agents/agent-ruleset-builder.spec.js +135 -0
  83. package/dist/core/agents/agent-ruleset-builder.spec.js.map +1 -0
  84. package/dist/core/di/container.spec.js +164 -0
  85. package/dist/core/di/container.spec.js.map +1 -1
  86. package/dist/core/mcp/metrics.service.spec.d.ts +1 -0
  87. package/dist/core/mcp/metrics.service.spec.js +159 -0
  88. package/dist/core/mcp/metrics.service.spec.js.map +1 -0
  89. package/dist/core/mcp/prompts/index.js +36 -0
  90. package/dist/core/mcp/prompts/index.js.map +1 -1
  91. package/dist/core/mcp/prompts/index.spec.d.ts +1 -0
  92. package/dist/core/mcp/prompts/index.spec.js +150 -0
  93. package/dist/core/mcp/prompts/index.spec.js.map +1 -0
  94. package/dist/core/mcp/resources/index.js +16 -0
  95. package/dist/core/mcp/resources/index.js.map +1 -1
  96. package/dist/core/mcp/resources/index.spec.d.ts +1 -0
  97. package/dist/core/mcp/resources/index.spec.js +212 -0
  98. package/dist/core/mcp/resources/index.spec.js.map +1 -0
  99. package/dist/core/mcp/server.d.ts +15 -9
  100. package/dist/core/mcp/server.js +480 -174
  101. package/dist/core/mcp/server.js.map +1 -1
  102. package/dist/core/mcp/server.spec.d.ts +1 -0
  103. package/dist/core/mcp/server.spec.js +563 -0
  104. package/dist/core/mcp/server.spec.js.map +1 -0
  105. package/dist/core/mcp/tools/agent.spec.d.ts +1 -0
  106. package/dist/core/mcp/tools/agent.spec.js +171 -0
  107. package/dist/core/mcp/tools/agent.spec.js.map +1 -0
  108. package/dist/core/mcp/tools/architecture.d.ts +2 -0
  109. package/dist/core/mcp/tools/architecture.js +68 -0
  110. package/dist/core/mcp/tools/architecture.js.map +1 -1
  111. package/dist/core/mcp/tools/architecture.spec.d.ts +1 -0
  112. package/dist/core/mcp/tools/architecture.spec.js +145 -0
  113. package/dist/core/mcp/tools/architecture.spec.js.map +1 -0
  114. package/dist/core/mcp/tools/moscow.d.ts +30 -0
  115. package/dist/core/mcp/tools/moscow.js +113 -0
  116. package/dist/core/mcp/tools/moscow.js.map +1 -0
  117. package/dist/core/mcp/tools/moscow.spec.d.ts +1 -0
  118. package/dist/core/mcp/tools/moscow.spec.js +209 -0
  119. package/dist/core/mcp/tools/moscow.spec.js.map +1 -0
  120. package/dist/core/mcp/tools/sdlc.js +2 -1
  121. package/dist/core/mcp/tools/sdlc.js.map +1 -1
  122. package/dist/core/mcp/tools/sdlc.spec.d.ts +1 -0
  123. package/dist/core/mcp/tools/sdlc.spec.js +170 -0
  124. package/dist/core/mcp/tools/sdlc.spec.js.map +1 -0
  125. package/dist/core/mcp/tools/validate.spec.d.ts +1 -0
  126. package/dist/core/mcp/tools/validate.spec.js +130 -0
  127. package/dist/core/mcp/tools/validate.spec.js.map +1 -0
  128. package/dist/core/mcp/watcher.service.spec.js +109 -8
  129. package/dist/core/mcp/watcher.service.spec.js.map +1 -1
  130. package/dist/core/observability/error-reporter.spec.d.ts +1 -0
  131. package/dist/core/observability/error-reporter.spec.js +291 -0
  132. package/dist/core/observability/error-reporter.spec.js.map +1 -0
  133. package/dist/core/observability/structured-logger.spec.d.ts +1 -0
  134. package/dist/core/observability/structured-logger.spec.js +197 -0
  135. package/dist/core/observability/structured-logger.spec.js.map +1 -0
  136. package/dist/core/observability/timing.spec.d.ts +1 -0
  137. package/dist/core/observability/timing.spec.js +216 -0
  138. package/dist/core/observability/timing.spec.js.map +1 -0
  139. package/dist/core/services/command-history.service.spec.d.ts +1 -0
  140. package/dist/core/services/command-history.service.spec.js +166 -0
  141. package/dist/core/services/command-history.service.spec.js.map +1 -0
  142. package/dist/core/upgrade/satellite-upgrade.service.d.ts +48 -0
  143. package/dist/core/upgrade/satellite-upgrade.service.js +358 -0
  144. package/dist/core/upgrade/satellite-upgrade.service.js.map +1 -0
  145. package/dist/core/upgrade/satellite-upgrade.service.spec.d.ts +1 -0
  146. package/dist/core/upgrade/satellite-upgrade.service.spec.js +163 -0
  147. package/dist/core/upgrade/satellite-upgrade.service.spec.js.map +1 -0
  148. package/dist/core/validators/architecture-drift.service.d.ts +68 -0
  149. package/dist/core/validators/architecture-drift.service.js +266 -0
  150. package/dist/core/validators/architecture-drift.service.js.map +1 -0
  151. package/dist/core/validators/architecture-drift.service.spec.d.ts +1 -0
  152. package/dist/core/validators/architecture-drift.service.spec.js +315 -0
  153. package/dist/core/validators/architecture-drift.service.spec.js.map +1 -0
  154. package/dist/core/validators/deep-architecture-analyzer.d.ts +58 -0
  155. package/dist/core/validators/deep-architecture-analyzer.js +333 -0
  156. package/dist/core/validators/deep-architecture-analyzer.js.map +1 -0
  157. package/dist/core/validators/deep-architecture-analyzer.spec.d.ts +1 -0
  158. package/dist/core/validators/deep-architecture-analyzer.spec.js +216 -0
  159. package/dist/core/validators/deep-architecture-analyzer.spec.js.map +1 -0
  160. package/dist/core/validators/phase-gate-validator.service.d.ts +71 -0
  161. package/dist/core/validators/phase-gate-validator.service.js +273 -0
  162. package/dist/core/validators/phase-gate-validator.service.js.map +1 -0
  163. package/dist/core/validators/phase-gate-validator.service.spec.d.ts +1 -0
  164. package/dist/core/validators/phase-gate-validator.service.spec.js +326 -0
  165. package/dist/core/validators/phase-gate-validator.service.spec.js.map +1 -0
  166. package/dist/core/validators/ruleset-validator-architecture.spec.d.ts +1 -0
  167. package/dist/core/validators/ruleset-validator-architecture.spec.js +178 -0
  168. package/dist/core/validators/ruleset-validator-architecture.spec.js.map +1 -0
  169. package/dist/core/validators/ruleset-validator.service.d.ts +24 -0
  170. package/dist/core/validators/ruleset-validator.service.js +394 -0
  171. package/dist/core/validators/ruleset-validator.service.js.map +1 -1
  172. package/dist/core/validators/ruleset-validator.service.spec.js +351 -3
  173. package/dist/core/validators/ruleset-validator.service.spec.js.map +1 -1
  174. package/dist/domain/services/adr.service.spec.d.ts +1 -0
  175. package/dist/domain/services/adr.service.spec.js +141 -0
  176. package/dist/domain/services/adr.service.spec.js.map +1 -0
  177. package/dist/domain/services/agent-registry.service.spec.d.ts +1 -0
  178. package/dist/domain/services/agent-registry.service.spec.js +162 -0
  179. package/dist/domain/services/agent-registry.service.spec.js.map +1 -0
  180. package/dist/domain/services/index.d.ts +1 -0
  181. package/dist/domain/services/index.js +3 -1
  182. package/dist/domain/services/index.js.map +1 -1
  183. package/dist/domain/services/moscow-prioritization.service.d.ts +44 -0
  184. package/dist/domain/services/moscow-prioritization.service.js +213 -0
  185. package/dist/domain/services/moscow-prioritization.service.js.map +1 -0
  186. package/dist/domain/services/moscow-prioritization.service.spec.d.ts +1 -0
  187. package/dist/domain/services/moscow-prioritization.service.spec.js +285 -0
  188. package/dist/domain/services/moscow-prioritization.service.spec.js.map +1 -0
  189. package/dist/domain/services/standards.service.spec.d.ts +1 -0
  190. package/dist/domain/services/standards.service.spec.js +600 -0
  191. package/dist/domain/services/standards.service.spec.js.map +1 -0
  192. package/dist/domain/services/tool-usage-telemetry.service.spec.d.ts +1 -0
  193. package/dist/domain/services/tool-usage-telemetry.service.spec.js +180 -0
  194. package/dist/domain/services/tool-usage-telemetry.service.spec.js.map +1 -0
  195. package/dist/infrastructure/formatters/output-formatter.service.spec.d.ts +1 -0
  196. package/dist/infrastructure/formatters/output-formatter.service.spec.js +164 -0
  197. package/dist/infrastructure/formatters/output-formatter.service.spec.js.map +1 -0
  198. package/dist/main.js +0 -0
  199. package/package.json +2 -2
@@ -33,175 +33,367 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.EvolithMcpServer = void 0;
37
36
  exports.startMcpServer = startMcpServer;
38
37
  const common_1 = require("@nestjs/common");
38
+ const http = __importStar(require("node:http"));
39
39
  const ruleset_validator_service_1 = require("../validators/ruleset-validator.service");
40
40
  const validate_1 = require("./tools/validate");
41
41
  const agent_1 = require("./tools/agent");
42
42
  const architecture_1 = require("./tools/architecture");
43
43
  const sdlc_1 = require("./tools/sdlc");
44
- const resources_1 = require("./resources");
45
- const prompts_1 = require("./prompts");
44
+ const moscow_1 = require("./tools/moscow");
46
45
  const metrics_service_1 = require("./metrics.service");
47
- let ServerClass;
48
- let StdioTransportClass;
49
- let StreamableHttpTransportClass;
50
- async function loadMcpSdk() {
51
- if (ServerClass)
52
- return;
53
- try {
54
- const mcp = await Promise.resolve().then(() => __importStar(require('@modelcontextprotocol/sdk')));
55
- ServerClass = mcp.Server;
56
- StdioTransportClass = mcp.StdioServerTransport;
57
- const httpTransport = await Promise.resolve().then(() => __importStar(require('@modelcontextprotocol/sdk/server/streamableHttp')));
58
- if (httpTransport.StreamableHTTPServerTransport) {
59
- StreamableHttpTransportClass = httpTransport.StreamableHTTPServerTransport;
60
- }
46
+ class MinimalStdioTransport {
47
+ constructor(stdin, stdout) {
48
+ this.readBuffer = '';
49
+ this.stdin = stdin || process.stdin;
50
+ this.stdout = stdout || process.stdout;
51
+ this.readBuffer = '';
52
+ this.started = false;
61
53
  }
62
- catch (error) {
63
- const msg = error instanceof Error ? error.message : String(error);
64
- throw new Error(`Failed to load @modelcontextprotocol/sdk: ${msg}. Install with: npm install @modelcontextprotocol/sdk`);
54
+ async start() {
55
+ if (this.started)
56
+ return;
57
+ this.started = true;
58
+ this.stdin.on('data', (chunk) => {
59
+ this.readBuffer += chunk.toString();
60
+ let newlineIndex;
61
+ while ((newlineIndex = this.readBuffer.indexOf('\n')) !== -1) {
62
+ const line = this.readBuffer.slice(0, newlineIndex).trim();
63
+ this.readBuffer = this.readBuffer.slice(newlineIndex + 1);
64
+ if (line) {
65
+ try {
66
+ const message = JSON.parse(line);
67
+ if (this.onmessage) {
68
+ this.onmessage(message);
69
+ }
70
+ }
71
+ catch (e) {
72
+ if (this.onerror) {
73
+ this.onerror(new Error(`Invalid JSON: ${line}`));
74
+ }
75
+ }
76
+ }
77
+ }
78
+ });
79
+ this.stdin.on('end', () => {
80
+ if (this.onclose) {
81
+ this.onclose();
82
+ }
83
+ });
84
+ this.stdin.on('error', (err) => {
85
+ if (this.onerror) {
86
+ this.onerror(err);
87
+ }
88
+ });
89
+ }
90
+ async close() {
91
+ this.started = false;
92
+ }
93
+ async send(message) {
94
+ return new Promise((resolve, reject) => {
95
+ const json = JSON.stringify(message) + '\n';
96
+ this.stdout.write(json, (err) => {
97
+ if (err)
98
+ reject(err);
99
+ else
100
+ resolve();
101
+ });
102
+ });
65
103
  }
66
104
  }
67
- function validateApiKey(apiKey, validKey) {
68
- if (!validKey)
69
- return true;
70
- if (!apiKey)
71
- return false;
72
- return apiKey === validKey;
73
- }
74
- const LIST_TOOLS_REQUEST_SCHEMA = {
75
- name: 'tools/list',
76
- description: 'List available tools',
77
- };
78
- const CALL_TOOL_REQUEST_SCHEMA = {
79
- name: 'tools/call',
80
- description: 'Call a tool by name',
81
- };
82
- const LIST_RESOURCES_REQUEST_SCHEMA = {
83
- name: 'resources/list',
84
- description: 'List available resources',
85
- };
86
- const READ_RESOURCE_REQUEST_SCHEMA = {
87
- name: 'resources/read',
88
- description: 'Read a resource',
89
- };
90
- const LIST_PROMPTS_REQUEST_SCHEMA = {
91
- name: 'prompts/list',
92
- description: 'List available prompts',
93
- };
94
- const GET_PROMPT_REQUEST_SCHEMA = {
95
- name: 'prompts/get',
96
- description: 'Get a prompt template',
97
- };
98
- class EvolithMcpServer {
99
- constructor(options = {}) {
100
- this.logger = new common_1.Logger(EvolithMcpServer.name);
101
- this.serverInstance = null;
102
- this.rulesetValidator = options.rulesetValidator || new ruleset_validator_service_1.RulesetValidatorService();
103
- this.metricsService = options.metricsService || new metrics_service_1.McpMetricsService();
104
- this.apiKey = options.apiKey || process.env.EVOLITH_API_KEY;
105
- this.port = options.port || parseInt(process.env.PORT || '3000', 10);
105
+ class MinimalHttpTransport {
106
+ constructor(port, apiKey) {
107
+ this.server = null;
108
+ this.logger = new common_1.Logger(MinimalHttpTransport.name);
109
+ this.sseClients = [];
110
+ this.started = false;
111
+ this.port = port;
112
+ this.apiKey = apiKey;
106
113
  }
107
- async initialize() {
108
- await loadMcpSdk();
109
- this.serverInstance = new ServerClass({
110
- name: 'evolith-mcp-server',
111
- version: '1.0.0',
114
+ async start() {
115
+ if (this.started)
116
+ return;
117
+ this.started = true;
118
+ this.server = http.createServer((req, res) => {
119
+ this.handleRequest(req, res);
112
120
  });
113
- this.serverInstance.setRequestHandler(LIST_TOOLS_REQUEST_SCHEMA, async () => {
114
- return this.handleListTools();
121
+ this.server.on('error', (error) => {
122
+ this.logger.error(`HTTP server error: ${error.message}`);
123
+ if (this.onerror) {
124
+ this.onerror(error);
125
+ }
115
126
  });
116
- this.serverInstance.setRequestHandler(CALL_TOOL_REQUEST_SCHEMA, async (request) => {
117
- const req = request;
118
- if (!validateApiKey(req.arguments?.apiKey, this.apiKey)) {
119
- return {
120
- content: [{ type: 'text', text: JSON.stringify({ error: true, message: 'Invalid API key' }) }],
121
- isError: true,
122
- };
127
+ this.server.on('close', () => {
128
+ if (this.onclose) {
129
+ this.onclose();
130
+ }
131
+ });
132
+ await new Promise((resolve, reject) => {
133
+ this.server.listen(this.port, '127.0.0.1', () => {
134
+ this.logger.log(`Evolith MCP HTTP server listening on http://127.0.0.1:${this.port}`);
135
+ resolve();
136
+ });
137
+ this.server.on('error', reject);
138
+ });
139
+ }
140
+ async close() {
141
+ this.started = false;
142
+ for (const client of this.sseClients) {
143
+ client.res.end();
144
+ }
145
+ this.sseClients = [];
146
+ if (this.server) {
147
+ await new Promise((resolve) => {
148
+ this.server.close(() => resolve());
149
+ });
150
+ this.server = null;
151
+ }
152
+ }
153
+ async send(message) {
154
+ const data = `event: message\ndata: ${JSON.stringify(message)}\n\n`;
155
+ const clientsToRemove = [];
156
+ for (const client of this.sseClients) {
157
+ try {
158
+ client.res.write(data);
159
+ }
160
+ catch {
161
+ clientsToRemove.push(client);
123
162
  }
124
- const args = { ...req.arguments };
125
- delete args.apiKey;
126
- return this.handleCallTool(req.name, args);
163
+ }
164
+ for (const client of clientsToRemove) {
165
+ const index = this.sseClients.indexOf(client);
166
+ if (index > -1) {
167
+ this.sseClients.splice(index, 1);
168
+ }
169
+ }
170
+ }
171
+ handleRequest(req, res) {
172
+ const url = new URL(req.url || '/', `http://127.0.0.1:${this.port}`);
173
+ if (!this.validateAuth(req, res)) {
174
+ return;
175
+ }
176
+ if (req.method === 'POST' && url.pathname === '/message') {
177
+ this.handlePostMessage(req, res);
178
+ }
179
+ else if (req.method === 'GET' && url.pathname === '/sse') {
180
+ this.handleSseConnection(req, res);
181
+ }
182
+ else if (req.method === 'GET' && url.pathname === '/health') {
183
+ res.writeHead(200, { 'Content-Type': 'application/json' });
184
+ res.end(JSON.stringify({ status: 'ok', transport: 'http', protocol: 'mcp' }));
185
+ }
186
+ else {
187
+ res.writeHead(404, { 'Content-Type': 'application/json' });
188
+ res.end(JSON.stringify({ error: 'Not found' }));
189
+ }
190
+ }
191
+ validateAuth(req, res) {
192
+ if (!this.apiKey)
193
+ return true;
194
+ const authHeader = req.headers.authorization || '';
195
+ const bearerToken = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : '';
196
+ const apiKeyHeader = req.headers['x-api-key'];
197
+ if (bearerToken !== this.apiKey && apiKeyHeader !== this.apiKey) {
198
+ res.writeHead(401, { 'Content-Type': 'application/json' });
199
+ res.end(JSON.stringify({ error: 'Unauthorized', message: 'Invalid or missing API key' }));
200
+ return false;
201
+ }
202
+ return true;
203
+ }
204
+ async handlePostMessage(req, res) {
205
+ let body = '';
206
+ req.on('data', (chunk) => {
207
+ body += chunk.toString();
127
208
  });
128
- this.serverInstance.setRequestHandler(LIST_RESOURCES_REQUEST_SCHEMA, async () => {
129
- return (0, resources_1.listResources)();
209
+ req.on('end', async () => {
210
+ try {
211
+ const message = JSON.parse(body);
212
+ if (this.onmessage) {
213
+ await this.onmessage(message);
214
+ }
215
+ res.writeHead(202, { 'Content-Type': 'application/json' });
216
+ res.end(JSON.stringify({ status: 'accepted' }));
217
+ }
218
+ catch (error) {
219
+ this.logger.error(`Invalid POST message: ${error}`);
220
+ res.writeHead(400, { 'Content-Type': 'application/json' });
221
+ res.end(JSON.stringify({ error: 'Invalid JSON' }));
222
+ }
130
223
  });
131
- this.serverInstance.setRequestHandler(READ_RESOURCE_REQUEST_SCHEMA, async (request) => {
132
- return (0, resources_1.readResource)(request);
224
+ req.on('error', (error) => {
225
+ this.logger.error(`Request error: ${error.message}`);
226
+ if (this.onerror) {
227
+ this.onerror(error);
228
+ }
229
+ if (!res.headersSent) {
230
+ res.writeHead(500, { 'Content-Type': 'application/json' });
231
+ res.end(JSON.stringify({ error: 'Internal server error' }));
232
+ }
133
233
  });
134
- this.serverInstance.setRequestHandler(LIST_PROMPTS_REQUEST_SCHEMA, async () => {
135
- return (0, prompts_1.listPrompts)();
234
+ }
235
+ handleSseConnection(req, res) {
236
+ const clientId = `client-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`;
237
+ res.writeHead(200, {
238
+ 'Content-Type': 'text/event-stream',
239
+ 'Cache-Control': 'no-cache',
240
+ 'Connection': 'keep-alive',
241
+ 'Access-Control-Allow-Origin': '*',
136
242
  });
137
- this.serverInstance.setRequestHandler(GET_PROMPT_REQUEST_SCHEMA, async (request) => {
138
- return (0, prompts_1.getPrompt)(request);
243
+ res.write(': connected\n\n');
244
+ this.sseClients.push({ id: clientId, res });
245
+ req.on('close', () => {
246
+ const index = this.sseClients.findIndex(c => c.id === clientId);
247
+ if (index > -1) {
248
+ this.sseClients.splice(index, 1);
249
+ }
250
+ this.logger.debug(`SSE client disconnected: ${clientId}`);
139
251
  });
140
- this.logger.log('Evolith MCP Server initialized');
252
+ this.logger.debug(`SSE client connected: ${clientId}`);
141
253
  }
142
- async connect(transport = 'stdio') {
143
- if (!this.serverInstance) {
144
- await this.initialize();
145
- }
146
- if (transport === 'http') {
147
- await this.startHttpServer();
254
+ }
255
+ class DirectMcpServer {
256
+ constructor(transportType = 'stdio', port = 49100, apiKey, rulesetValidator, metricsService) {
257
+ this.logger = new common_1.Logger(DirectMcpServer.name);
258
+ this.transportType = transportType;
259
+ this.rulesetValidator = rulesetValidator || new ruleset_validator_service_1.RulesetValidatorService();
260
+ this.metricsService = metricsService || new metrics_service_1.McpMetricsService();
261
+ if (transportType === 'http') {
262
+ this.transport = new MinimalHttpTransport(port, apiKey);
148
263
  }
149
264
  else {
150
- const stdioTransport = new StdioTransportClass();
151
- await this.serverInstance.connect(stdioTransport);
265
+ this.transport = new MinimalStdioTransport();
152
266
  }
153
267
  }
154
- async startHttpServer() {
155
- if (!StreamableHttpTransportClass) {
156
- this.logger.warn('Streamable HTTP transport not available, falling back to stdio');
157
- const stdioTransport = new StdioTransportClass();
158
- await this.serverInstance.connect(stdioTransport);
159
- return;
268
+ async start() {
269
+ const transport = this.transport;
270
+ transport.onmessage = async (message) => {
271
+ await this.handleMessage(message);
272
+ };
273
+ transport.onerror = (error) => {
274
+ this.logger.error(`Transport error: ${error.message}`);
275
+ };
276
+ await transport.start();
277
+ this.logger.log(`Evolith MCP Server started on ${this.transportType}`);
278
+ }
279
+ async stop() {
280
+ await this.transport.close();
281
+ }
282
+ async handleMessage(rawMessage) {
283
+ try {
284
+ const request = rawMessage;
285
+ this.logger.debug(`Received: ${JSON.stringify(request)}`);
286
+ if (request.method === 'initialize') {
287
+ const response = {
288
+ jsonrpc: '2.0',
289
+ id: request.id,
290
+ result: {
291
+ protocolVersion: '2024-11-05',
292
+ capabilities: {
293
+ tools: {},
294
+ resources: {},
295
+ prompts: {},
296
+ },
297
+ serverInfo: {
298
+ name: 'evolith-mcp-server',
299
+ version: '1.0.0',
300
+ },
301
+ },
302
+ };
303
+ await this.transport.send(response);
304
+ return;
305
+ }
306
+ let result;
307
+ try {
308
+ result = await this.dispatchRequest(request.method, request.params || {});
309
+ }
310
+ catch (error) {
311
+ const errorResponse = {
312
+ jsonrpc: '2.0',
313
+ id: request.id,
314
+ error: {
315
+ code: -32603,
316
+ message: error instanceof Error ? error.message : String(error),
317
+ },
318
+ };
319
+ await this.transport.send(errorResponse);
320
+ return;
321
+ }
322
+ const response = {
323
+ jsonrpc: '2.0',
324
+ id: request.id,
325
+ result,
326
+ };
327
+ await this.transport.send(response);
328
+ }
329
+ catch (error) {
330
+ this.logger.error(`Error handling message: ${error}`);
331
+ const errorResponse = {
332
+ jsonrpc: '2.0',
333
+ id: null,
334
+ error: {
335
+ code: -32603,
336
+ message: error instanceof Error ? error.message : String(error),
337
+ },
338
+ };
339
+ await this.transport.send(errorResponse);
340
+ }
341
+ }
342
+ async dispatchRequest(method, params) {
343
+ switch (method) {
344
+ case 'tools/list':
345
+ return this.handleListTools();
346
+ case 'tools/call':
347
+ return this.handleCallTool(params);
348
+ case 'resources/list':
349
+ return this.handleListResources();
350
+ case 'resources/read':
351
+ return this.handleReadResource(params);
352
+ case 'prompts/list':
353
+ return this.handleListPrompts();
354
+ case 'prompts/get':
355
+ return this.handleGetPrompt(params);
356
+ default:
357
+ throw new Error(`Method not found: ${method}`);
160
358
  }
161
- this.logger.log(`Starting HTTP MCP server on port ${this.port}`);
162
- const httpTransport = new StreamableHttpTransportClass({
163
- port: this.port,
164
- host: '0.0.0.0',
165
- });
166
- await this.serverInstance.connect(httpTransport);
167
359
  }
168
- async handleListTools() {
360
+ handleListTools() {
169
361
  return {
170
362
  tools: [
171
363
  {
172
364
  name: 'evolith-validate',
173
- description: 'Validate a repository against Evolith governance rules. Returns validation status, rules checked, and any issues found.',
365
+ description: 'Validate a repository against Evolith governance rules',
174
366
  inputSchema: {
175
367
  type: 'object',
176
368
  properties: {
177
369
  path: { type: 'string', description: 'Path to the repository to validate' },
178
370
  format: { type: 'string', description: 'Output format: json, summary, table', default: 'json' },
179
- ruleset: { type: 'string', description: 'Specific ruleset to validate (acl, open-core, inheritance, adr-XXXX)' },
180
- corePath: { type: 'string', description: 'Path to Evolith Core (optional, auto-detected)' },
371
+ ruleset: { type: 'string', description: 'Specific ruleset to validate' },
372
+ corePath: { type: 'string', description: 'Path to Evolith Core' },
181
373
  },
182
374
  required: ['path'],
183
375
  },
184
376
  },
185
377
  {
186
378
  name: 'evolith-agent-install',
187
- description: 'Install a new Evolith agent with specified name and template',
379
+ description: 'Install a new Evolith agent',
188
380
  inputSchema: {
189
381
  type: 'object',
190
382
  properties: {
191
383
  name: { type: 'string', description: 'Name of the agent to install' },
192
- template: { type: 'string', description: 'Template to use: standard, minimal, enterprise', default: 'standard' },
193
- dir: { type: 'string', description: 'Directory to install into (defaults to current working directory)' },
384
+ template: { type: 'string', description: 'Template: standard, minimal, enterprise', default: 'standard' },
385
+ dir: { type: 'string', description: 'Directory to install into' },
194
386
  },
195
387
  required: ['name'],
196
388
  },
197
389
  },
198
390
  {
199
391
  name: 'evolith-agent-list',
200
- description: 'List all installed Evolith agents in a repository',
392
+ description: 'List all installed Evolith agents',
201
393
  inputSchema: {
202
394
  type: 'object',
203
395
  properties: {
204
- dir: { type: 'string', description: 'Directory to search for agents (defaults to current working directory)' },
396
+ dir: { type: 'string', description: 'Directory to search' },
205
397
  },
206
398
  },
207
399
  },
@@ -211,44 +403,45 @@ class EvolithMcpServer {
211
403
  inputSchema: {
212
404
  type: 'object',
213
405
  properties: {
214
- name: { type: 'string', description: 'Name of the agent to validate' },
215
- dir: { type: 'string', description: 'Directory containing the agent (defaults to current working directory)' },
406
+ name: { type: 'string' },
407
+ dir: { type: 'string' },
216
408
  },
217
409
  required: ['name'],
218
410
  },
219
411
  },
220
412
  {
221
413
  name: 'evolith-agent-upgrade',
222
- description: 'Upgrade an existing Evolith agent to the latest version',
414
+ description: 'Upgrade an existing Evolith agent',
223
415
  inputSchema: {
224
416
  type: 'object',
225
417
  properties: {
226
- name: { type: 'string', description: 'Name of the agent to upgrade' },
227
- dir: { type: 'string', description: 'Directory containing the agent (defaults to current working directory)' },
418
+ name: { type: 'string' },
419
+ dir: { type: 'string' },
228
420
  },
229
421
  required: ['name'],
230
422
  },
231
423
  },
232
424
  {
233
425
  name: 'evolith-agent-remove',
234
- description: 'Remove an Evolith agent and its ruleset',
426
+ description: 'Remove an Evolith agent',
235
427
  inputSchema: {
236
428
  type: 'object',
237
429
  properties: {
238
- name: { type: 'string', description: 'Name of the agent to remove' },
239
- dir: { type: 'string', description: 'Directory containing the agent (defaults to current working directory)' },
430
+ name: { type: 'string' },
431
+ dir: { type: 'string' },
240
432
  },
241
433
  required: ['name'],
242
434
  },
243
435
  },
244
436
  {
245
437
  name: 'evolith-architecture-validate',
246
- description: 'Validate repository architecture against F1/F2/F3 rules',
438
+ description: 'Validate repository architecture against F1/F2/F3 rules. Use deep=true for import graph analysis, layer violations, and coupling metrics.',
247
439
  inputSchema: {
248
440
  type: 'object',
249
441
  properties: {
250
- path: { type: 'string', description: 'Path to the repository to validate' },
251
- level: { type: 'string', description: 'Architecture level: F1 (modular), F2 (contracts), F3 (extraction)', default: 'F1' },
442
+ path: { type: 'string' },
443
+ level: { type: 'string', description: 'F1, F2, or F3' },
444
+ deep: { type: 'boolean', description: 'Enable deep static analysis (import graph, layer violations, coupling metrics)', default: false },
252
445
  },
253
446
  required: ['path'],
254
447
  },
@@ -259,20 +452,20 @@ class EvolithMcpServer {
259
452
  inputSchema: {
260
453
  type: 'object',
261
454
  properties: {
262
- path: { type: 'string', description: 'Path to the repository' },
263
- fromPhase: { type: 'string', description: 'Source phase: phase-0, phase-1, phase-2, phase-3, phase-4' },
264
- toPhase: { type: 'string', description: 'Target phase: phase-0, phase-1, phase-2, phase-3, phase-4' },
455
+ path: { type: 'string' },
456
+ fromPhase: { type: 'string' },
457
+ toPhase: { type: 'string' },
265
458
  },
266
459
  required: ['path', 'fromPhase', 'toPhase'],
267
460
  },
268
461
  },
269
462
  {
270
463
  name: 'evolith-sdlc-status',
271
- description: 'Show current SDLC phase gate status for a repository',
464
+ description: 'Show current SDLC phase gate status',
272
465
  inputSchema: {
273
466
  type: 'object',
274
467
  properties: {
275
- path: { type: 'string', description: 'Path to the repository' },
468
+ path: { type: 'string' },
276
469
  },
277
470
  required: ['path'],
278
471
  },
@@ -283,8 +476,8 @@ class EvolithMcpServer {
283
476
  inputSchema: {
284
477
  type: 'object',
285
478
  properties: {
286
- key: { type: 'string', description: 'Configuration key to retrieve' },
287
- dir: { type: 'string', description: 'Directory containing evolith.yaml' },
479
+ key: { type: 'string' },
480
+ dir: { type: 'string' },
288
481
  },
289
482
  required: ['key'],
290
483
  },
@@ -295,26 +488,114 @@ class EvolithMcpServer {
295
488
  inputSchema: {
296
489
  type: 'object',
297
490
  properties: {
298
- key: { type: 'string', description: 'Configuration key to set' },
299
- value: { type: 'string', description: 'Value to set' },
300
- dir: { type: 'string', description: 'Directory containing evolith.yaml' },
491
+ key: { type: 'string' },
492
+ value: { type: 'string' },
493
+ dir: { type: 'string' },
301
494
  },
302
495
  required: ['key', 'value'],
303
496
  },
304
497
  },
305
498
  {
306
499
  name: 'evolith-metrics',
307
- description: 'Get MCP server metrics including tool usage statistics, latency, and error rates',
500
+ description: 'Get MCP server metrics',
308
501
  inputSchema: {
309
502
  type: 'object',
310
503
  properties: {},
311
504
  },
312
505
  },
506
+ {
507
+ name: 'evolith-moscow-create',
508
+ description: 'Create a new MoSCoW prioritization analysis for a phase',
509
+ inputSchema: {
510
+ type: 'object',
511
+ properties: {
512
+ path: { type: 'string', description: 'Path to the repository' },
513
+ phase: { type: 'string', description: 'Phase identifier (e.g., phase-0)', default: 'phase-0' },
514
+ items: { type: 'array', description: 'Array of MoSCoW items with description, priority, category, rationale' },
515
+ },
516
+ required: ['path', 'items'],
517
+ },
518
+ },
519
+ {
520
+ name: 'evolith-moscow-load',
521
+ description: 'Load an existing MoSCoW analysis for a phase',
522
+ inputSchema: {
523
+ type: 'object',
524
+ properties: {
525
+ path: { type: 'string' },
526
+ phase: { type: 'string', default: 'phase-0' },
527
+ },
528
+ required: ['path'],
529
+ },
530
+ },
531
+ {
532
+ name: 'evolith-moscow-update',
533
+ description: 'Update an item in a MoSCoW analysis',
534
+ inputSchema: {
535
+ type: 'object',
536
+ properties: {
537
+ path: { type: 'string' },
538
+ phase: { type: 'string', default: 'phase-0' },
539
+ itemId: { type: 'string' },
540
+ updates: { type: 'object' },
541
+ },
542
+ required: ['path', 'itemId'],
543
+ },
544
+ },
545
+ {
546
+ name: 'evolith-moscow-remove',
547
+ description: 'Remove an item from a MoSCoW analysis',
548
+ inputSchema: {
549
+ type: 'object',
550
+ properties: {
551
+ path: { type: 'string' },
552
+ phase: { type: 'string', default: 'phase-0' },
553
+ itemId: { type: 'string' },
554
+ },
555
+ required: ['path', 'itemId'],
556
+ },
557
+ },
558
+ {
559
+ name: 'evolith-moscow-list',
560
+ description: 'List all MoSCoW analyses for a repository',
561
+ inputSchema: {
562
+ type: 'object',
563
+ properties: {
564
+ path: { type: 'string' },
565
+ },
566
+ required: ['path'],
567
+ },
568
+ },
569
+ {
570
+ name: 'evolith-moscow-validate',
571
+ description: 'Validate a MoSCoW analysis for correctness',
572
+ inputSchema: {
573
+ type: 'object',
574
+ properties: {
575
+ path: { type: 'string' },
576
+ phase: { type: 'string', default: 'phase-0' },
577
+ },
578
+ required: ['path'],
579
+ },
580
+ },
581
+ {
582
+ name: 'evolith-moscow-report',
583
+ description: 'Generate a markdown report from a MoSCoW analysis',
584
+ inputSchema: {
585
+ type: 'object',
586
+ properties: {
587
+ path: { type: 'string' },
588
+ phase: { type: 'string', default: 'phase-0' },
589
+ },
590
+ required: ['path'],
591
+ },
592
+ },
313
593
  ],
314
594
  };
315
595
  }
316
- async handleCallTool(name, args) {
317
- this.logger.debug(`Tool call: ${name} with args: ${JSON.stringify(args)}`);
596
+ async handleCallTool(params) {
597
+ const name = params.name;
598
+ const args = params.arguments || {};
318
599
  const startTime = Date.now();
319
600
  try {
320
601
  let result;
@@ -331,11 +612,14 @@ class EvolithMcpServer {
331
612
  result = await (0, sdlc_1.handleSdlcTools)(name, args);
332
613
  }
333
614
  else if (name === 'evolith-config-get' || name === 'evolith-config-set') {
334
- result = await handleConfigTools(name, args);
615
+ result = await this.handleConfigTools(name, args);
335
616
  }
336
617
  else if (name === 'evolith-metrics') {
337
618
  result = this.metricsService.getMetrics();
338
619
  }
620
+ else if (name.startsWith('evolith-moscow')) {
621
+ result = await (0, moscow_1.handleMoscowTools)(name, args);
622
+ }
339
623
  else {
340
624
  throw new Error(`Unknown tool: ${name}`);
341
625
  }
@@ -353,7 +637,6 @@ class EvolithMcpServer {
353
637
  catch (error) {
354
638
  const latencyMs = Date.now() - startTime;
355
639
  const message = error instanceof Error ? error.message : String(error);
356
- this.logger.error(`Tool ${name} failed: ${message}`);
357
640
  this.metricsService.recordToolCall(name, latencyMs, false);
358
641
  this.metricsService.recordError(message.substring(0, 50));
359
642
  return {
@@ -367,47 +650,70 @@ class EvolithMcpServer {
367
650
  };
368
651
  }
369
652
  }
370
- }
371
- exports.EvolithMcpServer = EvolithMcpServer;
372
- async function handleConfigTools(name, args) {
373
- const fs = await Promise.resolve().then(() => __importStar(require('fs-extra')));
374
- const path = await Promise.resolve().then(() => __importStar(require('path')));
375
- const yaml = await Promise.resolve().then(() => __importStar(require('yaml')));
376
- const dir = args.dir || process.cwd();
377
- const configPath = path.join(dir, 'evolith.yaml');
378
- if (!(await fs.pathExists(configPath))) {
379
- throw new Error('evolith.yaml not found');
380
- }
381
- const config = yaml.parse(await fs.readFile(configPath, 'utf-8'));
382
- if (name === 'evolith-config-get') {
383
- const key = args.key;
384
- const keys = key.split('.');
385
- let value = config;
386
- for (const k of keys) {
387
- value = value?.[k];
653
+ async handleConfigTools(name, args) {
654
+ const fs = await Promise.resolve().then(() => __importStar(require('fs-extra')));
655
+ const path = await Promise.resolve().then(() => __importStar(require('path')));
656
+ const yaml = await Promise.resolve().then(() => __importStar(require('yaml')));
657
+ const dir = args.dir || process.cwd();
658
+ const configPath = path.join(dir, 'evolith.yaml');
659
+ if (!(await fs.pathExists(configPath))) {
660
+ throw new Error('evolith.yaml not found');
388
661
  }
389
- return { key, value: value ?? null };
390
- }
391
- else {
392
- const key = args.key;
393
- const value = args.value;
394
- const keys = key.split('.');
395
- let target = config;
396
- for (let i = 0; i < keys.length - 1; i++) {
397
- if (!target[keys[i]]) {
398
- target[keys[i]] = {};
662
+ const config = yaml.parse(await fs.readFile(configPath, 'utf-8'));
663
+ if (name === 'evolith-config-get') {
664
+ const key = args.key;
665
+ const keys = key.split('.');
666
+ let value = config;
667
+ for (const k of keys) {
668
+ value = value?.[k];
399
669
  }
400
- target = target[keys[i]];
670
+ return { key, value: value ?? null };
401
671
  }
402
- target[keys[keys.length - 1]] = value;
403
- await fs.writeFile(configPath, yaml.stringify(config));
404
- return { key, value, updated: true };
672
+ else {
673
+ const key = args.key;
674
+ const value = args.value;
675
+ const keys = key.split('.');
676
+ let target = config;
677
+ for (let i = 0; i < keys.length - 1; i++) {
678
+ if (!target[keys[i]]) {
679
+ target[keys[i]] = {};
680
+ }
681
+ target = target[keys[i]];
682
+ }
683
+ target[keys[keys.length - 1]] = value;
684
+ await fs.writeFile(configPath, yaml.stringify(config));
685
+ return { key, value, updated: true };
686
+ }
687
+ }
688
+ async handleListResources() {
689
+ const { listResources } = await Promise.resolve().then(() => __importStar(require('./resources')));
690
+ return listResources();
691
+ }
692
+ async handleReadResource(params) {
693
+ const { readResource } = await Promise.resolve().then(() => __importStar(require('./resources')));
694
+ return readResource(params);
405
695
  }
696
+ async handleListPrompts() {
697
+ const { listPrompts } = await Promise.resolve().then(() => __importStar(require('./prompts')));
698
+ return listPrompts();
699
+ }
700
+ async handleGetPrompt(params) {
701
+ const { getPrompt } = await Promise.resolve().then(() => __importStar(require('./prompts')));
702
+ return getPrompt(params);
703
+ }
704
+ }
705
+ function validateApiKey(apiKey, validKey) {
706
+ if (!validKey)
707
+ return true;
708
+ if (!apiKey)
709
+ return false;
710
+ return apiKey === validKey;
406
711
  }
407
712
  async function startMcpServer(options = {}) {
408
- const server = new EvolithMcpServer(options);
409
713
  const transport = options.transport || 'stdio';
410
- await server.connect(transport);
714
+ const port = options.port || 49100;
715
+ const server = new DirectMcpServer(transport, port, options.apiKey, options.rulesetValidator, options.metricsService);
716
+ await server.start();
411
717
  return server;
412
718
  }
413
719
  //# sourceMappingURL=server.js.map