@mcpilotx/intentorch 0.5.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.
- package/LICENSE +201 -0
- package/README.md +545 -0
- package/dist/ai/ai.d.ts +205 -0
- package/dist/ai/ai.js +1200 -0
- package/dist/ai/cloud-intent-engine.d.ts +270 -0
- package/dist/ai/cloud-intent-engine.js +956 -0
- package/dist/ai/command.d.ts +59 -0
- package/dist/ai/command.js +285 -0
- package/dist/ai/config.d.ts +66 -0
- package/dist/ai/config.js +211 -0
- package/dist/ai/enhanced-intent.d.ts +17 -0
- package/dist/ai/enhanced-intent.js +32 -0
- package/dist/ai/index.d.ts +29 -0
- package/dist/ai/index.js +44 -0
- package/dist/ai/intent.d.ts +16 -0
- package/dist/ai/intent.js +30 -0
- package/dist/core/ai-config.d.ts +25 -0
- package/dist/core/ai-config.js +326 -0
- package/dist/core/config-manager.d.ts +36 -0
- package/dist/core/config-manager.js +400 -0
- package/dist/core/config-validator.d.ts +9 -0
- package/dist/core/config-validator.js +184 -0
- package/dist/core/constants.d.ts +34 -0
- package/dist/core/constants.js +37 -0
- package/dist/core/error-ai.d.ts +23 -0
- package/dist/core/error-ai.js +217 -0
- package/dist/core/error-handler.d.ts +197 -0
- package/dist/core/error-handler.js +467 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +17 -0
- package/dist/core/logger.d.ts +27 -0
- package/dist/core/logger.js +108 -0
- package/dist/core/performance-monitor.d.ts +74 -0
- package/dist/core/performance-monitor.js +260 -0
- package/dist/core/providers.d.ts +36 -0
- package/dist/core/providers.js +304 -0
- package/dist/core/retry-manager.d.ts +41 -0
- package/dist/core/retry-manager.js +204 -0
- package/dist/core/types.d.ts +155 -0
- package/dist/core/types.js +2 -0
- package/dist/daemon/index.d.ts +10 -0
- package/dist/daemon/index.js +15 -0
- package/dist/daemon/intent-engine.d.ts +22 -0
- package/dist/daemon/intent-engine.js +50 -0
- package/dist/daemon/orchestrator.d.ts +24 -0
- package/dist/daemon/orchestrator.js +100 -0
- package/dist/daemon/pm.d.ts +33 -0
- package/dist/daemon/pm.js +127 -0
- package/dist/daemon/process.d.ts +11 -0
- package/dist/daemon/process.js +49 -0
- package/dist/daemon/server.d.ts +17 -0
- package/dist/daemon/server.js +435 -0
- package/dist/daemon/service.d.ts +36 -0
- package/dist/daemon/service.js +278 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +36 -0
- package/dist/mcp/client.d.ts +51 -0
- package/dist/mcp/client.js +276 -0
- package/dist/mcp/index.d.ts +162 -0
- package/dist/mcp/index.js +199 -0
- package/dist/mcp/tool-registry.d.ts +71 -0
- package/dist/mcp/tool-registry.js +308 -0
- package/dist/mcp/transport.d.ts +83 -0
- package/dist/mcp/transport.js +515 -0
- package/dist/mcp/types.d.ts +136 -0
- package/dist/mcp/types.js +31 -0
- package/dist/runtime/adapter-advanced.d.ts +184 -0
- package/dist/runtime/adapter-advanced.js +160 -0
- package/dist/runtime/adapter.d.ts +9 -0
- package/dist/runtime/adapter.js +2 -0
- package/dist/runtime/detector-advanced.d.ts +59 -0
- package/dist/runtime/detector-advanced.js +487 -0
- package/dist/runtime/detector.d.ts +5 -0
- package/dist/runtime/detector.js +56 -0
- package/dist/runtime/docker-adapter.d.ts +18 -0
- package/dist/runtime/docker-adapter.js +170 -0
- package/dist/runtime/docker.d.ts +17 -0
- package/dist/runtime/docker.js +71 -0
- package/dist/runtime/executable-analyzer.d.ts +56 -0
- package/dist/runtime/executable-analyzer.js +391 -0
- package/dist/runtime/go-adapter.d.ts +19 -0
- package/dist/runtime/go-adapter.js +190 -0
- package/dist/runtime/index.d.ts +9 -0
- package/dist/runtime/index.js +10 -0
- package/dist/runtime/node-adapter.d.ts +10 -0
- package/dist/runtime/node-adapter.js +23 -0
- package/dist/runtime/node.d.ts +20 -0
- package/dist/runtime/node.js +86 -0
- package/dist/runtime/python-adapter.d.ts +11 -0
- package/dist/runtime/python-adapter.js +102 -0
- package/dist/runtime/python.d.ts +17 -0
- package/dist/runtime/python.js +72 -0
- package/dist/runtime/rust-adapter.d.ts +21 -0
- package/dist/runtime/rust-adapter.js +267 -0
- package/dist/sdk.d.ts +500 -0
- package/dist/sdk.js +904 -0
- package/docs/README.ZH_CN.md +545 -0
- package/docs/api.md +888 -0
- package/docs/architecture.md +731 -0
- package/docs/development.md +744 -0
- package/package.json +112 -0
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Transport Layer Abstraction
|
|
3
|
+
* Supports stdio, HTTP, SSE and other transport methods
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
export class BaseTransport extends EventEmitter {
|
|
7
|
+
config;
|
|
8
|
+
connected = false;
|
|
9
|
+
jsonBuffer = '';
|
|
10
|
+
bufferTimeout = null;
|
|
11
|
+
lastBufferUpdate = 0;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
super();
|
|
14
|
+
this.config = config;
|
|
15
|
+
}
|
|
16
|
+
isConnected() {
|
|
17
|
+
return this.connected;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Clear the JSON buffer and any associated timeout
|
|
21
|
+
*/
|
|
22
|
+
clearBuffer() {
|
|
23
|
+
this.jsonBuffer = '';
|
|
24
|
+
if (this.bufferTimeout) {
|
|
25
|
+
clearTimeout(this.bufferTimeout);
|
|
26
|
+
this.bufferTimeout = null;
|
|
27
|
+
}
|
|
28
|
+
this.lastBufferUpdate = 0;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Check if a string looks like it could be part of a JSON object
|
|
32
|
+
*/
|
|
33
|
+
looksLikeJsonChunk(text) {
|
|
34
|
+
const trimmed = text.trim();
|
|
35
|
+
if (!trimmed) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
// Check for JSON-like patterns (more flexible matching)
|
|
39
|
+
const jsonLikePatterns = [
|
|
40
|
+
/^\{/, // Starts with {
|
|
41
|
+
/^\}/, // Starts with }
|
|
42
|
+
/^\[/, // Starts with [
|
|
43
|
+
/^\]/, // Starts with ]
|
|
44
|
+
/^\s*"[^"]*"\s*:/, // Key-value pair with optional whitespace
|
|
45
|
+
/^\s*\d+\s*,?\s*$/, // Number with optional comma and whitespace
|
|
46
|
+
/^\s*"[^"]*"\s*,?\s*$/, // String with optional comma and whitespace
|
|
47
|
+
/^\s*(true|false|null)\s*,?\s*$/i, // Boolean or null with optional comma
|
|
48
|
+
/^[\[\]{},:]$/, // Single JSON structure characters
|
|
49
|
+
/^\s*"\w+"\s*:/, // Alternative key pattern
|
|
50
|
+
];
|
|
51
|
+
return jsonLikePatterns.some(pattern => pattern.test(trimmed));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Try to parse buffer as JSON, returns parsed object or null
|
|
55
|
+
*/
|
|
56
|
+
tryParseBuffer() {
|
|
57
|
+
if (!this.jsonBuffer.trim()) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const parsed = JSON.parse(this.jsonBuffer);
|
|
62
|
+
// Return any valid JSON, not just JSONRPC messages
|
|
63
|
+
return parsed;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// Not valid JSON yet
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Process a line of text, handling JSON that may span multiple lines
|
|
72
|
+
*/
|
|
73
|
+
processLine(line) {
|
|
74
|
+
const results = [];
|
|
75
|
+
const trimmed = line.trim();
|
|
76
|
+
if (!trimmed) {
|
|
77
|
+
return results;
|
|
78
|
+
}
|
|
79
|
+
// Update buffer timeout
|
|
80
|
+
this.lastBufferUpdate = Date.now();
|
|
81
|
+
const bufferTimeoutMs = this.config.logFilter?.timeout || 1000; // Default 1 second
|
|
82
|
+
if (this.bufferTimeout) {
|
|
83
|
+
clearTimeout(this.bufferTimeout);
|
|
84
|
+
}
|
|
85
|
+
this.bufferTimeout = setTimeout(() => {
|
|
86
|
+
if (this.jsonBuffer) {
|
|
87
|
+
console.warn(`[MCP Transport] JSON buffer timeout, clearing buffer: ${this.jsonBuffer.substring(0, 100)}...`);
|
|
88
|
+
this.clearBuffer();
|
|
89
|
+
}
|
|
90
|
+
}, bufferTimeoutMs);
|
|
91
|
+
// Check if this looks like JSON or could be part of JSON
|
|
92
|
+
const looksLikeJsonChunk = this.looksLikeJsonChunk(trimmed);
|
|
93
|
+
const looksLikeCompleteJson = this.looksLikeJsonMessage(trimmed);
|
|
94
|
+
if (looksLikeJsonChunk || looksLikeCompleteJson) {
|
|
95
|
+
// Add to buffer
|
|
96
|
+
this.jsonBuffer += (this.jsonBuffer ? '\n' : '') + trimmed;
|
|
97
|
+
// Try to parse the buffer
|
|
98
|
+
const parsed = this.tryParseBuffer();
|
|
99
|
+
if (parsed) {
|
|
100
|
+
results.push({ type: 'json', data: parsed });
|
|
101
|
+
this.clearBuffer();
|
|
102
|
+
}
|
|
103
|
+
else if (looksLikeCompleteJson) {
|
|
104
|
+
// Looks like complete JSON but can't parse, might be malformed
|
|
105
|
+
// Clear buffer to avoid infinite accumulation
|
|
106
|
+
console.warn(`[MCP Transport] JSON-like message but cannot parse, clearing buffer: ${trimmed.substring(0, 100)}...`);
|
|
107
|
+
this.clearBuffer();
|
|
108
|
+
}
|
|
109
|
+
// If not parsable yet, wait for more data
|
|
110
|
+
return results;
|
|
111
|
+
}
|
|
112
|
+
// Not JSON-like, clear any existing buffer (incomplete JSON)
|
|
113
|
+
if (this.jsonBuffer) {
|
|
114
|
+
console.warn(`[MCP Transport] Incomplete JSON in buffer, clearing: ${this.jsonBuffer.substring(0, 100)}...`);
|
|
115
|
+
this.clearBuffer();
|
|
116
|
+
}
|
|
117
|
+
// Check if it's a log message
|
|
118
|
+
const isLogMessage = this.isLogMessage(trimmed);
|
|
119
|
+
if (isLogMessage) {
|
|
120
|
+
results.push({ type: 'log', content: trimmed });
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// Try one more time to parse as complete JSON (single line)
|
|
124
|
+
try {
|
|
125
|
+
const jsonData = JSON.parse(trimmed);
|
|
126
|
+
if (jsonData && typeof jsonData === 'object' && jsonData.jsonrpc === '2.0') {
|
|
127
|
+
results.push({ type: 'json', data: jsonData });
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// Valid JSON but not JSONRPC
|
|
131
|
+
results.push({ type: 'log', content: trimmed });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Not valid JSON, treat as unrecognized log
|
|
136
|
+
console.warn(`[MCP Server] Unrecognized message: ${trimmed}`);
|
|
137
|
+
results.push({ type: 'log', content: `[Unrecognized] ${trimmed}` });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return results;
|
|
141
|
+
}
|
|
142
|
+
handleMessage(data) {
|
|
143
|
+
// Use improved message processor
|
|
144
|
+
const messages = this.processStdioOutput(data);
|
|
145
|
+
for (const message of messages) {
|
|
146
|
+
if (message.type === 'json') {
|
|
147
|
+
this.emit('message', message.data);
|
|
148
|
+
}
|
|
149
|
+
else if (message.type === 'log') {
|
|
150
|
+
// Log but don't treat as error
|
|
151
|
+
console.log(`[MCP Server stdout] ${message.content}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Process stdio output, intelligently separate JSON messages and logs
|
|
157
|
+
*/
|
|
158
|
+
processStdioOutput(data) {
|
|
159
|
+
const results = [];
|
|
160
|
+
const lines = data.split('\n');
|
|
161
|
+
for (const line of lines) {
|
|
162
|
+
const lineResults = this.processLine(line);
|
|
163
|
+
results.push(...lineResults);
|
|
164
|
+
}
|
|
165
|
+
return results;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Check if a message looks like JSON (more comprehensive check)
|
|
169
|
+
*/
|
|
170
|
+
looksLikeJsonMessage(message) {
|
|
171
|
+
const trimmed = message.trim();
|
|
172
|
+
// Quick checks for common JSON structures
|
|
173
|
+
if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
// Check for JSON-like content (more strict)
|
|
180
|
+
const jsonIndicators = [
|
|
181
|
+
/^\s*\{.*\}\s*$/, // Object with content
|
|
182
|
+
/^\s*\[.*\]\s*$/, // Array with content
|
|
183
|
+
/^\s*\{\s*\}\s*$/, // Empty object
|
|
184
|
+
/^\s*\[\s*\]\s*$/, // Empty array
|
|
185
|
+
/^\s*\d+(\.\d+)?\s*$/, // Number (integer or float)
|
|
186
|
+
/^\s*"(?:[^"\\]|\\.)*"\s*$/, // String
|
|
187
|
+
/^\s*(?:true|false|null)\s*$/, // Primitive
|
|
188
|
+
];
|
|
189
|
+
// Additional check: must have at least some content between braces/brackets
|
|
190
|
+
// or be a primitive value
|
|
191
|
+
const hasJsonStructure = jsonIndicators.some(pattern => pattern.test(trimmed));
|
|
192
|
+
if (hasJsonStructure) {
|
|
193
|
+
// For objects/arrays, ensure they have proper structure
|
|
194
|
+
if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
|
|
195
|
+
// Check if it has at least a key-value pair or is empty
|
|
196
|
+
const content = trimmed.slice(1, -1).trim();
|
|
197
|
+
return content === '' || content.includes(':');
|
|
198
|
+
}
|
|
199
|
+
if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
|
|
200
|
+
// Arrays are simpler
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
// For other JSON types (numbers, strings, primitives)
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Determine if a message is a log message using multiple detection strategies
|
|
210
|
+
*/
|
|
211
|
+
isLogMessage(message) {
|
|
212
|
+
const trimmed = message.trim();
|
|
213
|
+
// Empty message is not a log
|
|
214
|
+
if (!trimmed) {
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
// Get configured patterns
|
|
218
|
+
const configPatterns = this.config.logFilter?.ignorePatterns || [];
|
|
219
|
+
const keepPatterns = this.config.logFilter?.keepPatterns || [];
|
|
220
|
+
// Strategy 1: Check keep patterns (highest priority)
|
|
221
|
+
for (const patternStr of keepPatterns) {
|
|
222
|
+
try {
|
|
223
|
+
const pattern = new RegExp(patternStr);
|
|
224
|
+
if (pattern.test(trimmed)) {
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
console.warn(`[MCP Transport] Invalid keep pattern regex: ${patternStr}`, error);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Strategy 2: Check ignore patterns (second priority)
|
|
233
|
+
for (const patternStr of configPatterns) {
|
|
234
|
+
try {
|
|
235
|
+
const pattern = new RegExp(patternStr);
|
|
236
|
+
if (pattern.test(trimmed)) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
console.warn(`[MCP Transport] Invalid ignore pattern regex: ${patternStr}`, error);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Strategy 3: Check if it looks like JSON (not a log)
|
|
245
|
+
if (this.looksLikeJsonMessage(trimmed)) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
// Strategy 4: Check common log patterns
|
|
249
|
+
const commonLogPatterns = [
|
|
250
|
+
// Timestamp patterns
|
|
251
|
+
/^\[\d{4}-\d{2}-\d{2}/,
|
|
252
|
+
/^\[\d{2}:\d{2}:\d{2}/,
|
|
253
|
+
/^\d{4}\/\d{2}\/\d{2}/,
|
|
254
|
+
/^\d{2}:\d{2}:\d{2}/,
|
|
255
|
+
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/,
|
|
256
|
+
// Log level patterns
|
|
257
|
+
/^\[?(DEBUG|INFO|WARN|WARNING|ERROR|FATAL|TRACE)\]?/i,
|
|
258
|
+
/^(DEBUG|INFO|WARN|WARNING|ERROR|FATAL|TRACE):/i,
|
|
259
|
+
// Common server messages
|
|
260
|
+
/^Secure MCP/,
|
|
261
|
+
/^Server (running|started|listening)/i,
|
|
262
|
+
/^Listening on/,
|
|
263
|
+
/^Started/,
|
|
264
|
+
/^Allowed directories:/,
|
|
265
|
+
/^Connected to/,
|
|
266
|
+
/^Disconnected from/,
|
|
267
|
+
// Structured log formats
|
|
268
|
+
/^\[.*\]\s+\w+:/, // [context] level:
|
|
269
|
+
/^\w+\s+\d{1,2},\s+\d{4}/, // Month day, year
|
|
270
|
+
// Common prefixes
|
|
271
|
+
/^>>>/,
|
|
272
|
+
/^<<</,
|
|
273
|
+
/^---/,
|
|
274
|
+
/^===/,
|
|
275
|
+
// Error-like patterns (but not JSON errors)
|
|
276
|
+
/error/i,
|
|
277
|
+
/warning/i,
|
|
278
|
+
/failed/i,
|
|
279
|
+
/exception/i,
|
|
280
|
+
/stack trace/i,
|
|
281
|
+
];
|
|
282
|
+
// Check if it matches any common log pattern
|
|
283
|
+
const matchesCommonPattern = commonLogPatterns.some(pattern => pattern.test(trimmed));
|
|
284
|
+
// Strategy 5: Heuristic analysis
|
|
285
|
+
if (!matchesCommonPattern) {
|
|
286
|
+
// Check for other indicators
|
|
287
|
+
const hasLogIndicators = trimmed.includes(': ') || // Common log separator
|
|
288
|
+
(trimmed.split(' ').length <= 5 && trimmed.length < 100) || // Short messages
|
|
289
|
+
/^[A-Z][a-z]+:/.test(trimmed) || // Capitalized word followed by colon
|
|
290
|
+
trimmed.includes('...') || // Ellipsis
|
|
291
|
+
/^\d+\.\d+s$/.test(trimmed); // Time duration
|
|
292
|
+
return hasLogIndicators;
|
|
293
|
+
}
|
|
294
|
+
return matchesCommonPattern;
|
|
295
|
+
}
|
|
296
|
+
handleError(error) {
|
|
297
|
+
this.emit('error', error);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// ==================== Stdio Transport ====================
|
|
301
|
+
export class StdioTransport extends BaseTransport {
|
|
302
|
+
process;
|
|
303
|
+
reader;
|
|
304
|
+
writer;
|
|
305
|
+
constructor(config) {
|
|
306
|
+
super(config);
|
|
307
|
+
if (!config.command) {
|
|
308
|
+
throw new Error('Stdio transport requires a command');
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
async connect() {
|
|
312
|
+
if (this.connected) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
try {
|
|
316
|
+
// Dynamically import child_process to avoid errors in non-Node.js environments
|
|
317
|
+
const { spawn } = await import('child_process');
|
|
318
|
+
const spawnOptions = {
|
|
319
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
320
|
+
};
|
|
321
|
+
// Add optional env if provided
|
|
322
|
+
if (this.config.env) {
|
|
323
|
+
spawnOptions.env = { ...process.env, ...this.config.env };
|
|
324
|
+
}
|
|
325
|
+
// Add optional cwd if provided
|
|
326
|
+
if (this.config.cwd) {
|
|
327
|
+
spawnOptions.cwd = this.config.cwd;
|
|
328
|
+
}
|
|
329
|
+
this.process = spawn(this.config.command, this.config.args || [], spawnOptions);
|
|
330
|
+
// Set up stdout reader
|
|
331
|
+
this.process.stdout?.on('data', (data) => {
|
|
332
|
+
this.handleMessage(data.toString());
|
|
333
|
+
});
|
|
334
|
+
// Set up stderr reader
|
|
335
|
+
this.process.stderr?.on('data', (data) => {
|
|
336
|
+
const stderrOutput = data.toString().trim();
|
|
337
|
+
// Log stderr output for debugging
|
|
338
|
+
console.log(`[MCP Server stderr] ${stderrOutput}`);
|
|
339
|
+
// Only emit error for actual error messages, not normal server startup messages
|
|
340
|
+
// Check if this looks like a normal server startup message
|
|
341
|
+
const isNormalStartupMessage = stderrOutput.includes('Secure MCP') ||
|
|
342
|
+
stderrOutput.includes('Server running on') ||
|
|
343
|
+
stderrOutput.includes('Listening on') ||
|
|
344
|
+
stderrOutput.includes('Started') ||
|
|
345
|
+
stderrOutput.match(/^\[.*\]/); // Common log format
|
|
346
|
+
if (!isNormalStartupMessage &&
|
|
347
|
+
(stderrOutput.toLowerCase().includes('error') ||
|
|
348
|
+
stderrOutput.toLowerCase().includes('failed') ||
|
|
349
|
+
stderrOutput.toLowerCase().includes('fatal'))) {
|
|
350
|
+
this.emit('error', new Error(`Process stderr: ${stderrOutput}`));
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
// Handle process exit
|
|
354
|
+
this.process.on('close', (code) => {
|
|
355
|
+
this.connected = false;
|
|
356
|
+
this.emit('disconnected', { code });
|
|
357
|
+
});
|
|
358
|
+
this.process.on('error', (error) => {
|
|
359
|
+
this.handleError(error);
|
|
360
|
+
});
|
|
361
|
+
this.connected = true;
|
|
362
|
+
this.emit('connected');
|
|
363
|
+
}
|
|
364
|
+
catch (error) {
|
|
365
|
+
throw new Error(`Failed to start process: ${error}`, { cause: error });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async disconnect() {
|
|
369
|
+
if (!this.connected || !this.process) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
this.process.kill();
|
|
373
|
+
this.process = undefined;
|
|
374
|
+
this.connected = false;
|
|
375
|
+
this.emit('disconnected');
|
|
376
|
+
}
|
|
377
|
+
async send(request) {
|
|
378
|
+
if (!this.connected || !this.process) {
|
|
379
|
+
throw new Error('Not connected');
|
|
380
|
+
}
|
|
381
|
+
return new Promise((resolve, reject) => {
|
|
382
|
+
const data = JSON.stringify(request) + '\n';
|
|
383
|
+
this.process.stdin.write(data, (error) => {
|
|
384
|
+
if (error) {
|
|
385
|
+
reject(error);
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
resolve();
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// ==================== HTTP Transport ====================
|
|
395
|
+
export class HTTPTransport extends BaseTransport {
|
|
396
|
+
abortController;
|
|
397
|
+
constructor(config) {
|
|
398
|
+
super(config);
|
|
399
|
+
if (!config.url) {
|
|
400
|
+
throw new Error('HTTP transport requires a URL');
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
async connect() {
|
|
404
|
+
// HTTP transport establishes connection when sending requests, here we just mark as connected
|
|
405
|
+
this.connected = true;
|
|
406
|
+
this.emit('connected');
|
|
407
|
+
}
|
|
408
|
+
async disconnect() {
|
|
409
|
+
if (this.abortController) {
|
|
410
|
+
this.abortController.abort();
|
|
411
|
+
this.abortController = undefined;
|
|
412
|
+
}
|
|
413
|
+
this.connected = false;
|
|
414
|
+
this.emit('disconnected');
|
|
415
|
+
}
|
|
416
|
+
async send(request) {
|
|
417
|
+
if (!this.connected) {
|
|
418
|
+
throw new Error('Not connected');
|
|
419
|
+
}
|
|
420
|
+
this.abortController = new AbortController();
|
|
421
|
+
try {
|
|
422
|
+
const response = await fetch(this.config.url, {
|
|
423
|
+
method: 'POST',
|
|
424
|
+
headers: {
|
|
425
|
+
'Content-Type': 'application/json',
|
|
426
|
+
...this.config.headers,
|
|
427
|
+
},
|
|
428
|
+
body: JSON.stringify(request),
|
|
429
|
+
signal: this.abortController.signal,
|
|
430
|
+
});
|
|
431
|
+
if (!response.ok) {
|
|
432
|
+
throw new Error(`HTTP error: ${response.status} ${response.statusText}`);
|
|
433
|
+
}
|
|
434
|
+
const data = await response.text();
|
|
435
|
+
this.handleMessage(data);
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
this.handleError(error);
|
|
439
|
+
throw error;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
// ==================== SSE Transport ====================
|
|
444
|
+
export class SSETransport extends BaseTransport {
|
|
445
|
+
eventSource;
|
|
446
|
+
pendingRequests = new Map();
|
|
447
|
+
constructor(config) {
|
|
448
|
+
super(config);
|
|
449
|
+
if (!config.url) {
|
|
450
|
+
throw new Error('SSE transport requires a URL');
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
async connect() {
|
|
454
|
+
if (this.connected) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
try {
|
|
458
|
+
// Note: SSE is typically used for server-to-client push, client requests still need HTTP
|
|
459
|
+
// Here we only establish SSE connection for receiving server push
|
|
460
|
+
this.eventSource = new EventSource(this.config.url);
|
|
461
|
+
this.eventSource.onmessage = (event) => {
|
|
462
|
+
this.handleMessage(event.data);
|
|
463
|
+
};
|
|
464
|
+
this.eventSource.onerror = (error) => {
|
|
465
|
+
this.handleError(new Error(`SSE error: ${error}`));
|
|
466
|
+
};
|
|
467
|
+
this.eventSource.onopen = () => {
|
|
468
|
+
this.connected = true;
|
|
469
|
+
this.emit('connected');
|
|
470
|
+
};
|
|
471
|
+
// Also create an HTTP transport for sending requests
|
|
472
|
+
this.httpTransport = new HTTPTransport(this.config);
|
|
473
|
+
await this.httpTransport.connect();
|
|
474
|
+
}
|
|
475
|
+
catch (error) {
|
|
476
|
+
throw new Error(`Failed to connect SSE: ${error}`, { cause: error });
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
async disconnect() {
|
|
480
|
+
if (this.eventSource) {
|
|
481
|
+
this.eventSource.close();
|
|
482
|
+
this.eventSource = undefined;
|
|
483
|
+
}
|
|
484
|
+
if (this.httpTransport) {
|
|
485
|
+
await this.httpTransport.disconnect();
|
|
486
|
+
this.httpTransport = undefined;
|
|
487
|
+
}
|
|
488
|
+
this.connected = false;
|
|
489
|
+
this.emit('disconnected');
|
|
490
|
+
}
|
|
491
|
+
async send(request) {
|
|
492
|
+
if (!this.connected || !this.httpTransport) {
|
|
493
|
+
throw new Error('Not connected');
|
|
494
|
+
}
|
|
495
|
+
// Use HTTP transport to send request
|
|
496
|
+
await this.httpTransport.send(request);
|
|
497
|
+
}
|
|
498
|
+
httpTransport;
|
|
499
|
+
}
|
|
500
|
+
// ==================== Transport Factory ====================
|
|
501
|
+
export class TransportFactory {
|
|
502
|
+
static create(config) {
|
|
503
|
+
switch (config.type) {
|
|
504
|
+
case 'stdio':
|
|
505
|
+
return new StdioTransport(config);
|
|
506
|
+
case 'http':
|
|
507
|
+
return new HTTPTransport(config);
|
|
508
|
+
case 'sse':
|
|
509
|
+
return new SSETransport(config);
|
|
510
|
+
default:
|
|
511
|
+
throw new Error(`Unsupported transport type: ${config.type}`);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) Type Definitions
|
|
3
|
+
* Based on MCP protocol specification: https://spec.modelcontextprotocol.io/
|
|
4
|
+
*/
|
|
5
|
+
export interface MCPError {
|
|
6
|
+
code: number;
|
|
7
|
+
message: string;
|
|
8
|
+
data?: any;
|
|
9
|
+
}
|
|
10
|
+
export interface JSONRPCRequest {
|
|
11
|
+
jsonrpc: '2.0';
|
|
12
|
+
id: string | number | null;
|
|
13
|
+
method: string;
|
|
14
|
+
params?: any;
|
|
15
|
+
}
|
|
16
|
+
export interface JSONRPCResponse {
|
|
17
|
+
jsonrpc: '2.0';
|
|
18
|
+
id: string | number | null;
|
|
19
|
+
result?: any;
|
|
20
|
+
error?: MCPError;
|
|
21
|
+
}
|
|
22
|
+
export interface Tool {
|
|
23
|
+
name: string;
|
|
24
|
+
description: string;
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object';
|
|
27
|
+
properties: Record<string, any>;
|
|
28
|
+
required?: string[];
|
|
29
|
+
additionalProperties?: boolean;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface ToolList {
|
|
33
|
+
tools: Tool[];
|
|
34
|
+
}
|
|
35
|
+
export interface ToolCall {
|
|
36
|
+
name: string;
|
|
37
|
+
arguments: Record<string, any>;
|
|
38
|
+
}
|
|
39
|
+
export interface ToolResult {
|
|
40
|
+
content: Array<{
|
|
41
|
+
type: 'text' | 'image' | 'resource';
|
|
42
|
+
text?: string;
|
|
43
|
+
data?: any;
|
|
44
|
+
}>;
|
|
45
|
+
isError?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface Resource {
|
|
48
|
+
uri: string;
|
|
49
|
+
name: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
mimeType?: string;
|
|
52
|
+
}
|
|
53
|
+
export interface ResourceList {
|
|
54
|
+
resources: Resource[];
|
|
55
|
+
}
|
|
56
|
+
export interface ResourceContents {
|
|
57
|
+
contents: Array<{
|
|
58
|
+
uri: string;
|
|
59
|
+
mimeType: string;
|
|
60
|
+
text?: string;
|
|
61
|
+
blob?: string;
|
|
62
|
+
}>;
|
|
63
|
+
}
|
|
64
|
+
export interface Prompt {
|
|
65
|
+
name: string;
|
|
66
|
+
description?: string;
|
|
67
|
+
arguments?: Array<{
|
|
68
|
+
name: string;
|
|
69
|
+
description?: string;
|
|
70
|
+
required?: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
}
|
|
73
|
+
export interface PromptList {
|
|
74
|
+
prompts: Prompt[];
|
|
75
|
+
}
|
|
76
|
+
export type TransportType = 'stdio' | 'http' | 'sse';
|
|
77
|
+
export interface StdioLogFilterConfig {
|
|
78
|
+
ignorePatterns?: string[];
|
|
79
|
+
keepPatterns?: string[];
|
|
80
|
+
verbose?: boolean;
|
|
81
|
+
bufferSize?: number;
|
|
82
|
+
timeout?: number;
|
|
83
|
+
}
|
|
84
|
+
export interface TransportConfig {
|
|
85
|
+
type: TransportType;
|
|
86
|
+
command?: string;
|
|
87
|
+
args?: string[];
|
|
88
|
+
url?: string;
|
|
89
|
+
headers?: Record<string, string>;
|
|
90
|
+
logFilter?: StdioLogFilterConfig;
|
|
91
|
+
env?: Record<string, string>;
|
|
92
|
+
cwd?: string;
|
|
93
|
+
}
|
|
94
|
+
export interface MCPClientConfig {
|
|
95
|
+
transport: TransportConfig;
|
|
96
|
+
autoConnect?: boolean;
|
|
97
|
+
timeout?: number;
|
|
98
|
+
maxRetries?: number;
|
|
99
|
+
}
|
|
100
|
+
export type MCPEventType = 'connected' | 'disconnected' | 'error' | 'tools_updated' | 'resources_updated' | 'prompts_updated';
|
|
101
|
+
export interface MCPEvent {
|
|
102
|
+
type: MCPEventType;
|
|
103
|
+
data?: any;
|
|
104
|
+
timestamp: number;
|
|
105
|
+
}
|
|
106
|
+
export interface MCPSession {
|
|
107
|
+
id: string;
|
|
108
|
+
clientId: string;
|
|
109
|
+
serverId: string;
|
|
110
|
+
tools: Tool[];
|
|
111
|
+
resources: Resource[];
|
|
112
|
+
prompts: Prompt[];
|
|
113
|
+
createdAt: number;
|
|
114
|
+
lastActivity: number;
|
|
115
|
+
}
|
|
116
|
+
export declare const MCP_METHODS: {
|
|
117
|
+
readonly TOOLS_LIST: "tools/list";
|
|
118
|
+
readonly TOOLS_CALL: "tools/call";
|
|
119
|
+
readonly RESOURCES_LIST: "resources/list";
|
|
120
|
+
readonly RESOURCES_READ: "resources/read";
|
|
121
|
+
readonly RESOURCES_SUBSCRIBE: "resources/subscribe";
|
|
122
|
+
readonly RESOURCES_UNSUBSCRIBE: "resources/unsubscribe";
|
|
123
|
+
readonly PROMPTS_LIST: "prompts/list";
|
|
124
|
+
readonly PROMPTS_GET: "prompts/get";
|
|
125
|
+
readonly LOGGING_SET_LEVEL: "logging/setLevel";
|
|
126
|
+
readonly NOTIFICATIONS_LIST: "notifications/list";
|
|
127
|
+
};
|
|
128
|
+
export declare const MCP_ERROR_CODES: {
|
|
129
|
+
readonly PARSE_ERROR: -32700;
|
|
130
|
+
readonly INVALID_REQUEST: -32600;
|
|
131
|
+
readonly METHOD_NOT_FOUND: -32601;
|
|
132
|
+
readonly INVALID_PARAMS: -32602;
|
|
133
|
+
readonly INTERNAL_ERROR: -32603;
|
|
134
|
+
readonly SERVER_ERROR: -32000;
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) Type Definitions
|
|
3
|
+
* Based on MCP protocol specification: https://spec.modelcontextprotocol.io/
|
|
4
|
+
*/
|
|
5
|
+
// ==================== Constants ====================
|
|
6
|
+
export const MCP_METHODS = {
|
|
7
|
+
// Tool related
|
|
8
|
+
TOOLS_LIST: 'tools/list',
|
|
9
|
+
TOOLS_CALL: 'tools/call',
|
|
10
|
+
// Resource related
|
|
11
|
+
RESOURCES_LIST: 'resources/list',
|
|
12
|
+
RESOURCES_READ: 'resources/read',
|
|
13
|
+
RESOURCES_SUBSCRIBE: 'resources/subscribe',
|
|
14
|
+
RESOURCES_UNSUBSCRIBE: 'resources/unsubscribe',
|
|
15
|
+
// Prompt related
|
|
16
|
+
PROMPTS_LIST: 'prompts/list',
|
|
17
|
+
PROMPTS_GET: 'prompts/get',
|
|
18
|
+
// Logging related
|
|
19
|
+
LOGGING_SET_LEVEL: 'logging/setLevel',
|
|
20
|
+
// Notifications
|
|
21
|
+
NOTIFICATIONS_LIST: 'notifications/list',
|
|
22
|
+
};
|
|
23
|
+
export const MCP_ERROR_CODES = {
|
|
24
|
+
PARSE_ERROR: -32700,
|
|
25
|
+
INVALID_REQUEST: -32600,
|
|
26
|
+
METHOD_NOT_FOUND: -32601,
|
|
27
|
+
INVALID_PARAMS: -32602,
|
|
28
|
+
INTERNAL_ERROR: -32603,
|
|
29
|
+
SERVER_ERROR: -32000,
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=types.js.map
|