@claude-flow/mcp 3.0.0-alpha.1
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.
- package/.agentic-flow/intelligence.json +16 -0
- package/README.md +428 -0
- package/__tests__/integration.test.ts +449 -0
- package/__tests__/mcp.test.ts +641 -0
- package/dist/connection-pool.d.ts +36 -0
- package/dist/connection-pool.d.ts.map +1 -0
- package/dist/connection-pool.js +273 -0
- package/dist/connection-pool.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +85 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth.d.ts +146 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +318 -0
- package/dist/oauth.js.map +1 -0
- package/dist/prompt-registry.d.ts +90 -0
- package/dist/prompt-registry.d.ts.map +1 -0
- package/dist/prompt-registry.js +209 -0
- package/dist/prompt-registry.js.map +1 -0
- package/dist/rate-limiter.d.ts +86 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +197 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/resource-registry.d.ts +144 -0
- package/dist/resource-registry.d.ts.map +1 -0
- package/dist/resource-registry.js +405 -0
- package/dist/resource-registry.js.map +1 -0
- package/dist/sampling.d.ts +102 -0
- package/dist/sampling.d.ts.map +1 -0
- package/dist/sampling.js +268 -0
- package/dist/sampling.js.map +1 -0
- package/dist/schema-validator.d.ts +30 -0
- package/dist/schema-validator.d.ts.map +1 -0
- package/dist/schema-validator.js +182 -0
- package/dist/schema-validator.js.map +1 -0
- package/dist/server.d.ts +122 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +829 -0
- package/dist/server.js.map +1 -0
- package/dist/session-manager.d.ts +55 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +252 -0
- package/dist/session-manager.js.map +1 -0
- package/dist/task-manager.d.ts +81 -0
- package/dist/task-manager.d.ts.map +1 -0
- package/dist/task-manager.js +337 -0
- package/dist/task-manager.js.map +1 -0
- package/dist/tool-registry.d.ts +88 -0
- package/dist/tool-registry.d.ts.map +1 -0
- package/dist/tool-registry.js +353 -0
- package/dist/tool-registry.js.map +1 -0
- package/dist/transport/http.d.ts +55 -0
- package/dist/transport/http.d.ts.map +1 -0
- package/dist/transport/http.js +446 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/transport/index.d.ts +50 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +181 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/stdio.d.ts +43 -0
- package/dist/transport/stdio.d.ts.map +1 -0
- package/dist/transport/stdio.js +194 -0
- package/dist/transport/stdio.js.map +1 -0
- package/dist/transport/websocket.d.ts +65 -0
- package/dist/transport/websocket.d.ts.map +1 -0
- package/dist/transport/websocket.js +314 -0
- package/dist/transport/websocket.js.map +1 -0
- package/dist/types.d.ts +473 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +40 -0
- package/dist/types.js.map +1 -0
- package/package.json +42 -0
- package/src/connection-pool.ts +344 -0
- package/src/index.ts +253 -0
- package/src/oauth.ts +447 -0
- package/src/prompt-registry.ts +296 -0
- package/src/rate-limiter.ts +266 -0
- package/src/resource-registry.ts +530 -0
- package/src/sampling.ts +363 -0
- package/src/schema-validator.ts +213 -0
- package/src/server.ts +1134 -0
- package/src/session-manager.ts +339 -0
- package/src/task-manager.ts +427 -0
- package/src/tool-registry.ts +475 -0
- package/src/transport/http.ts +532 -0
- package/src/transport/index.ts +233 -0
- package/src/transport/stdio.ts +252 -0
- package/src/transport/websocket.ts +396 -0
- package/src/types.ts +664 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +13 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @claude-flow/mcp - Transport Factory
|
|
3
|
+
*
|
|
4
|
+
* Central factory for creating transport instances
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
ITransport,
|
|
9
|
+
TransportType,
|
|
10
|
+
TransportHealthStatus,
|
|
11
|
+
ILogger,
|
|
12
|
+
} from '../types.js';
|
|
13
|
+
import { StdioTransport, StdioTransportConfig, createStdioTransport } from './stdio.js';
|
|
14
|
+
import { HttpTransport, HttpTransportConfig, createHttpTransport } from './http.js';
|
|
15
|
+
import { WebSocketTransport, WebSocketTransportConfig, createWebSocketTransport } from './websocket.js';
|
|
16
|
+
|
|
17
|
+
export { StdioTransport } from './stdio.js';
|
|
18
|
+
export { HttpTransport } from './http.js';
|
|
19
|
+
export { WebSocketTransport } from './websocket.js';
|
|
20
|
+
|
|
21
|
+
export type { StdioTransportConfig } from './stdio.js';
|
|
22
|
+
export type { HttpTransportConfig } from './http.js';
|
|
23
|
+
export type { WebSocketTransportConfig } from './websocket.js';
|
|
24
|
+
|
|
25
|
+
export type TransportConfig =
|
|
26
|
+
| { type: 'stdio' } & StdioTransportConfig
|
|
27
|
+
| { type: 'http' } & HttpTransportConfig
|
|
28
|
+
| { type: 'websocket' } & WebSocketTransportConfig
|
|
29
|
+
| { type: 'in-process' };
|
|
30
|
+
|
|
31
|
+
export function createTransport(
|
|
32
|
+
type: TransportType,
|
|
33
|
+
logger: ILogger,
|
|
34
|
+
config?: Partial<TransportConfig>
|
|
35
|
+
): ITransport {
|
|
36
|
+
switch (type) {
|
|
37
|
+
case 'stdio':
|
|
38
|
+
return createStdioTransport(logger, config as StdioTransportConfig);
|
|
39
|
+
|
|
40
|
+
case 'http':
|
|
41
|
+
if (!config || !('host' in config) || !('port' in config)) {
|
|
42
|
+
throw new Error('HTTP transport requires host and port configuration');
|
|
43
|
+
}
|
|
44
|
+
return createHttpTransport(logger, {
|
|
45
|
+
host: config.host as string,
|
|
46
|
+
port: config.port as number,
|
|
47
|
+
...config,
|
|
48
|
+
} as HttpTransportConfig);
|
|
49
|
+
|
|
50
|
+
case 'websocket':
|
|
51
|
+
if (!config || !('host' in config) || !('port' in config)) {
|
|
52
|
+
throw new Error('WebSocket transport requires host and port configuration');
|
|
53
|
+
}
|
|
54
|
+
return createWebSocketTransport(logger, {
|
|
55
|
+
host: config.host as string,
|
|
56
|
+
port: config.port as number,
|
|
57
|
+
...config,
|
|
58
|
+
} as WebSocketTransportConfig);
|
|
59
|
+
|
|
60
|
+
case 'in-process':
|
|
61
|
+
return createInProcessTransport(logger);
|
|
62
|
+
|
|
63
|
+
default:
|
|
64
|
+
throw new Error(`Unknown transport type: ${type}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
class InProcessTransport implements ITransport {
|
|
69
|
+
public readonly type: TransportType = 'in-process';
|
|
70
|
+
|
|
71
|
+
constructor(private readonly logger: ILogger) {}
|
|
72
|
+
|
|
73
|
+
async start(): Promise<void> {
|
|
74
|
+
this.logger.debug('In-process transport started');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async stop(): Promise<void> {
|
|
78
|
+
this.logger.debug('In-process transport stopped');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
onRequest(): void {
|
|
82
|
+
// No-op - requests are handled directly
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
onNotification(): void {
|
|
86
|
+
// No-op - notifications are handled directly
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async getHealthStatus(): Promise<TransportHealthStatus> {
|
|
90
|
+
return {
|
|
91
|
+
healthy: true,
|
|
92
|
+
metrics: {
|
|
93
|
+
latency: 0,
|
|
94
|
+
connections: 1,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function createInProcessTransport(logger: ILogger): ITransport {
|
|
101
|
+
return new InProcessTransport(logger);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export class TransportManager {
|
|
105
|
+
private transports: Map<string, ITransport> = new Map();
|
|
106
|
+
private running = false;
|
|
107
|
+
|
|
108
|
+
constructor(private readonly logger: ILogger) {}
|
|
109
|
+
|
|
110
|
+
addTransport(name: string, transport: ITransport): void {
|
|
111
|
+
if (this.transports.has(name)) {
|
|
112
|
+
throw new Error(`Transport "${name}" already exists`);
|
|
113
|
+
}
|
|
114
|
+
this.transports.set(name, transport);
|
|
115
|
+
this.logger.debug('Transport added', { name, type: transport.type });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async removeTransport(name: string): Promise<boolean> {
|
|
119
|
+
const transport = this.transports.get(name);
|
|
120
|
+
if (!transport) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
await transport.stop();
|
|
125
|
+
this.transports.delete(name);
|
|
126
|
+
this.logger.debug('Transport removed', { name });
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getTransport(name: string): ITransport | undefined {
|
|
131
|
+
return this.transports.get(name);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
getTransportNames(): string[] {
|
|
135
|
+
return Array.from(this.transports.keys());
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async startAll(): Promise<void> {
|
|
139
|
+
if (this.running) {
|
|
140
|
+
throw new Error('TransportManager already running');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
this.logger.info('Starting all transports', { count: this.transports.size });
|
|
144
|
+
|
|
145
|
+
const startPromises = Array.from(this.transports.entries()).map(
|
|
146
|
+
async ([name, transport]) => {
|
|
147
|
+
try {
|
|
148
|
+
await transport.start();
|
|
149
|
+
this.logger.info('Transport started', { name, type: transport.type });
|
|
150
|
+
} catch (error) {
|
|
151
|
+
this.logger.error('Failed to start transport', { name, error });
|
|
152
|
+
throw error;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
await Promise.all(startPromises);
|
|
158
|
+
this.running = true;
|
|
159
|
+
this.logger.info('All transports started');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async stopAll(): Promise<void> {
|
|
163
|
+
if (!this.running) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
this.logger.info('Stopping all transports');
|
|
168
|
+
|
|
169
|
+
const stopPromises = Array.from(this.transports.entries()).map(
|
|
170
|
+
async ([name, transport]) => {
|
|
171
|
+
try {
|
|
172
|
+
await transport.stop();
|
|
173
|
+
this.logger.info('Transport stopped', { name });
|
|
174
|
+
} catch (error) {
|
|
175
|
+
this.logger.error('Error stopping transport', { name, error });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
await Promise.all(stopPromises);
|
|
181
|
+
this.running = false;
|
|
182
|
+
this.logger.info('All transports stopped');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async getHealthStatus(): Promise<Record<string, { healthy: boolean; error?: string }>> {
|
|
186
|
+
const results: Record<string, { healthy: boolean; error?: string }> = {};
|
|
187
|
+
|
|
188
|
+
for (const [name, transport] of this.transports) {
|
|
189
|
+
try {
|
|
190
|
+
const status = await transport.getHealthStatus();
|
|
191
|
+
results[name] = { healthy: status.healthy, error: status.error };
|
|
192
|
+
} catch (error) {
|
|
193
|
+
results[name] = {
|
|
194
|
+
healthy: false,
|
|
195
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return results;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
isRunning(): boolean {
|
|
204
|
+
return this.running;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function createTransportManager(logger: ILogger): TransportManager {
|
|
209
|
+
return new TransportManager(logger);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export const DEFAULT_TRANSPORT_CONFIGS = {
|
|
213
|
+
stdio: {} as StdioTransportConfig,
|
|
214
|
+
|
|
215
|
+
http: {
|
|
216
|
+
host: 'localhost',
|
|
217
|
+
port: 3000,
|
|
218
|
+
corsEnabled: true,
|
|
219
|
+
corsOrigins: ['*'],
|
|
220
|
+
maxRequestSize: '10mb',
|
|
221
|
+
requestTimeout: 30000,
|
|
222
|
+
} as HttpTransportConfig,
|
|
223
|
+
|
|
224
|
+
websocket: {
|
|
225
|
+
host: 'localhost',
|
|
226
|
+
port: 3001,
|
|
227
|
+
path: '/ws',
|
|
228
|
+
maxConnections: 100,
|
|
229
|
+
heartbeatInterval: 30000,
|
|
230
|
+
heartbeatTimeout: 10000,
|
|
231
|
+
maxMessageSize: 10 * 1024 * 1024,
|
|
232
|
+
} as WebSocketTransportConfig,
|
|
233
|
+
} as const;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @claude-flow/mcp - Stdio Transport
|
|
3
|
+
*
|
|
4
|
+
* Standard I/O transport for MCP communication
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { EventEmitter } from 'events';
|
|
8
|
+
import * as readline from 'readline';
|
|
9
|
+
import type {
|
|
10
|
+
ITransport,
|
|
11
|
+
TransportType,
|
|
12
|
+
MCPRequest,
|
|
13
|
+
MCPResponse,
|
|
14
|
+
MCPNotification,
|
|
15
|
+
RequestHandler,
|
|
16
|
+
NotificationHandler,
|
|
17
|
+
TransportHealthStatus,
|
|
18
|
+
ILogger,
|
|
19
|
+
} from '../types.js';
|
|
20
|
+
|
|
21
|
+
export interface StdioTransportConfig {
|
|
22
|
+
inputStream?: NodeJS.ReadableStream;
|
|
23
|
+
outputStream?: NodeJS.WritableStream;
|
|
24
|
+
maxMessageSize?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class StdioTransport extends EventEmitter implements ITransport {
|
|
28
|
+
public readonly type: TransportType = 'stdio';
|
|
29
|
+
|
|
30
|
+
private requestHandler?: RequestHandler;
|
|
31
|
+
private notificationHandler?: NotificationHandler;
|
|
32
|
+
private rl?: readline.Interface;
|
|
33
|
+
private running = false;
|
|
34
|
+
|
|
35
|
+
private messagesReceived = 0;
|
|
36
|
+
private messagesSent = 0;
|
|
37
|
+
private errors = 0;
|
|
38
|
+
|
|
39
|
+
private readonly inputStream: NodeJS.ReadableStream;
|
|
40
|
+
private readonly outputStream: NodeJS.WritableStream;
|
|
41
|
+
private readonly maxMessageSize: number;
|
|
42
|
+
|
|
43
|
+
constructor(
|
|
44
|
+
private readonly logger: ILogger,
|
|
45
|
+
config: StdioTransportConfig = {}
|
|
46
|
+
) {
|
|
47
|
+
super();
|
|
48
|
+
this.inputStream = config.inputStream || process.stdin;
|
|
49
|
+
this.outputStream = config.outputStream || process.stdout;
|
|
50
|
+
this.maxMessageSize = config.maxMessageSize || 10 * 1024 * 1024;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async start(): Promise<void> {
|
|
54
|
+
if (this.running) {
|
|
55
|
+
throw new Error('Stdio transport already running');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.logger.info('Starting stdio transport');
|
|
59
|
+
|
|
60
|
+
this.rl = readline.createInterface({
|
|
61
|
+
input: this.inputStream,
|
|
62
|
+
crlfDelay: Infinity,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
this.rl.on('line', (line) => {
|
|
66
|
+
this.handleLine(line);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
this.rl.on('close', () => {
|
|
70
|
+
this.handleClose();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
this.inputStream.on('error', (error) => {
|
|
74
|
+
this.handleError(error);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
this.running = true;
|
|
78
|
+
this.logger.info('Stdio transport started');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async stop(): Promise<void> {
|
|
82
|
+
if (!this.running) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.logger.info('Stopping stdio transport');
|
|
87
|
+
this.running = false;
|
|
88
|
+
|
|
89
|
+
if (this.rl) {
|
|
90
|
+
this.rl.close();
|
|
91
|
+
this.rl = undefined;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
this.logger.info('Stdio transport stopped');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
onRequest(handler: RequestHandler): void {
|
|
98
|
+
this.requestHandler = handler;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
onNotification(handler: NotificationHandler): void {
|
|
102
|
+
this.notificationHandler = handler;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async getHealthStatus(): Promise<TransportHealthStatus> {
|
|
106
|
+
return {
|
|
107
|
+
healthy: this.running,
|
|
108
|
+
metrics: {
|
|
109
|
+
messagesReceived: this.messagesReceived,
|
|
110
|
+
messagesSent: this.messagesSent,
|
|
111
|
+
errors: this.errors,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private async handleLine(line: string): Promise<void> {
|
|
117
|
+
if (!line.trim()) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (line.length > this.maxMessageSize) {
|
|
122
|
+
this.logger.error('Message exceeds maximum size', {
|
|
123
|
+
size: line.length,
|
|
124
|
+
max: this.maxMessageSize,
|
|
125
|
+
});
|
|
126
|
+
this.errors++;
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const message = JSON.parse(line);
|
|
132
|
+
this.messagesReceived++;
|
|
133
|
+
|
|
134
|
+
if (message.jsonrpc !== '2.0') {
|
|
135
|
+
this.logger.warn('Invalid JSON-RPC version', { received: message.jsonrpc });
|
|
136
|
+
await this.sendError(message.id, -32600, 'Invalid JSON-RPC version');
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!message.method) {
|
|
141
|
+
this.logger.warn('Missing method in request');
|
|
142
|
+
await this.sendError(message.id, -32600, 'Missing method');
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (message.id !== undefined) {
|
|
147
|
+
await this.handleRequest(message as MCPRequest);
|
|
148
|
+
} else {
|
|
149
|
+
await this.handleNotification(message as MCPNotification);
|
|
150
|
+
}
|
|
151
|
+
} catch (error) {
|
|
152
|
+
this.errors++;
|
|
153
|
+
this.logger.error('Failed to parse message', { error, line: line.substring(0, 100) });
|
|
154
|
+
await this.sendError(null, -32700, 'Parse error');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private async handleRequest(request: MCPRequest): Promise<void> {
|
|
159
|
+
if (!this.requestHandler) {
|
|
160
|
+
this.logger.warn('No request handler registered');
|
|
161
|
+
await this.sendError(request.id, -32603, 'No request handler');
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const startTime = performance.now();
|
|
167
|
+
const response = await this.requestHandler(request);
|
|
168
|
+
const duration = performance.now() - startTime;
|
|
169
|
+
|
|
170
|
+
this.logger.debug('Request processed', {
|
|
171
|
+
method: request.method,
|
|
172
|
+
duration: `${duration.toFixed(2)}ms`,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
await this.sendResponse(response);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
this.logger.error('Request handler error', { method: request.method, error });
|
|
178
|
+
await this.sendError(
|
|
179
|
+
request.id,
|
|
180
|
+
-32603,
|
|
181
|
+
error instanceof Error ? error.message : 'Internal error'
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private async handleNotification(notification: MCPNotification): Promise<void> {
|
|
187
|
+
if (!this.notificationHandler) {
|
|
188
|
+
this.logger.debug('Notification received but no handler', { method: notification.method });
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
await this.notificationHandler(notification);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
this.logger.error('Notification handler error', { method: notification.method, error });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private async sendResponse(response: MCPResponse): Promise<void> {
|
|
200
|
+
const json = JSON.stringify(response);
|
|
201
|
+
await this.write(json);
|
|
202
|
+
this.messagesSent++;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private async sendError(id: string | number | null, code: number, message: string): Promise<void> {
|
|
206
|
+
const response: MCPResponse = {
|
|
207
|
+
jsonrpc: '2.0',
|
|
208
|
+
id,
|
|
209
|
+
error: { code, message },
|
|
210
|
+
};
|
|
211
|
+
await this.sendResponse(response);
|
|
212
|
+
this.errors++;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async sendNotification(notification: MCPNotification): Promise<void> {
|
|
216
|
+
const json = JSON.stringify(notification);
|
|
217
|
+
await this.write(json);
|
|
218
|
+
this.messagesSent++;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private write(data: string): Promise<void> {
|
|
222
|
+
return new Promise((resolve, reject) => {
|
|
223
|
+
this.outputStream.write(data + '\n', (error) => {
|
|
224
|
+
if (error) {
|
|
225
|
+
this.errors++;
|
|
226
|
+
reject(error);
|
|
227
|
+
} else {
|
|
228
|
+
resolve();
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private handleClose(): void {
|
|
235
|
+
this.logger.info('Stdio stream closed');
|
|
236
|
+
this.running = false;
|
|
237
|
+
this.emit('close');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private handleError(error: Error): void {
|
|
241
|
+
this.logger.error('Stdio stream error', error);
|
|
242
|
+
this.errors++;
|
|
243
|
+
this.emit('error', error);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function createStdioTransport(
|
|
248
|
+
logger: ILogger,
|
|
249
|
+
config: StdioTransportConfig = {}
|
|
250
|
+
): StdioTransport {
|
|
251
|
+
return new StdioTransport(logger, config);
|
|
252
|
+
}
|