claude-flow 1.0.0

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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +612 -0
  3. package/bin/claude-flow +0 -0
  4. package/bin/claude-flow-simple +0 -0
  5. package/bin/claude-flow-typecheck +0 -0
  6. package/deno.json +84 -0
  7. package/package.json +45 -0
  8. package/scripts/check-links.ts +274 -0
  9. package/scripts/check-performance-regression.ts +168 -0
  10. package/scripts/claude-sparc.sh +562 -0
  11. package/scripts/coverage-report.ts +692 -0
  12. package/scripts/demo-task-system.ts +224 -0
  13. package/scripts/install.js +72 -0
  14. package/scripts/test-batch-tasks.ts +29 -0
  15. package/scripts/test-coordination-features.ts +238 -0
  16. package/scripts/test-mcp.ts +251 -0
  17. package/scripts/test-runner.ts +571 -0
  18. package/scripts/validate-examples.ts +288 -0
  19. package/src/cli/cli-core.ts +273 -0
  20. package/src/cli/commands/agent.ts +83 -0
  21. package/src/cli/commands/config.ts +442 -0
  22. package/src/cli/commands/help.ts +765 -0
  23. package/src/cli/commands/index.ts +963 -0
  24. package/src/cli/commands/mcp.ts +191 -0
  25. package/src/cli/commands/memory.ts +74 -0
  26. package/src/cli/commands/monitor.ts +403 -0
  27. package/src/cli/commands/session.ts +595 -0
  28. package/src/cli/commands/start.ts +156 -0
  29. package/src/cli/commands/status.ts +345 -0
  30. package/src/cli/commands/task.ts +79 -0
  31. package/src/cli/commands/workflow.ts +763 -0
  32. package/src/cli/completion.ts +553 -0
  33. package/src/cli/formatter.ts +310 -0
  34. package/src/cli/index.ts +211 -0
  35. package/src/cli/main.ts +23 -0
  36. package/src/cli/repl.ts +1050 -0
  37. package/src/cli/simple-cli.js +211 -0
  38. package/src/cli/simple-cli.ts +211 -0
  39. package/src/coordination/README.md +400 -0
  40. package/src/coordination/advanced-scheduler.ts +487 -0
  41. package/src/coordination/circuit-breaker.ts +366 -0
  42. package/src/coordination/conflict-resolution.ts +490 -0
  43. package/src/coordination/dependency-graph.ts +475 -0
  44. package/src/coordination/index.ts +63 -0
  45. package/src/coordination/manager.ts +460 -0
  46. package/src/coordination/messaging.ts +290 -0
  47. package/src/coordination/metrics.ts +585 -0
  48. package/src/coordination/resources.ts +322 -0
  49. package/src/coordination/scheduler.ts +390 -0
  50. package/src/coordination/work-stealing.ts +224 -0
  51. package/src/core/config.ts +627 -0
  52. package/src/core/event-bus.ts +186 -0
  53. package/src/core/json-persistence.ts +183 -0
  54. package/src/core/logger.ts +262 -0
  55. package/src/core/orchestrator-fixed.ts +312 -0
  56. package/src/core/orchestrator.ts +1234 -0
  57. package/src/core/persistence.ts +276 -0
  58. package/src/mcp/auth.ts +438 -0
  59. package/src/mcp/claude-flow-tools.ts +1280 -0
  60. package/src/mcp/load-balancer.ts +510 -0
  61. package/src/mcp/router.ts +240 -0
  62. package/src/mcp/server.ts +548 -0
  63. package/src/mcp/session-manager.ts +418 -0
  64. package/src/mcp/tools.ts +180 -0
  65. package/src/mcp/transports/base.ts +21 -0
  66. package/src/mcp/transports/http.ts +457 -0
  67. package/src/mcp/transports/stdio.ts +254 -0
  68. package/src/memory/backends/base.ts +22 -0
  69. package/src/memory/backends/markdown.ts +283 -0
  70. package/src/memory/backends/sqlite.ts +329 -0
  71. package/src/memory/cache.ts +238 -0
  72. package/src/memory/indexer.ts +238 -0
  73. package/src/memory/manager.ts +572 -0
  74. package/src/terminal/adapters/base.ts +29 -0
  75. package/src/terminal/adapters/native.ts +504 -0
  76. package/src/terminal/adapters/vscode.ts +340 -0
  77. package/src/terminal/manager.ts +308 -0
  78. package/src/terminal/pool.ts +271 -0
  79. package/src/terminal/session.ts +250 -0
  80. package/src/terminal/vscode-bridge.ts +242 -0
  81. package/src/utils/errors.ts +231 -0
  82. package/src/utils/helpers.ts +476 -0
  83. package/src/utils/types.ts +493 -0
@@ -0,0 +1,457 @@
1
+ /**
2
+ * HTTP transport for MCP
3
+ */
4
+
5
+ import { ITransport, RequestHandler, NotificationHandler } from './base.ts';
6
+ import { MCPRequest, MCPResponse, MCPNotification, MCPConfig } from '../../utils/types.ts';
7
+ import { ILogger } from '../../core/logger.ts';
8
+ import { MCPTransportError } from '../../utils/errors.ts';
9
+
10
+ /**
11
+ * HTTP transport implementation
12
+ */
13
+ export class HttpTransport implements ITransport {
14
+ private requestHandler?: RequestHandler;
15
+ private notificationHandler?: NotificationHandler;
16
+ private server?: Deno.HttpServer | undefined;
17
+ private messageCount = 0;
18
+ private notificationCount = 0;
19
+ private running = false;
20
+ private connections = new Set<WebSocket>();
21
+ private activeWebSockets = new Set<WebSocket>();
22
+
23
+ constructor(
24
+ private host: string,
25
+ private port: number,
26
+ private tlsEnabled: boolean,
27
+ private logger: ILogger,
28
+ private config?: MCPConfig,
29
+ ) {}
30
+
31
+ async start(): Promise<void> {
32
+ if (this.running) {
33
+ throw new MCPTransportError('Transport already running');
34
+ }
35
+
36
+ this.logger.info('Starting HTTP transport', {
37
+ host: this.host,
38
+ port: this.port,
39
+ tls: this.tlsEnabled,
40
+ });
41
+
42
+ try {
43
+ // Create listener
44
+ const listener = Deno.listen({
45
+ hostname: this.host,
46
+ port: this.port,
47
+ });
48
+
49
+ this.server = Deno.serve({
50
+ port: this.port,
51
+ hostname: this.host,
52
+ handler: (request) => this.handleRequest(request),
53
+ onListen: ({ hostname, port }) => {
54
+ this.logger.info(`HTTP server listening on ${hostname}:${port}`);
55
+ },
56
+ });
57
+
58
+ this.running = true;
59
+ this.logger.info('HTTP transport started');
60
+ } catch (error) {
61
+ throw new MCPTransportError('Failed to start HTTP transport', { error });
62
+ }
63
+ }
64
+
65
+ async stop(): Promise<void> {
66
+ if (!this.running) {
67
+ return;
68
+ }
69
+
70
+ this.logger.info('Stopping HTTP transport');
71
+
72
+ this.running = false;
73
+
74
+ // Close all connections
75
+ for (const conn of this.connections) {
76
+ try {
77
+ conn.close();
78
+ } catch {
79
+ // Ignore errors
80
+ }
81
+ }
82
+ this.connections.clear();
83
+
84
+ // Shutdown server
85
+ if (this.server) {
86
+ await this.server.shutdown();
87
+ this.server = undefined;
88
+ }
89
+
90
+ this.logger.info('HTTP transport stopped');
91
+ }
92
+
93
+ onRequest(handler: RequestHandler): void {
94
+ this.requestHandler = handler;
95
+ }
96
+
97
+ onNotification(handler: NotificationHandler): void {
98
+ this.notificationHandler = handler;
99
+ }
100
+
101
+ async sendNotification(notification: MCPNotification): Promise<void> {
102
+ // Send notification to all connected WebSocket clients
103
+ const message = JSON.stringify(notification);
104
+ const promises: Promise<void>[] = [];
105
+
106
+ for (const ws of this.activeWebSockets) {
107
+ if (ws.readyState === WebSocket.OPEN) {
108
+ promises.push(
109
+ new Promise<void>((resolve, reject) => {
110
+ try {
111
+ ws.send(message);
112
+ resolve();
113
+ } catch (error) {
114
+ reject(error);
115
+ }
116
+ })
117
+ );
118
+ }
119
+ }
120
+
121
+ try {
122
+ await Promise.all(promises);
123
+ this.notificationCount++;
124
+
125
+ this.logger.debug('Notification sent to WebSocket clients', {
126
+ method: notification.method,
127
+ clientCount: this.activeWebSockets.size,
128
+ });
129
+ } catch (error) {
130
+ this.logger.error('Failed to send notification to some clients', { error });
131
+ throw new MCPTransportError('Failed to send notification', { error });
132
+ }
133
+ }
134
+
135
+ async getHealthStatus(): Promise<{
136
+ healthy: boolean;
137
+ error?: string;
138
+ metrics?: Record<string, number>;
139
+ }> {
140
+ return {
141
+ healthy: this.running,
142
+ metrics: {
143
+ messagesReceived: this.messageCount,
144
+ notificationsSent: this.notificationCount,
145
+ activeConnections: this.connections.size,
146
+ activeWebSockets: this.activeWebSockets.size,
147
+ },
148
+ };
149
+ }
150
+
151
+ private async handleRequest(request: Request): Promise<Response> {
152
+ const url = new URL(request.url);
153
+ const pathname = url.pathname;
154
+
155
+ // Handle CORS preflight requests
156
+ if (request.method === 'OPTIONS') {
157
+ return this.handleCORS(request);
158
+ }
159
+
160
+ // Handle WebSocket upgrade for real-time notifications
161
+ if (request.headers.get('upgrade') === 'websocket' && pathname === '/ws') {
162
+ return this.handleWebSocketUpgrade(request);
163
+ }
164
+
165
+ // Only accept POST requests to /rpc for JSON-RPC
166
+ if (request.method !== 'POST' || pathname !== '/rpc') {
167
+ return this.createErrorResponse(405, 'Method not allowed');
168
+ }
169
+
170
+ // Add CORS headers to all responses
171
+ const headers = this.getCORSHeaders();
172
+ headers.set('content-type', 'application/json');
173
+
174
+ // Check content type
175
+ const contentType = request.headers.get('content-type');
176
+ if (!contentType?.includes('application/json')) {
177
+ return this.createErrorResponse(400, 'Invalid content type', headers);
178
+ }
179
+
180
+ // Check authorization if authentication is enabled
181
+ if (this.config?.auth?.enabled) {
182
+ const authResult = await this.validateAuth(request);
183
+ if (!authResult.valid) {
184
+ return this.createErrorResponse(401, authResult.error || 'Unauthorized', headers);
185
+ }
186
+ }
187
+
188
+ try {
189
+ // Parse request body
190
+ const body = await request.text();
191
+
192
+ let mcpMessage: any;
193
+ try {
194
+ mcpMessage = JSON.parse(body);
195
+ } catch {
196
+ return new Response(
197
+ JSON.stringify({
198
+ jsonrpc: '2.0',
199
+ id: null,
200
+ error: {
201
+ code: -32700,
202
+ message: 'Parse error',
203
+ },
204
+ }),
205
+ { status: 400, headers },
206
+ );
207
+ }
208
+
209
+ // Validate JSON-RPC format
210
+ if (!mcpMessage.jsonrpc || mcpMessage.jsonrpc !== '2.0') {
211
+ return new Response(
212
+ JSON.stringify({
213
+ jsonrpc: '2.0',
214
+ id: mcpMessage.id || null,
215
+ error: {
216
+ code: -32600,
217
+ message: 'Invalid request - missing or invalid jsonrpc version',
218
+ },
219
+ }),
220
+ { status: 400, headers },
221
+ );
222
+ }
223
+
224
+ if (!mcpMessage.method) {
225
+ return new Response(
226
+ JSON.stringify({
227
+ jsonrpc: '2.0',
228
+ id: mcpMessage.id || null,
229
+ error: {
230
+ code: -32600,
231
+ message: 'Invalid request - missing method',
232
+ },
233
+ }),
234
+ { status: 400, headers },
235
+ );
236
+ }
237
+
238
+ this.messageCount++;
239
+
240
+ // Check if this is a notification (no id) or request
241
+ if (mcpMessage.id === undefined) {
242
+ // Handle notification
243
+ await this.handleNotificationMessage(mcpMessage as MCPNotification);
244
+ // Notifications don't get responses
245
+ return new Response('', { status: 204, headers });
246
+ } else {
247
+ // Handle request
248
+ const response = await this.handleRequestMessage(mcpMessage as MCPRequest);
249
+ return new Response(JSON.stringify(response), { status: 200, headers });
250
+ }
251
+ } catch (error) {
252
+ this.logger.error('Error handling HTTP request', error);
253
+
254
+ return new Response(
255
+ JSON.stringify({
256
+ jsonrpc: '2.0',
257
+ id: null,
258
+ error: {
259
+ code: -32603,
260
+ message: 'Internal error',
261
+ data: error instanceof Error ? error.message : String(error),
262
+ },
263
+ }),
264
+ { status: 500, headers },
265
+ );
266
+ }
267
+ }
268
+
269
+ private handleCORS(request: Request): Response {
270
+ const headers = this.getCORSHeaders();
271
+
272
+ // Handle preflight request
273
+ const requestMethod = request.headers.get('access-control-request-method');
274
+ const requestHeaders = request.headers.get('access-control-request-headers');
275
+
276
+ if (requestMethod) {
277
+ headers.set('access-control-allow-methods', 'POST, OPTIONS');
278
+ }
279
+
280
+ if (requestHeaders) {
281
+ headers.set('access-control-allow-headers', requestHeaders);
282
+ }
283
+
284
+ return new Response('', { status: 204, headers });
285
+ }
286
+
287
+ private getCORSHeaders(): Headers {
288
+ const headers = new Headers();
289
+
290
+ if (this.config?.corsEnabled) {
291
+ const origins = this.config.corsOrigins || ['*'];
292
+ headers.set('access-control-allow-origin', origins.join(', '));
293
+ headers.set('access-control-allow-credentials', 'true');
294
+ headers.set('access-control-max-age', '86400'); // 24 hours
295
+ }
296
+
297
+ return headers;
298
+ }
299
+
300
+ private async handleWebSocketUpgrade(request: Request): Promise<Response> {
301
+ try {
302
+ // Check authentication for WebSocket connections
303
+ if (this.config?.auth?.enabled) {
304
+ const authResult = await this.validateAuth(request);
305
+ if (!authResult.valid) {
306
+ return this.createErrorResponse(401, authResult.error || 'Unauthorized');
307
+ }
308
+ }
309
+
310
+ const { socket, response } = Deno.upgradeWebSocket(request);
311
+
312
+ socket.onopen = () => {
313
+ this.activeWebSockets.add(socket);
314
+ this.logger.info('WebSocket client connected', {
315
+ totalClients: this.activeWebSockets.size,
316
+ });
317
+ };
318
+
319
+ socket.onclose = () => {
320
+ this.activeWebSockets.delete(socket);
321
+ this.logger.info('WebSocket client disconnected', {
322
+ totalClients: this.activeWebSockets.size,
323
+ });
324
+ };
325
+
326
+ socket.onerror = (error) => {
327
+ this.logger.error('WebSocket error', error);
328
+ this.activeWebSockets.delete(socket);
329
+ };
330
+
331
+ socket.onmessage = async (event) => {
332
+ try {
333
+ const message = JSON.parse(event.data);
334
+
335
+ if (message.id === undefined) {
336
+ // Notification from client
337
+ await this.handleNotificationMessage(message as MCPNotification);
338
+ } else {
339
+ // Request from client
340
+ const response = await this.handleRequestMessage(message as MCPRequest);
341
+ socket.send(JSON.stringify(response));
342
+ }
343
+ } catch (error) {
344
+ this.logger.error('Error processing WebSocket message', error);
345
+
346
+ // Send error response if it was a request
347
+ try {
348
+ const parsed = JSON.parse(event.data);
349
+ if (parsed.id !== undefined) {
350
+ socket.send(JSON.stringify({
351
+ jsonrpc: '2.0',
352
+ id: parsed.id,
353
+ error: {
354
+ code: -32603,
355
+ message: 'Internal error',
356
+ },
357
+ }));
358
+ }
359
+ } catch {
360
+ // Ignore parse errors for error responses
361
+ }
362
+ }
363
+ };
364
+
365
+ return response;
366
+ } catch (error) {
367
+ this.logger.error('Error upgrading WebSocket connection', error);
368
+ return this.createErrorResponse(500, 'Failed to upgrade WebSocket connection');
369
+ }
370
+ }
371
+
372
+ private async handleRequestMessage(request: MCPRequest): Promise<MCPResponse> {
373
+ if (!this.requestHandler) {
374
+ return {
375
+ jsonrpc: '2.0',
376
+ id: request.id,
377
+ error: {
378
+ code: -32603,
379
+ message: 'No request handler registered',
380
+ },
381
+ };
382
+ }
383
+
384
+ try {
385
+ return await this.requestHandler(request);
386
+ } catch (error) {
387
+ this.logger.error('Request handler error', { request, error });
388
+
389
+ return {
390
+ jsonrpc: '2.0',
391
+ id: request.id,
392
+ error: {
393
+ code: -32603,
394
+ message: 'Internal error',
395
+ data: error instanceof Error ? error.message : String(error),
396
+ },
397
+ };
398
+ }
399
+ }
400
+
401
+ private async handleNotificationMessage(notification: MCPNotification): Promise<void> {
402
+ if (!this.notificationHandler) {
403
+ this.logger.warn('Received notification but no handler registered', {
404
+ method: notification.method,
405
+ });
406
+ return;
407
+ }
408
+
409
+ try {
410
+ await this.notificationHandler(notification);
411
+ } catch (error) {
412
+ this.logger.error('Notification handler error', { notification, error });
413
+ // Notifications don't send error responses
414
+ }
415
+ }
416
+
417
+ private async validateAuth(request: Request): Promise<{ valid: boolean; error?: string }> {
418
+ const auth = request.headers.get('authorization');
419
+
420
+ if (!auth) {
421
+ return { valid: false, error: 'Authorization header required' };
422
+ }
423
+
424
+ // Extract token from Authorization header
425
+ const tokenMatch = auth.match(/^Bearer\s+(.+)$/i);
426
+ if (!tokenMatch) {
427
+ return { valid: false, error: 'Invalid authorization format - use Bearer token' };
428
+ }
429
+
430
+ const token = tokenMatch[1];
431
+
432
+ // Validate against configured tokens
433
+ if (this.config?.auth?.tokens && this.config.auth.tokens.length > 0) {
434
+ const isValid = this.config.auth.tokens.includes(token);
435
+ if (!isValid) {
436
+ return { valid: false, error: 'Invalid token' };
437
+ }
438
+ }
439
+
440
+ return { valid: true };
441
+ }
442
+
443
+ private createErrorResponse(status: number, message: string, headers?: Headers): Response {
444
+ const responseHeaders = headers || this.getCORSHeaders();
445
+ responseHeaders.set('content-type', 'application/json');
446
+
447
+ return new Response(
448
+ JSON.stringify({
449
+ error: {
450
+ code: status,
451
+ message,
452
+ },
453
+ }),
454
+ { status, headers: responseHeaders },
455
+ );
456
+ }
457
+ }
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Standard I/O transport for MCP
3
+ */
4
+
5
+ import { ITransport, RequestHandler, NotificationHandler } from './base.ts';
6
+ import { MCPRequest, MCPResponse, MCPNotification } from '../../utils/types.ts';
7
+ import { ILogger } from '../../core/logger.ts';
8
+ import { MCPTransportError } from '../../utils/errors.ts';
9
+
10
+ /**
11
+ * Stdio transport implementation
12
+ */
13
+ export class StdioTransport implements ITransport {
14
+ private requestHandler?: RequestHandler;
15
+ private notificationHandler?: NotificationHandler;
16
+ private decoder = new TextDecoder();
17
+ private encoder = new TextEncoder();
18
+ private buffer = '';
19
+ private messageCount = 0;
20
+ private notificationCount = 0;
21
+ private running = false;
22
+ private reader?: ReadableStreamDefaultReader<Uint8Array> | undefined;
23
+
24
+ constructor(private logger: ILogger) {}
25
+
26
+ async start(): Promise<void> {
27
+ if (this.running) {
28
+ throw new MCPTransportError('Transport already running');
29
+ }
30
+
31
+ this.logger.info('Starting stdio transport');
32
+
33
+ try {
34
+ // Start reading from stdin
35
+ this.reader = Deno.stdin.readable.getReader();
36
+ this.running = true;
37
+
38
+ // Start read loop
39
+ this.readLoop();
40
+
41
+ this.logger.info('Stdio transport started');
42
+ } catch (error) {
43
+ throw new MCPTransportError('Failed to start stdio transport', { error });
44
+ }
45
+ }
46
+
47
+ async stop(): Promise<void> {
48
+ if (!this.running) {
49
+ return;
50
+ }
51
+
52
+ this.logger.info('Stopping stdio transport');
53
+
54
+ this.running = false;
55
+
56
+ if (this.reader) {
57
+ await this.reader.cancel();
58
+ this.reader = undefined;
59
+ }
60
+
61
+ this.logger.info('Stdio transport stopped');
62
+ }
63
+
64
+ onRequest(handler: RequestHandler): void {
65
+ this.requestHandler = handler;
66
+ }
67
+
68
+ onNotification(handler: NotificationHandler): void {
69
+ this.notificationHandler = handler;
70
+ }
71
+
72
+ async sendNotification(notification: MCPNotification): Promise<void> {
73
+ try {
74
+ const json = JSON.stringify(notification);
75
+ const data = this.encoder.encode(json + '\n');
76
+
77
+ await Deno.stdout.write(data);
78
+ this.notificationCount++;
79
+
80
+ this.logger.debug('Notification sent', {
81
+ method: notification.method,
82
+ params: notification.params,
83
+ });
84
+ } catch (error) {
85
+ this.logger.error('Failed to send notification', { notification, error });
86
+ throw new MCPTransportError('Failed to send notification', { error });
87
+ }
88
+ }
89
+
90
+ async getHealthStatus(): Promise<{
91
+ healthy: boolean;
92
+ error?: string;
93
+ metrics?: Record<string, number>;
94
+ }> {
95
+ return {
96
+ healthy: this.running,
97
+ metrics: {
98
+ messagesReceived: this.messageCount,
99
+ notificationsSent: this.notificationCount,
100
+ bufferSize: this.buffer.length,
101
+ },
102
+ };
103
+ }
104
+
105
+ private async readLoop(): Promise<void> {
106
+ while (this.running && this.reader) {
107
+ try {
108
+ const { done, value } = await this.reader.read();
109
+
110
+ if (done) {
111
+ this.logger.info('Stdin closed');
112
+ break;
113
+ }
114
+
115
+ // Add to buffer
116
+ this.buffer += this.decoder.decode(value, { stream: true });
117
+
118
+ // Process complete messages
119
+ await this.processBuffer();
120
+ } catch (error) {
121
+ if (this.running) {
122
+ this.logger.error('Error reading from stdin', error);
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ private async processBuffer(): Promise<void> {
129
+ let newlineIndex: number;
130
+
131
+ while ((newlineIndex = this.buffer.indexOf('\n')) !== -1) {
132
+ const line = this.buffer.slice(0, newlineIndex).trim();
133
+ this.buffer = this.buffer.slice(newlineIndex + 1);
134
+
135
+ if (line.length === 0) {
136
+ continue;
137
+ }
138
+
139
+ try {
140
+ await this.processMessage(line);
141
+ } catch (error) {
142
+ this.logger.error('Error processing message', { line, error });
143
+ }
144
+ }
145
+ }
146
+
147
+ private async processMessage(line: string): Promise<void> {
148
+ let message: any;
149
+
150
+ try {
151
+ message = JSON.parse(line);
152
+
153
+ if (!message.jsonrpc || message.jsonrpc !== '2.0') {
154
+ throw new Error('Invalid JSON-RPC version');
155
+ }
156
+
157
+ if (!message.method) {
158
+ throw new Error('Missing method');
159
+ }
160
+ } catch (error) {
161
+ this.logger.error('Failed to parse message', { line, error });
162
+
163
+ // Send error response if we can extract an ID
164
+ let id = 'unknown';
165
+ try {
166
+ const parsed = JSON.parse(line);
167
+ if (parsed.id !== undefined) {
168
+ id = parsed.id;
169
+ }
170
+ } catch {
171
+ // Ignore parse error for ID extraction
172
+ }
173
+
174
+ await this.sendResponse({
175
+ jsonrpc: '2.0',
176
+ id,
177
+ error: {
178
+ code: -32700,
179
+ message: 'Parse error',
180
+ },
181
+ });
182
+ return;
183
+ }
184
+
185
+ this.messageCount++;
186
+
187
+ // Check if this is a notification (no id field) or a request
188
+ if (message.id === undefined) {
189
+ // This is a notification
190
+ await this.handleNotification(message as MCPNotification);
191
+ } else {
192
+ // This is a request
193
+ await this.handleRequest(message as MCPRequest);
194
+ }
195
+ }
196
+
197
+ private async handleRequest(request: MCPRequest): Promise<void> {
198
+ if (!this.requestHandler) {
199
+ await this.sendResponse({
200
+ jsonrpc: '2.0',
201
+ id: request.id,
202
+ error: {
203
+ code: -32603,
204
+ message: 'No request handler registered',
205
+ },
206
+ });
207
+ return;
208
+ }
209
+
210
+ try {
211
+ const response = await this.requestHandler(request);
212
+ await this.sendResponse(response);
213
+ } catch (error) {
214
+ this.logger.error('Request handler error', { request, error });
215
+
216
+ await this.sendResponse({
217
+ jsonrpc: '2.0',
218
+ id: request.id,
219
+ error: {
220
+ code: -32603,
221
+ message: 'Internal error',
222
+ data: error instanceof Error ? error.message : String(error),
223
+ },
224
+ });
225
+ }
226
+ }
227
+
228
+ private async handleNotification(notification: MCPNotification): Promise<void> {
229
+ if (!this.notificationHandler) {
230
+ this.logger.warn('Received notification but no handler registered', {
231
+ method: notification.method,
232
+ });
233
+ return;
234
+ }
235
+
236
+ try {
237
+ await this.notificationHandler(notification);
238
+ } catch (error) {
239
+ this.logger.error('Notification handler error', { notification, error });
240
+ // Notifications don't send error responses
241
+ }
242
+ }
243
+
244
+ private async sendResponse(response: MCPResponse): Promise<void> {
245
+ try {
246
+ const json = JSON.stringify(response);
247
+ const data = this.encoder.encode(json + '\n');
248
+
249
+ await Deno.stdout.write(data);
250
+ } catch (error) {
251
+ this.logger.error('Failed to send response', { response, error });
252
+ }
253
+ }
254
+ }