@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,278 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { spawn } from 'child_process';
|
|
4
|
+
import { CONFIG_PATH, LOGS_DIR } from '../core/constants.js';
|
|
5
|
+
import { logger } from '../core/logger.js';
|
|
6
|
+
export class ServiceManager {
|
|
7
|
+
services = new Map();
|
|
8
|
+
processes = new Map();
|
|
9
|
+
constructor() {
|
|
10
|
+
this.loadServices();
|
|
11
|
+
}
|
|
12
|
+
loadServices() {
|
|
13
|
+
if (!fs.existsSync(CONFIG_PATH)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
|
|
17
|
+
const serviceInstances = config.services?.instances || [];
|
|
18
|
+
for (const service of serviceInstances) {
|
|
19
|
+
this.services.set(service.name, {
|
|
20
|
+
...service,
|
|
21
|
+
status: service.status || 'installed',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
saveServices() {
|
|
26
|
+
const config = fs.existsSync(CONFIG_PATH)
|
|
27
|
+
? JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'))
|
|
28
|
+
: { services: {} };
|
|
29
|
+
config.services.instances = Array.from(this.services.values());
|
|
30
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
31
|
+
}
|
|
32
|
+
async installService(servicePath, name) {
|
|
33
|
+
const resolvedPath = path.resolve(servicePath);
|
|
34
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
35
|
+
throw new Error(`Service path not found: ${resolvedPath}`);
|
|
36
|
+
}
|
|
37
|
+
const serviceName = name || path.basename(resolvedPath);
|
|
38
|
+
// Check if service is already installed
|
|
39
|
+
if (this.services.has(serviceName)) {
|
|
40
|
+
throw new Error(`Service ${serviceName} is already installed`);
|
|
41
|
+
}
|
|
42
|
+
// Create service configuration
|
|
43
|
+
const serviceConfig = {
|
|
44
|
+
name: serviceName,
|
|
45
|
+
path: resolvedPath,
|
|
46
|
+
runtime: 'node', // Default, should actually be obtained from detector
|
|
47
|
+
entry: this.detectEntryPoint(resolvedPath),
|
|
48
|
+
};
|
|
49
|
+
const serviceInfo = {
|
|
50
|
+
name: serviceName,
|
|
51
|
+
path: resolvedPath,
|
|
52
|
+
runtime: serviceConfig.runtime,
|
|
53
|
+
status: 'installed',
|
|
54
|
+
installedAt: new Date().toISOString(),
|
|
55
|
+
config: serviceConfig,
|
|
56
|
+
};
|
|
57
|
+
this.services.set(serviceName, serviceInfo);
|
|
58
|
+
this.saveServices();
|
|
59
|
+
logger.info(`Service installed: ${serviceName} at ${resolvedPath}`);
|
|
60
|
+
return serviceInfo;
|
|
61
|
+
}
|
|
62
|
+
async startService(name) {
|
|
63
|
+
const service = this.services.get(name);
|
|
64
|
+
if (!service) {
|
|
65
|
+
throw new Error(`Service ${name} is not installed`);
|
|
66
|
+
}
|
|
67
|
+
if (service.status === 'running') {
|
|
68
|
+
logger.warn(`Service ${name} is already running`);
|
|
69
|
+
return service;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
// Create log directory
|
|
73
|
+
const logDir = path.join(LOGS_DIR, name);
|
|
74
|
+
if (!fs.existsSync(logDir)) {
|
|
75
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
76
|
+
}
|
|
77
|
+
const stdoutLog = path.join(logDir, 'stdout.log');
|
|
78
|
+
const stderrLog = path.join(logDir, 'stderr.log');
|
|
79
|
+
const stdout = fs.openSync(stdoutLog, 'a');
|
|
80
|
+
const stderr = fs.openSync(stderrLog, 'a');
|
|
81
|
+
// Start service based on runtime
|
|
82
|
+
const process = this.spawnService(service);
|
|
83
|
+
process.stdout?.pipe(fs.createWriteStream(stdoutLog, { flags: 'a' }));
|
|
84
|
+
process.stderr?.pipe(fs.createWriteStream(stderrLog, { flags: 'a' }));
|
|
85
|
+
this.processes.set(name, process);
|
|
86
|
+
// Update service status
|
|
87
|
+
service.status = 'running';
|
|
88
|
+
service.startedAt = new Date().toISOString();
|
|
89
|
+
service.stoppedAt = undefined;
|
|
90
|
+
service.pid = process.pid;
|
|
91
|
+
this.saveServices();
|
|
92
|
+
logger.info(`Service started: ${name} (PID: ${process.pid})`);
|
|
93
|
+
return service;
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
service.status = 'error';
|
|
97
|
+
this.saveServices();
|
|
98
|
+
throw new Error(`Failed to start service ${name}: ${error.message}`, { cause: error });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async stopService(name) {
|
|
102
|
+
const service = this.services.get(name);
|
|
103
|
+
if (!service) {
|
|
104
|
+
throw new Error(`Service ${name} is not installed`);
|
|
105
|
+
}
|
|
106
|
+
if (service.status !== 'running') {
|
|
107
|
+
logger.warn(`Service ${name} is not running`);
|
|
108
|
+
return service;
|
|
109
|
+
}
|
|
110
|
+
const process = this.processes.get(name);
|
|
111
|
+
if (process) {
|
|
112
|
+
process.kill();
|
|
113
|
+
this.processes.delete(name);
|
|
114
|
+
}
|
|
115
|
+
service.status = 'stopped';
|
|
116
|
+
service.stoppedAt = new Date().toISOString();
|
|
117
|
+
service.pid = undefined;
|
|
118
|
+
this.saveServices();
|
|
119
|
+
logger.info(`Service stopped: ${name}`);
|
|
120
|
+
return service;
|
|
121
|
+
}
|
|
122
|
+
async restartService(name) {
|
|
123
|
+
await this.stopService(name);
|
|
124
|
+
// Wait for a while to ensure process is completely stopped
|
|
125
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
126
|
+
return await this.startService(name);
|
|
127
|
+
}
|
|
128
|
+
async uninstallService(name) {
|
|
129
|
+
const service = this.services.get(name);
|
|
130
|
+
if (!service) {
|
|
131
|
+
throw new Error(`Service ${name} is not installed`);
|
|
132
|
+
}
|
|
133
|
+
// If service is running, stop it first
|
|
134
|
+
if (service.status === 'running') {
|
|
135
|
+
await this.stopService(name);
|
|
136
|
+
}
|
|
137
|
+
// Remove from configuration
|
|
138
|
+
this.services.delete(name);
|
|
139
|
+
this.saveServices();
|
|
140
|
+
logger.info(`Service uninstalled: ${name}`);
|
|
141
|
+
}
|
|
142
|
+
getService(name) {
|
|
143
|
+
return this.services.get(name);
|
|
144
|
+
}
|
|
145
|
+
getAllServices() {
|
|
146
|
+
return Array.from(this.services.values());
|
|
147
|
+
}
|
|
148
|
+
getRunningServices() {
|
|
149
|
+
return Array.from(this.services.values()).filter(s => s.status === 'running');
|
|
150
|
+
}
|
|
151
|
+
async getServiceLogs(name, lines = 50) {
|
|
152
|
+
const logDir = path.join(LOGS_DIR, name);
|
|
153
|
+
const logFile = path.join(logDir, 'stdout.log');
|
|
154
|
+
if (!fs.existsSync(logFile)) {
|
|
155
|
+
return `No logs found for service ${name}`;
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const content = fs.readFileSync(logFile, 'utf-8');
|
|
159
|
+
const linesArray = content.split('\n');
|
|
160
|
+
return linesArray.slice(-lines).join('\n');
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
return `Failed to read logs: ${error.message}`;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async getServiceStats(name) {
|
|
167
|
+
const service = this.services.get(name);
|
|
168
|
+
if (!service) {
|
|
169
|
+
throw new Error(`Service ${name} not found`);
|
|
170
|
+
}
|
|
171
|
+
const process = this.processes.get(name);
|
|
172
|
+
return {
|
|
173
|
+
name: service.name,
|
|
174
|
+
status: service.status,
|
|
175
|
+
pid: service.pid,
|
|
176
|
+
runtime: service.runtime,
|
|
177
|
+
installedAt: service.installedAt,
|
|
178
|
+
startedAt: service.startedAt,
|
|
179
|
+
stoppedAt: service.stoppedAt,
|
|
180
|
+
isProcessAlive: process ? !process.exitCode : false,
|
|
181
|
+
memoryUsage: this.getProcessMemoryUsage(process),
|
|
182
|
+
uptime: service.startedAt
|
|
183
|
+
? Date.now() - new Date(service.startedAt).getTime()
|
|
184
|
+
: 0,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
spawnService(service) {
|
|
188
|
+
const { config } = service;
|
|
189
|
+
const cwd = config.path || '.';
|
|
190
|
+
let command;
|
|
191
|
+
let args = [];
|
|
192
|
+
switch (service.runtime) {
|
|
193
|
+
case 'node':
|
|
194
|
+
command = 'node';
|
|
195
|
+
args = [config.entry, ...(config.args || [])];
|
|
196
|
+
break;
|
|
197
|
+
case 'python':
|
|
198
|
+
command = 'python3';
|
|
199
|
+
args = [config.entry, ...(config.args || [])];
|
|
200
|
+
break;
|
|
201
|
+
case 'docker':
|
|
202
|
+
command = 'docker';
|
|
203
|
+
args = ['run', '-d', '--rm', '--name', `mcp-${service.name}`, config.image || service.name];
|
|
204
|
+
if (config.args) {
|
|
205
|
+
args.push(...config.args);
|
|
206
|
+
}
|
|
207
|
+
break;
|
|
208
|
+
default:
|
|
209
|
+
command = config.entry;
|
|
210
|
+
args = config.args || [];
|
|
211
|
+
}
|
|
212
|
+
logger.debug(`Spawning service: ${command} ${args.join(' ')}`);
|
|
213
|
+
return spawn(command, args, {
|
|
214
|
+
cwd,
|
|
215
|
+
env: {
|
|
216
|
+
...process.env,
|
|
217
|
+
...config.env,
|
|
218
|
+
},
|
|
219
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
220
|
+
detached: false,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
detectEntryPoint(servicePath) {
|
|
224
|
+
const possibleEntries = [
|
|
225
|
+
'index.js', 'main.js', 'app.js', 'server.js',
|
|
226
|
+
'index.ts', 'main.ts', 'app.ts', 'server.ts',
|
|
227
|
+
'main.py', 'app.py', 'server.py',
|
|
228
|
+
'main.go', 'server.go',
|
|
229
|
+
'main.rs', 'lib.rs',
|
|
230
|
+
];
|
|
231
|
+
for (const entry of possibleEntries) {
|
|
232
|
+
const entryPath = path.join(servicePath, entry);
|
|
233
|
+
if (fs.existsSync(entryPath)) {
|
|
234
|
+
return entry;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// If no standard entry point found, return the first file
|
|
238
|
+
const files = fs.readdirSync(servicePath);
|
|
239
|
+
const firstFile = files.find(f => f.endsWith('.js') || f.endsWith('.ts') || f.endsWith('.py') ||
|
|
240
|
+
f.endsWith('.go') || f.endsWith('.rs'));
|
|
241
|
+
return firstFile || 'index.js';
|
|
242
|
+
}
|
|
243
|
+
getProcessMemoryUsage(process) {
|
|
244
|
+
if (!process || !process.pid) {
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
// This is a simplified implementation, should actually use system-specific methods
|
|
249
|
+
// For example, reading /proc/[pid]/status on Linux
|
|
250
|
+
return 0;
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async healthCheck(name) {
|
|
257
|
+
const service = this.services.get(name);
|
|
258
|
+
if (!service || service.status !== 'running') {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
const process = this.processes.get(name);
|
|
262
|
+
if (!process || process.exitCode !== null) {
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
// More complex health check logic can be added here
|
|
266
|
+
// For example, checking HTTP endpoints, TCP ports, etc.
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
async cleanup() {
|
|
270
|
+
// Stop all running services
|
|
271
|
+
for (const [name, service] of this.services) {
|
|
272
|
+
if (service.status === 'running') {
|
|
273
|
+
await this.stopService(name);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=service.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SDKOptions, MCPilotSDK, mcpilot } from './sdk';
|
|
2
|
+
/**
|
|
3
|
+
* IntentOrch SDK Core - Main Entry File
|
|
4
|
+
* Exports all public APIs, designed for developers
|
|
5
|
+
* Formerly known as MCPilot SDK
|
|
6
|
+
*/
|
|
7
|
+
export { MCPilotSDK, IntentOrchSDK, mcpilot, intentorch } from './sdk';
|
|
8
|
+
export type { SDKOptions, ServiceStatus, AskOptions, AskResult, } from './sdk';
|
|
9
|
+
export type { RuntimeType, ServiceConfig, Config, AIConfig, DetectionResult, } from './core/types';
|
|
10
|
+
export type { RuntimeAdapter } from './runtime/adapter';
|
|
11
|
+
export { EnhancedRuntimeDetector } from './runtime/detector-advanced';
|
|
12
|
+
export { ConfigManager } from './core/config-manager';
|
|
13
|
+
export { SimpleAI } from './ai/ai';
|
|
14
|
+
export { CloudIntentEngine, type CloudIntentEngineConfig, type AtomicIntent, type DependencyEdge, type IntentParseResult, type ToolSelectionResult, type ExecutionContext, type ExecutionResult, type EnhancedExecutionStep, type WorkflowPlan, type EnhancedExecutionResult, } from './ai';
|
|
15
|
+
export { MCPClient, ToolRegistry, createMCPConfig, TOOL_CATEGORIES, TOOL_PATTERNS, discoverLocalMCPServers, loadMCPServersFromEnv, } from './mcp';
|
|
16
|
+
export { BaseTransport, StdioTransport, HTTPTransport, SSETransport, TransportFactory } from './mcp/transport';
|
|
17
|
+
export { MCP_METHODS, MCP_ERROR_CODES } from './mcp/types';
|
|
18
|
+
export type { Tool, ToolCall, ToolResult, MCPClientConfig, TransportConfig, StdioLogFilterConfig, TransportType, MCPError, JSONRPCRequest, JSONRPCResponse, Resource, ResourceList, ResourceContents, Prompt, PromptList, MCPSession, MCPEvent, MCPEventType, } from './mcp/types';
|
|
19
|
+
export { logger } from './core/logger';
|
|
20
|
+
export { MCPilotError, IntentOrchError, ErrorCode, ErrorSeverity, ErrorFactory, ErrorHandler, ConsoleErrorHandler, RetryErrorHandler, createError, wrapError, isMCPilotError, shouldRetry, } from './core/error-handler';
|
|
21
|
+
export { PerformanceMonitor, getPerformanceMonitor } from './core/performance-monitor';
|
|
22
|
+
/**
|
|
23
|
+
* Quick start function - Create and return SDK instance
|
|
24
|
+
*/
|
|
25
|
+
export declare function createSDK(options?: SDKOptions): MCPilotSDK;
|
|
26
|
+
/**
|
|
27
|
+
* Default export - Singleton instance
|
|
28
|
+
*/
|
|
29
|
+
export default mcpilot;
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { MCPilotSDK, mcpilot } from './sdk.js';
|
|
2
|
+
/**
|
|
3
|
+
* IntentOrch SDK Core - Main Entry File
|
|
4
|
+
* Exports all public APIs, designed for developers
|
|
5
|
+
* Formerly known as MCPilot SDK
|
|
6
|
+
*/
|
|
7
|
+
// Export core SDK class and types (with backward compatibility)
|
|
8
|
+
export { MCPilotSDK, IntentOrchSDK, mcpilot, intentorch } from './sdk.js';
|
|
9
|
+
export { EnhancedRuntimeDetector } from './runtime/detector-advanced.js';
|
|
10
|
+
// Export configuration manager
|
|
11
|
+
export { ConfigManager } from './core/config-manager.js';
|
|
12
|
+
// Export AI functionality (optional)
|
|
13
|
+
export { SimpleAI } from './ai/ai.js';
|
|
14
|
+
// Export Cloud Intent Engine functionality
|
|
15
|
+
export { CloudIntentEngine, } from './ai/index.js';
|
|
16
|
+
// Export MCP functionality
|
|
17
|
+
export { MCPClient, ToolRegistry, createMCPConfig, TOOL_CATEGORIES, TOOL_PATTERNS, discoverLocalMCPServers, loadMCPServersFromEnv, } from './mcp/index.js';
|
|
18
|
+
export { BaseTransport, StdioTransport, HTTPTransport, SSETransport, TransportFactory } from './mcp/transport.js';
|
|
19
|
+
export { MCP_METHODS, MCP_ERROR_CODES } from './mcp/types.js';
|
|
20
|
+
// Export utility functions
|
|
21
|
+
export { logger } from './core/logger.js';
|
|
22
|
+
// Export error handling
|
|
23
|
+
export { MCPilotError, IntentOrchError, ErrorCode, ErrorSeverity, ErrorFactory, ErrorHandler, ConsoleErrorHandler, RetryErrorHandler, createError, wrapError, isMCPilotError, shouldRetry, } from './core/error-handler.js';
|
|
24
|
+
// Export performance monitoring
|
|
25
|
+
export { PerformanceMonitor, getPerformanceMonitor } from './core/performance-monitor.js';
|
|
26
|
+
/**
|
|
27
|
+
* Quick start function - Create and return SDK instance
|
|
28
|
+
*/
|
|
29
|
+
export function createSDK(options) {
|
|
30
|
+
return new MCPilotSDK(options);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Default export - Singleton instance
|
|
34
|
+
*/
|
|
35
|
+
export default mcpilot;
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Client Core Class
|
|
3
|
+
* Provides complete MCP protocol client functionality
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { MCPClientConfig, Tool, ToolResult, Resource, Prompt } from './types';
|
|
7
|
+
export declare class MCPClient extends EventEmitter {
|
|
8
|
+
private config;
|
|
9
|
+
private transport;
|
|
10
|
+
private connected;
|
|
11
|
+
private requestId;
|
|
12
|
+
private pendingRequests;
|
|
13
|
+
private tools;
|
|
14
|
+
private resources;
|
|
15
|
+
private prompts;
|
|
16
|
+
private sessionId?;
|
|
17
|
+
constructor(config: MCPClientConfig);
|
|
18
|
+
connect(): Promise<void>;
|
|
19
|
+
disconnect(): Promise<void>;
|
|
20
|
+
isConnected(): boolean;
|
|
21
|
+
listTools(): Promise<Tool[]>;
|
|
22
|
+
callTool(toolName: string, arguments_: Record<string, any>): Promise<ToolResult>;
|
|
23
|
+
refreshTools(): Promise<void>;
|
|
24
|
+
getTools(): Tool[];
|
|
25
|
+
findTool(name: string): Tool | undefined;
|
|
26
|
+
listResources(): Promise<Resource[]>;
|
|
27
|
+
readResource(uri: string): Promise<any>;
|
|
28
|
+
refreshResources(): Promise<void>;
|
|
29
|
+
getResources(): Resource[];
|
|
30
|
+
listPrompts(): Promise<Prompt[]>;
|
|
31
|
+
getPrompt(name: string, arguments_?: Record<string, any>): Promise<any>;
|
|
32
|
+
refreshPrompts(): Promise<void>;
|
|
33
|
+
getPrompts(): Prompt[];
|
|
34
|
+
private sendRequest;
|
|
35
|
+
private generateRequestId;
|
|
36
|
+
private setupTransportListeners;
|
|
37
|
+
private handleTransportMessage;
|
|
38
|
+
private handleTransportError;
|
|
39
|
+
private handleNotification;
|
|
40
|
+
private emitEvent;
|
|
41
|
+
withRetry<T>(operation: () => Promise<T>): Promise<T>;
|
|
42
|
+
getStatus(): {
|
|
43
|
+
connected: boolean;
|
|
44
|
+
toolsCount: number;
|
|
45
|
+
resourcesCount: number;
|
|
46
|
+
promptsCount: number;
|
|
47
|
+
sessionId: string;
|
|
48
|
+
};
|
|
49
|
+
destroy(): void;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Client Core Class
|
|
3
|
+
* Provides complete MCP protocol client functionality
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import { MCP_METHODS, } from './types.js';
|
|
7
|
+
import { TransportFactory } from './transport.js';
|
|
8
|
+
export class MCPClient extends EventEmitter {
|
|
9
|
+
config;
|
|
10
|
+
transport;
|
|
11
|
+
connected = false;
|
|
12
|
+
requestId = 0;
|
|
13
|
+
pendingRequests = new Map();
|
|
14
|
+
// State
|
|
15
|
+
tools = [];
|
|
16
|
+
resources = [];
|
|
17
|
+
prompts = [];
|
|
18
|
+
sessionId;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
super();
|
|
21
|
+
this.config = {
|
|
22
|
+
autoConnect: false, // Default disable auto-connect requests to avoid server not being ready
|
|
23
|
+
timeout: 30000,
|
|
24
|
+
maxRetries: 3,
|
|
25
|
+
...config,
|
|
26
|
+
};
|
|
27
|
+
this.transport = TransportFactory.create(config.transport);
|
|
28
|
+
this.setupTransportListeners();
|
|
29
|
+
}
|
|
30
|
+
// ==================== Connection Management ====================
|
|
31
|
+
async connect() {
|
|
32
|
+
if (this.connected) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
await this.transport.connect();
|
|
37
|
+
this.connected = true;
|
|
38
|
+
this.emitEvent('connected');
|
|
39
|
+
// Automatically fetch tool list after connection
|
|
40
|
+
if (this.config.autoConnect) {
|
|
41
|
+
await this.refreshTools();
|
|
42
|
+
await this.refreshResources();
|
|
43
|
+
await this.refreshPrompts();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
this.emitEvent('error', error);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async disconnect() {
|
|
52
|
+
if (!this.connected) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
await this.transport.disconnect();
|
|
57
|
+
this.connected = false;
|
|
58
|
+
// Clean up all pending requests
|
|
59
|
+
this.pendingRequests.forEach(({ reject, timeout }) => {
|
|
60
|
+
clearTimeout(timeout);
|
|
61
|
+
reject(new Error('Disconnected'));
|
|
62
|
+
});
|
|
63
|
+
this.pendingRequests.clear();
|
|
64
|
+
this.emitEvent('disconnected');
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
this.emitEvent('error', error);
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
isConnected() {
|
|
72
|
+
return this.connected && this.transport.isConnected();
|
|
73
|
+
}
|
|
74
|
+
// ==================== Tool Related Methods ====================
|
|
75
|
+
async listTools() {
|
|
76
|
+
const response = await this.sendRequest(MCP_METHODS.TOOLS_LIST);
|
|
77
|
+
const toolList = response;
|
|
78
|
+
this.tools = toolList.tools;
|
|
79
|
+
this.emitEvent('tools_updated', this.tools);
|
|
80
|
+
return this.tools;
|
|
81
|
+
}
|
|
82
|
+
async callTool(toolName, arguments_) {
|
|
83
|
+
const toolCall = {
|
|
84
|
+
name: toolName,
|
|
85
|
+
arguments: arguments_,
|
|
86
|
+
};
|
|
87
|
+
const response = await this.sendRequest(MCP_METHODS.TOOLS_CALL, { call: toolCall });
|
|
88
|
+
// Ensure response is a valid ToolResult
|
|
89
|
+
const toolResult = response;
|
|
90
|
+
// Check if the tool execution failed (isError flag)
|
|
91
|
+
if (toolResult.isError) {
|
|
92
|
+
// Create a proper error from the tool result content
|
|
93
|
+
const errorMessage = toolResult.content?.[0]?.text || 'Tool execution failed';
|
|
94
|
+
throw new Error(`Tool "${toolName}" execution failed: ${errorMessage}`);
|
|
95
|
+
}
|
|
96
|
+
return toolResult;
|
|
97
|
+
}
|
|
98
|
+
async refreshTools() {
|
|
99
|
+
await this.listTools();
|
|
100
|
+
}
|
|
101
|
+
getTools() {
|
|
102
|
+
return [...this.tools];
|
|
103
|
+
}
|
|
104
|
+
findTool(name) {
|
|
105
|
+
return this.tools.find(tool => tool.name === name);
|
|
106
|
+
}
|
|
107
|
+
// ==================== Resource Related Methods ====================
|
|
108
|
+
async listResources() {
|
|
109
|
+
const response = await this.sendRequest(MCP_METHODS.RESOURCES_LIST);
|
|
110
|
+
const resourceList = response;
|
|
111
|
+
this.resources = resourceList.resources;
|
|
112
|
+
this.emitEvent('resources_updated', this.resources);
|
|
113
|
+
return this.resources;
|
|
114
|
+
}
|
|
115
|
+
async readResource(uri) {
|
|
116
|
+
const response = await this.sendRequest(MCP_METHODS.RESOURCES_READ, { uri });
|
|
117
|
+
return response;
|
|
118
|
+
}
|
|
119
|
+
async refreshResources() {
|
|
120
|
+
await this.listResources();
|
|
121
|
+
}
|
|
122
|
+
getResources() {
|
|
123
|
+
return [...this.resources];
|
|
124
|
+
}
|
|
125
|
+
// ==================== Prompt Related Methods ====================
|
|
126
|
+
async listPrompts() {
|
|
127
|
+
const response = await this.sendRequest(MCP_METHODS.PROMPTS_LIST);
|
|
128
|
+
const promptList = response;
|
|
129
|
+
this.prompts = promptList.prompts;
|
|
130
|
+
this.emitEvent('prompts_updated', this.prompts);
|
|
131
|
+
return this.prompts;
|
|
132
|
+
}
|
|
133
|
+
async getPrompt(name, arguments_) {
|
|
134
|
+
const response = await this.sendRequest(MCP_METHODS.PROMPTS_GET, {
|
|
135
|
+
name,
|
|
136
|
+
arguments: arguments_,
|
|
137
|
+
});
|
|
138
|
+
return response;
|
|
139
|
+
}
|
|
140
|
+
async refreshPrompts() {
|
|
141
|
+
await this.listPrompts();
|
|
142
|
+
}
|
|
143
|
+
getPrompts() {
|
|
144
|
+
return [...this.prompts];
|
|
145
|
+
}
|
|
146
|
+
// ==================== Core Request Methods ====================
|
|
147
|
+
async sendRequest(method, params) {
|
|
148
|
+
if (!this.isConnected()) {
|
|
149
|
+
throw new Error('Not connected to MCP server');
|
|
150
|
+
}
|
|
151
|
+
const requestId = this.generateRequestId();
|
|
152
|
+
const request = {
|
|
153
|
+
jsonrpc: '2.0',
|
|
154
|
+
id: requestId,
|
|
155
|
+
method,
|
|
156
|
+
params,
|
|
157
|
+
};
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
159
|
+
const timeout = setTimeout(() => {
|
|
160
|
+
this.pendingRequests.delete(requestId);
|
|
161
|
+
reject(new Error(`Request timeout after ${this.config.timeout}ms`));
|
|
162
|
+
}, this.config.timeout);
|
|
163
|
+
this.pendingRequests.set(requestId, { resolve, reject, timeout });
|
|
164
|
+
this.transport.send(request).catch(error => {
|
|
165
|
+
this.pendingRequests.delete(requestId);
|
|
166
|
+
clearTimeout(timeout);
|
|
167
|
+
reject(error);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
generateRequestId() {
|
|
172
|
+
return `req_${++this.requestId}_${Date.now()}`;
|
|
173
|
+
}
|
|
174
|
+
// ==================== Transport Layer Event Handling ====================
|
|
175
|
+
setupTransportListeners() {
|
|
176
|
+
this.transport.on('message', this.handleTransportMessage.bind(this));
|
|
177
|
+
this.transport.on('error', this.handleTransportError.bind(this));
|
|
178
|
+
this.transport.on('connected', () => {
|
|
179
|
+
this.connected = true;
|
|
180
|
+
this.emitEvent('connected');
|
|
181
|
+
});
|
|
182
|
+
this.transport.on('disconnected', () => {
|
|
183
|
+
this.connected = false;
|
|
184
|
+
this.emitEvent('disconnected');
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
handleTransportMessage(message) {
|
|
188
|
+
try {
|
|
189
|
+
const response = message;
|
|
190
|
+
// Handle request response
|
|
191
|
+
if (response.id && this.pendingRequests.has(response.id)) {
|
|
192
|
+
const { resolve, reject, timeout } = this.pendingRequests.get(response.id);
|
|
193
|
+
clearTimeout(timeout);
|
|
194
|
+
this.pendingRequests.delete(response.id);
|
|
195
|
+
if (response.error) {
|
|
196
|
+
const errorMessage = response.error.message || 'Unknown error';
|
|
197
|
+
const error = new Error(errorMessage);
|
|
198
|
+
error.code = response.error.code;
|
|
199
|
+
error.data = response.error.data;
|
|
200
|
+
reject(error);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
resolve(response.result);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Handle server-pushed notifications (messages without id)
|
|
207
|
+
else if (!response.id) {
|
|
208
|
+
this.handleNotification(response);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
this.emitEvent('error', error);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
handleTransportError(error) {
|
|
216
|
+
this.emitEvent('error', error);
|
|
217
|
+
}
|
|
218
|
+
handleNotification(response) {
|
|
219
|
+
// Handle server-pushed notifications
|
|
220
|
+
// For example: tools/changed, resources/changed, etc.
|
|
221
|
+
if (response.result) {
|
|
222
|
+
// Can handle different types of notifications based on method field
|
|
223
|
+
console.log('Received notification:', response);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// ==================== Event Emission ====================
|
|
227
|
+
emitEvent(type, data) {
|
|
228
|
+
const event = {
|
|
229
|
+
type,
|
|
230
|
+
data,
|
|
231
|
+
timestamp: Date.now(),
|
|
232
|
+
};
|
|
233
|
+
this.emit(type, event);
|
|
234
|
+
this.emit('event', event);
|
|
235
|
+
}
|
|
236
|
+
// ==================== Utility Methods ====================
|
|
237
|
+
async withRetry(operation) {
|
|
238
|
+
let lastError;
|
|
239
|
+
for (let attempt = 1; attempt <= this.config.maxRetries; attempt++) {
|
|
240
|
+
try {
|
|
241
|
+
return await operation();
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
lastError = error;
|
|
245
|
+
if (attempt < this.config.maxRetries) {
|
|
246
|
+
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
|
|
247
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
throw lastError;
|
|
253
|
+
}
|
|
254
|
+
// ==================== Status Query ====================
|
|
255
|
+
getStatus() {
|
|
256
|
+
return {
|
|
257
|
+
connected: this.connected,
|
|
258
|
+
toolsCount: this.tools.length,
|
|
259
|
+
resourcesCount: this.resources.length,
|
|
260
|
+
promptsCount: this.prompts.length,
|
|
261
|
+
sessionId: this.sessionId,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
// ==================== Cleanup ====================
|
|
265
|
+
destroy() {
|
|
266
|
+
this.disconnect().catch(() => {
|
|
267
|
+
// Ignore errors when disconnecting
|
|
268
|
+
});
|
|
269
|
+
this.removeAllListeners();
|
|
270
|
+
this.pendingRequests.clear();
|
|
271
|
+
this.tools = [];
|
|
272
|
+
this.resources = [];
|
|
273
|
+
this.prompts = [];
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=client.js.map
|