aiexecode 1.0.88 → 1.0.90

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.

Potentially problematic release.


This version of aiexecode might be problematic. Click here for more details.

Files changed (36) hide show
  1. package/index.js +128 -20
  2. package/mcp-agent-lib/.claude/settings.local.json +9 -0
  3. package/mcp-agent-lib/example/01-basic-usage.js +82 -0
  4. package/mcp-agent-lib/example/02-quick-start.js +52 -0
  5. package/mcp-agent-lib/example/03-http-server.js +76 -0
  6. package/mcp-agent-lib/example/04-multiple-servers.js +117 -0
  7. package/mcp-agent-lib/example/05-error-handling.js +116 -0
  8. package/mcp-agent-lib/example/06-resources-and-prompts.js +174 -0
  9. package/mcp-agent-lib/example/07-advanced-configuration.js +191 -0
  10. package/mcp-agent-lib/example/08-real-world-chatbot.js +331 -0
  11. package/mcp-agent-lib/example/README.md +346 -0
  12. package/mcp-agent-lib/sampleMCPHost/index.js +267 -0
  13. package/mcp-agent-lib/sampleMCPHost/mcp_config.json +18 -0
  14. package/mcp-agent-lib/src/mcp_client.js +302 -77
  15. package/package.json +1 -1
  16. package/payload_viewer/out/404/index.html +1 -1
  17. package/payload_viewer/out/404.html +1 -1
  18. package/payload_viewer/out/index.html +1 -1
  19. package/payload_viewer/out/index.txt +1 -1
  20. package/src/ai_based/orchestrator.js +4 -1
  21. package/src/cli/mcp_cli.js +14 -7
  22. package/src/cli/mcp_commands.js +31 -15
  23. package/src/commands/mcp.js +36 -18
  24. package/src/frontend/App.js +54 -4
  25. package/src/frontend/components/BlankLine.js +5 -3
  26. package/src/frontend/components/ConversationItem.js +43 -10
  27. package/src/system/code_executer.js +6 -0
  28. package/src/system/mcp_integration.js +94 -40
  29. package/src/tools/file_reader.js +6 -0
  30. package/src/tools/glob.js +3 -0
  31. package/src/tools/ripgrep.js +2 -0
  32. package/src/tools/web_downloader.js +3 -0
  33. package/src/util/mcp_config_manager.js +41 -20
  34. /package/payload_viewer/out/_next/static/{dp582oDmc4bDYYIktREJ4 → w4dMVYalgk7djrLxRxWiE}/_buildManifest.js +0 -0
  35. /package/payload_viewer/out/_next/static/{dp582oDmc4bDYYIktREJ4 → w4dMVYalgk7djrLxRxWiE}/_clientMiddlewareManifest.json +0 -0
  36. /package/payload_viewer/out/_next/static/{dp582oDmc4bDYYIktREJ4 → w4dMVYalgk7djrLxRxWiE}/_ssgManifest.js +0 -0
package/index.js CHANGED
@@ -164,7 +164,7 @@ if (viewerMode) {
164
164
  console.log(chalk.green(`✓ Payload viewer is running`));
165
165
  console.log(chalk.yellow(`Press Ctrl+C to stop the server`));
166
166
  // Keep process alive
167
- await new Promise(() => {});
167
+ await new Promise(() => { });
168
168
  }
169
169
 
170
170
  // 전역 설정
@@ -175,7 +175,7 @@ process.app_custom.__dirname = dirname(fileURLToPath(import.meta.url));
175
175
  // (글로벌 설치 후 aiexecode 명령으로 실행 시에는 다른 경로에서 실행됨)
176
176
  const packageJsonPath = join(process.app_custom.__dirname, 'package.json');
177
177
  const isDevelopment = existsSync(packageJsonPath) &&
178
- process.app_custom.__dirname === dirname(fileURLToPath(import.meta.url));
178
+ process.app_custom.__dirname === dirname(fileURLToPath(import.meta.url));
179
179
  process.env.IS_DEVELOPMENT = isDevelopment ? 'true' : 'false';
180
180
 
181
181
  // Session ID 생성 함수 (16자리 hex)
@@ -307,19 +307,100 @@ if (!process.env.OPENAI_API_KEY) {
307
307
  process.exit(1);
308
308
  }
309
309
 
310
- // MCP Integration 초기화 (백그라운드에서 실행)
311
- let mcpIntegration = null;
312
- let mcpToolFunctions = {};
313
- let mcpToolSchemas = [];
310
+ // ========================================
311
+ // MCP Integration 초기화
312
+ // ========================================
313
+ // MCP (Model Context Protocol) 서버들과의 연결을 설정하고 사용 가능한 도구 목록을 준비
314
+ // 프로그램 시작 시 백그라운드에서 비동기로 실행되어 UI 로딩을 블로킹하지 않음
314
315
 
315
- // MCP 초기화를 백그라운드에서 실행하되 Promise만 저장 (이벤트는 UI 시작 후에 발생)
316
- const mcpInitPromise = initializeMCPIntegration(process.cwd()).then(integration => {
316
+ let mcpIntegration = null; // MCP Integration 인스턴스 (서버 관리 도구 실행)
317
+ let mcpToolFunctions = {}; // MCP 도구 실행 함수들 (toolName -> async function)
318
+ let mcpToolSchemas = []; // MCP 도구 스키마들 (AI 모델에 전달할 도구 정의)
319
+
320
+ // MCP 초기화를 백그라운드에서 실행
321
+ // Promise만 저장하고 실제 UI 이벤트는 UI 시작 후에 발생시킨다
322
+ const mcpInitPromise = initializeMCPIntegration().then(async integration => {
323
+ // 초기화 성공 시 결과 저장
317
324
  mcpIntegration = integration;
325
+
326
+ // MCP 도구 실행 함수들을 가져옴 (session.js에서 도구 실행 시 사용)
318
327
  mcpToolFunctions = integration ? integration.getToolFunctions() : {};
328
+
329
+ // MCP 도구 스키마들을 가져옴 (orchestrator.js에서 AI에게 전달)
319
330
  mcpToolSchemas = integration ? integration.getToolSchemas() : [];
320
331
 
332
+ // 초기화 결과 로깅
321
333
  if (integration) {
322
334
  const servers = integration.getConnectedServers();
335
+ const logLines = [];
336
+
337
+ logLines.push('');
338
+ logLines.push(`MCP INTEGRATION COMPLETE`);
339
+ logLines.push(`Timestamp: ${new Date().toISOString()}`);
340
+ logLines.push(`Total Servers: ${servers.length}`);
341
+ logLines.push(`Total Tools: ${Object.keys(mcpToolFunctions).length}`);
342
+ logLines.push(`Total Schemas: ${mcpToolSchemas.length}`);
343
+ logLines.push('');
344
+
345
+ // MCP 서버별 상세 정보
346
+ if (servers.length > 0) {
347
+ logLines.push('Connected MCP Servers:');
348
+ servers.forEach((server, idx) => {
349
+ if (idx > 0) logLines.push('');
350
+ logLines.push(`[${idx + 1}] ${server.name}`);
351
+ logLines.push(` Status: ${server.status}`);
352
+ logLines.push(` Tool Count: ${server.toolCount}`);
353
+ if (server.transport) {
354
+ logLines.push(` Transport: ${JSON.stringify(server.transport, null, 2).split('\n').join('\n ')}`);
355
+ }
356
+ if (server.tools && server.tools.length > 0) {
357
+ logLines.push(` Available Tools:`);
358
+ server.tools.forEach(tool => {
359
+ logLines.push(` - ${tool.name}: ${tool.description || 'No description'}`);
360
+ });
361
+ }
362
+ });
363
+ logLines.push('');
364
+ }
365
+
366
+ // mcpToolFunctions 구조 로깅
367
+ if (Object.keys(mcpToolFunctions).length > 0) {
368
+ logLines.push('MCP Tool Functions:');
369
+ Object.keys(mcpToolFunctions).forEach((toolName, idx) => {
370
+ const func = mcpToolFunctions[toolName];
371
+ logLines.push(` [${idx + 1}] ${toolName}`);
372
+ logLines.push(` Type: ${typeof func}`);
373
+ logLines.push(` Function Name: ${func?.name || 'anonymous'}`);
374
+ });
375
+ logLines.push('');
376
+ }
377
+
378
+ // mcpToolSchemas 구조 로깅
379
+ if (mcpToolSchemas.length > 0) {
380
+ logLines.push('MCP Tool Schemas:');
381
+ mcpToolSchemas.forEach((schema, idx) => {
382
+ logLines.push(` [${idx + 1}] ${schema.name}`);
383
+ logLines.push(` Description: ${schema.description || 'No description'}`);
384
+ if (schema.inputSchema) {
385
+ const props = schema.inputSchema.properties || {};
386
+ const propCount = Object.keys(props).length;
387
+ logLines.push(` Input Properties: ${propCount}`);
388
+ if (propCount > 0) {
389
+ Object.entries(props).forEach(([key, value]) => {
390
+ const required = schema.inputSchema.required?.includes(key) ? ' (required)' : '';
391
+ logLines.push(` - ${key}: ${value.type || 'unknown'}${required}`);
392
+ });
393
+ }
394
+ }
395
+ });
396
+ logLines.push('');
397
+ }
398
+
399
+ // 별도 파일에 기록 (createDebugLogger 사용)
400
+ const mcpLogger = createDebugLogger('mcp_initialization.log', 'MCP');
401
+ logLines.forEach(line => mcpLogger(line));
402
+
403
+ // 기존 디버그 로그에도 간략하게 출력
323
404
  debugLog(`MCP integration complete: ${servers.length} server(s), ${Object.keys(mcpToolFunctions).length} tool(s)`);
324
405
  servers.forEach(server => {
325
406
  debugLog(` - ${server.name}: ${server.toolCount} tool(s) (${server.status})`);
@@ -327,16 +408,28 @@ const mcpInitPromise = initializeMCPIntegration(process.cwd()).then(integration
327
408
  }
328
409
  return integration;
329
410
  }).catch(err => {
411
+ // 초기화 실패 시에도 프로그램은 계속 실행 (MCP 없이도 동작)
330
412
  debugLog(`MCP initialization failed: ${err.message}`);
331
413
  return null;
332
414
  });
333
415
 
416
+ // ========================================
334
417
  // 커맨드 레지스트리 초기화
418
+ // ========================================
419
+ // 사용자가 입력하는 슬래시 커맨드들(/mcp, /exit 등)을 관리
335
420
  const commandRegistry = new CommandRegistry();
336
- await loadCommands(commandRegistry, {
421
+
422
+ // context 객체를 생성 - getter를 사용하여 mcpIntegration을 동적으로 참조
423
+ // 이렇게 하면 나중에 MCP가 초기화되어도 최신 값을 참조할 수 있음
424
+ const commandContext = {
337
425
  commandRegistry,
338
- mcpIntegration
339
- });
426
+ get mcpIntegration() {
427
+ return mcpIntegration; // 현재 mcpIntegration 값을 반환 (null이거나 초기화된 값)
428
+ }
429
+ };
430
+
431
+ // src/commands/ 디렉토리의 모든 커맨드 파일들을 자동으로 로드하고 등록
432
+ await loadCommands(commandRegistry, commandContext);
340
433
 
341
434
  // 커맨드 목록 준비
342
435
  const commandList = Array.from(commandRegistry.commands.entries()).map(([name, cmd]) => ({
@@ -364,13 +457,14 @@ async function handleSubmit(text) {
364
457
  return;
365
458
  }
366
459
 
367
- // 세션 실행 (시작/종료 알림 저장은 runSession 내부에서 처리)
460
+ // 세션 실행 (AI Agent의 미션 수행)
461
+ // 시작/종료 알림 및 저장은 runSession 내부에서 처리
368
462
  try {
369
463
  await runSession({
370
- mission: text,
371
- maxIterations: 50,
372
- mcpToolSchemas,
373
- mcpToolFunctions
464
+ mission: text, // 사용자가 입력한 미션
465
+ maxIterations: 50, // 최대 반복 횟수
466
+ mcpToolSchemas, // AI 모델에 전달할 MCP 도구 스키마들
467
+ mcpToolFunctions // 실제 MCP 도구 실행 함수들
374
468
  });
375
469
  } catch (err) {
376
470
  // API 인증 에러 등 세션 실행 중 발생한 에러를 history에 표시
@@ -483,23 +577,34 @@ uiInstance = startUI({
483
577
  updateInfo: null // 초기에는 null, 나중에 업데이트됨
484
578
  });
485
579
 
486
- // UI가 시작된 후 로딩 태스크 추가
580
+ // ========================================
581
+ // 백그라운드 초기화 태스크 UI 연동
582
+ // ========================================
583
+ // UI가 시작된 후 백그라운드에서 실행 중인 초기화 작업들을 사용자에게 표시
584
+
585
+ // 버전 체크 로딩 표시
487
586
  uiEvents.emit('loading:task_add', {
488
587
  id: 'version_check',
489
588
  text: 'Checking for updates...'
490
589
  });
491
590
 
591
+ // MCP 초기화 로딩 표시
492
592
  uiEvents.emit('loading:task_add', {
493
593
  id: 'mcp_init',
494
594
  text: 'Initializing MCP servers...'
495
595
  });
496
596
 
497
- // UI가 준비된 비동기 초기화 이벤트 발생 (Promise가 이미 완료된 경우에도 처리됨)
498
- // 번째 catch에서 null을 반환하므로 항상 resolved 상태로 then이 실행됨
597
+ // 백그라운드 초기화 완료 UI에 이벤트 발생
598
+ // Promise가 이미 완료된 경우에도 then이 실행되어 UI가 업데이트됨
599
+ // catch에서 null을 반환하므로 항상 resolved 상태로 then이 실행됨
600
+
601
+ // 버전 체크 완료 이벤트
499
602
  versionCheckPromise.then(info => {
500
603
  uiEvents.emit('version:update', { updateInfo: info });
501
604
  });
502
605
 
606
+ // MCP 초기화 완료 이벤트
607
+ // 이 시점에서 MCP 서버들과의 연결이 완료되고 도구 목록이 준비됨
503
608
  mcpInitPromise.then(integration => {
504
609
  uiEvents.emit('mcp:initialized', { integration });
505
610
  });
@@ -515,7 +620,10 @@ process.on('SIGINT', handleExit);
515
620
  // UI가 종료될 때까지 대기
516
621
  await uiInstance.waitUntilExit();
517
622
 
518
- // MCP Integration 정리
623
+ // ========================================
624
+ // 프로그램 종료 시 MCP 정리
625
+ // ========================================
626
+ // 모든 MCP 서버와의 연결을 정상적으로 종료하고 리소스 정리
519
627
  if (mcpIntegration) {
520
628
  await mcpIntegration.cleanup();
521
629
  }
@@ -0,0 +1,9 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(mkdir:*)"
5
+ ],
6
+ "deny": [],
7
+ "ask": []
8
+ }
9
+ }
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 기본 사용 예제 - MCP Agent Client 시작하기
5
+ *
6
+ * 이 예제는 MCP Agent Client의 가장 기본적인 사용 방법을 보여줍니다.
7
+ * - 클라이언트 생성
8
+ * - 서버 연결
9
+ * - 도구 목록 조회
10
+ * - 도구 실행
11
+ */
12
+
13
+ import { MCPAgentClient } from '../index.js';
14
+
15
+ async function main() {
16
+ // 1. 클라이언트 인스턴스 생성
17
+ // logLevel을 'info'로 설정하여 진행 상황을 확인할 수 있습니다
18
+ const client = new MCPAgentClient({
19
+ logLevel: 'info',
20
+ enableConsoleDebug: true
21
+ });
22
+
23
+ try {
24
+ // 2. 서버 설정으로 초기화
25
+ // mcpServers 객체에 연결할 서버들을 정의합니다
26
+ await client.initialize({
27
+ mcpServers: {
28
+ // stdio 방식 서버 예시
29
+ 'example-server': {
30
+ type: 'stdio',
31
+ command: 'node',
32
+ args: ['path/to/your/server.js'],
33
+ // 선택사항: 환경변수 설정
34
+ env: {
35
+ NODE_ENV: 'development'
36
+ }
37
+ }
38
+ }
39
+ });
40
+
41
+ console.log('✅ 클라이언트가 성공적으로 초기화되었습니다!');
42
+
43
+ // 3. 사용 가능한 도구 목록 조회
44
+ const tools = client.getAvailableTools();
45
+ console.log('\n📋 사용 가능한 도구 목록:');
46
+ tools.forEach(tool => {
47
+ console.log(` - ${tool.name}: ${tool.description}`);
48
+ console.log(` 서버: ${tool.server}`);
49
+ });
50
+
51
+ // 4. 특정 도구 실행하기
52
+ if (tools.length > 0) {
53
+ const firstTool = tools[0];
54
+ console.log(`\n🔧 도구 실행 예시: ${firstTool.name}`);
55
+
56
+ // executeTool()은 도구 이름만으로 자동으로 서버를 찾아 실행합니다
57
+ const result = await client.executeTool(firstTool.name, {
58
+ // 여기에 도구에 필요한 인자를 전달합니다
59
+ // 예: { query: 'test', limit: 10 }
60
+ });
61
+
62
+ console.log('✅ 실행 결과:', result);
63
+ }
64
+
65
+ // 5. 클라이언트 상태 확인
66
+ const status = client.getStatus();
67
+ console.log('\n📊 클라이언트 상태:');
68
+ console.log(` - 초기화 완료: ${status.initialized}`);
69
+ console.log(` - 연결된 서버 수: ${status.connectedServers}/${status.totalServers}`);
70
+ console.log(` - 사용 가능한 도구 수: ${status.totalTools}`);
71
+
72
+ } catch (error) {
73
+ console.error('❌ 오류 발생:', error.message);
74
+ } finally {
75
+ // 6. 리소스 정리 및 연결 해제
76
+ await client.disconnect();
77
+ console.log('\n👋 클라이언트 연결이 해제되었습니다.');
78
+ }
79
+ }
80
+
81
+ // 실행
82
+ main().catch(console.error);
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 빠른 시작 예제 - quickStart() 함수 사용
5
+ *
6
+ * quickStart() 함수를 사용하면 클라이언트 생성과 초기화를
7
+ * 한 번에 수행할 수 있어 가장 간단하게 시작할 수 있습니다.
8
+ */
9
+
10
+ import { quickStart } from '../index.js';
11
+
12
+ async function main() {
13
+ // quickStart()는 클라이언트 생성 + 초기화를 한 번에 수행합니다
14
+ const client = await quickStart(
15
+ // 첫 번째 인자: 서버 설정
16
+ {
17
+ mcpServers: {
18
+ 'my-server': {
19
+ type: 'stdio',
20
+ command: 'node',
21
+ args: ['server.js']
22
+ }
23
+ }
24
+ },
25
+ // 두 번째 인자: 클라이언트 옵션 (선택사항)
26
+ {
27
+ logLevel: 'info',
28
+ enableConsoleDebug: true,
29
+ timeout: 30000, // 30초 타임아웃
30
+ retries: 3 // 실패 시 3회 재시도
31
+ }
32
+ );
33
+
34
+ try {
35
+ console.log('✅ 클라이언트 준비 완료!');
36
+
37
+ // 바로 도구를 사용할 수 있습니다
38
+ const tools = client.getAvailableTools();
39
+ console.log(`📋 ${tools.length}개의 도구를 사용할 수 있습니다.`);
40
+
41
+ // 도구 실행
42
+ if (tools.length > 0) {
43
+ const result = await client.executeTool(tools[0].name);
44
+ console.log('결과:', result);
45
+ }
46
+
47
+ } finally {
48
+ await client.disconnect();
49
+ }
50
+ }
51
+
52
+ main().catch(console.error);
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * HTTP 서버 연결 예제
5
+ *
6
+ * stdio 방식 대신 HTTP/HTTPS를 통해 원격 MCP 서버에 연결하는 방법입니다.
7
+ * 인증이 필요한 경우 Bearer 토큰을 헤더에 포함시킬 수 있습니다.
8
+ */
9
+
10
+ import { MCPAgentClient } from '../index.js';
11
+
12
+ async function main() {
13
+ const client = new MCPAgentClient({
14
+ logLevel: 'info',
15
+ enableConsoleDebug: true
16
+ });
17
+
18
+ try {
19
+ await client.initialize({
20
+ mcpServers: {
21
+ // HTTP 방식 서버 (인증 없음)
22
+ 'public-api': {
23
+ type: 'http',
24
+ url: 'https://api.example.com/mcp'
25
+ },
26
+
27
+ // HTTP 방식 서버 (Bearer 토큰 인증)
28
+ 'secured-api': {
29
+ type: 'http',
30
+ url: 'https://secure-api.example.com/mcp',
31
+ headers: {
32
+ 'Authorization': 'Bearer YOUR_TOKEN_HERE',
33
+ 'X-API-Key': 'your-api-key'
34
+ }
35
+ },
36
+
37
+ // 로컬 HTTP 서버
38
+ 'local-http': {
39
+ type: 'http',
40
+ url: 'http://localhost:3000/mcp'
41
+ }
42
+ }
43
+ });
44
+
45
+ console.log('✅ HTTP 서버들에 연결되었습니다.');
46
+
47
+ // 연결된 서버별 상태 확인
48
+ const status = client.getStatus();
49
+ console.log('\n📊 서버별 상태:');
50
+ for (const [serverName, serverStatus] of Object.entries(status.servers)) {
51
+ console.log(`\n${serverName}:`);
52
+ console.log(` - 상태: ${serverStatus.status}`);
53
+ console.log(` - 타입: ${serverStatus.type}`);
54
+ console.log(` - 도구 수: ${serverStatus.toolCount}`);
55
+ }
56
+
57
+ // 특정 서버의 도구만 조회
58
+ const publicTools = client.getServerTools('public-api');
59
+ console.log('\n🔧 public-api의 도구:');
60
+ publicTools.forEach(tool => {
61
+ console.log(` - ${tool.name}: ${tool.description}`);
62
+ });
63
+
64
+ } catch (error) {
65
+ console.error('❌ 오류:', error.message);
66
+
67
+ // HTTP 인증 실패 시 자세한 정보가 로그에 출력됩니다
68
+ if (error.message.includes('401')) {
69
+ console.error('💡 인증 토큰을 확인해주세요.');
70
+ }
71
+ } finally {
72
+ await client.disconnect();
73
+ }
74
+ }
75
+
76
+ main().catch(console.error);
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 다중 서버 연결 예제
5
+ *
6
+ * 여러 MCP 서버에 동시에 연결하여 사용하는 방법입니다.
7
+ * 각 서버는 서로 다른 전송 방식(stdio, HTTP, SSE)을 사용할 수 있습니다.
8
+ */
9
+
10
+ import { MCPAgentClient } from '../index.js';
11
+
12
+ async function main() {
13
+ const client = new MCPAgentClient({
14
+ logLevel: 'info',
15
+ enableConsoleDebug: true
16
+ });
17
+
18
+ try {
19
+ // 여러 서버에 동시 연결
20
+ await client.initialize({
21
+ mcpServers: {
22
+ // 파일 시스템 도구를 제공하는 서버
23
+ 'filesystem': {
24
+ type: 'stdio',
25
+ command: 'node',
26
+ args: ['servers/filesystem-server.js']
27
+ },
28
+
29
+ // 데이터베이스 도구를 제공하는 서버
30
+ 'database': {
31
+ type: 'stdio',
32
+ command: 'python',
33
+ args: ['-m', 'mcp_server_db']
34
+ },
35
+
36
+ // 원격 API 서버
37
+ 'remote-api': {
38
+ type: 'http',
39
+ url: 'https://api.example.com/mcp',
40
+ headers: {
41
+ 'Authorization': 'Bearer TOKEN'
42
+ }
43
+ },
44
+
45
+ // 실시간 이벤트 서버
46
+ 'event-stream': {
47
+ type: 'sse',
48
+ url: 'https://events.example.com/mcp'
49
+ }
50
+ }
51
+ });
52
+
53
+ console.log('✅ 모든 서버에 연결되었습니다.');
54
+
55
+ // 1. 전체 도구 목록 조회 (모든 서버의 도구)
56
+ const allTools = client.getAvailableTools();
57
+ console.log(`\n📋 총 ${allTools.length}개의 도구 사용 가능:`);
58
+
59
+ // 서버별로 그룹화하여 출력
60
+ const toolsByServer = {};
61
+ allTools.forEach(tool => {
62
+ if (!toolsByServer[tool.server]) {
63
+ toolsByServer[tool.server] = [];
64
+ }
65
+ toolsByServer[tool.server].push(tool);
66
+ });
67
+
68
+ for (const [serverName, tools] of Object.entries(toolsByServer)) {
69
+ console.log(`\n${serverName} (${tools.length}개):`);
70
+ tools.forEach(tool => {
71
+ console.log(` - ${tool.name}: ${tool.description}`);
72
+ });
73
+ }
74
+
75
+ // 2. 특정 서버의 도구만 사용
76
+ console.log('\n🔧 filesystem 서버의 도구 실행:');
77
+ const fsTools = client.getServerTools('filesystem');
78
+ if (fsTools.length > 0) {
79
+ // callTool()을 사용하여 특정 서버의 도구를 직접 호출
80
+ const result = await client.callTool('filesystem', fsTools[0].name, {
81
+ path: '/tmp'
82
+ });
83
+ console.log('결과:', result);
84
+ }
85
+
86
+ // 3. 도구 이름만으로 자동 실행 (어느 서버의 도구인지 자동 검색)
87
+ console.log('\n🔍 자동 서버 검색으로 도구 실행:');
88
+ if (allTools.length > 0) {
89
+ // executeTool()은 도구 이름만으로 자동으로 서버를 찾습니다
90
+ const result = await client.executeTool(allTools[0].name);
91
+ console.log(`${allTools[0].name} (서버: ${result.server}):`, result.data);
92
+ }
93
+
94
+ // 4. 리소스 목록 조회 (모든 서버)
95
+ const resources = await client.listAllResources();
96
+ console.log(`\n📄 사용 가능한 리소스: ${resources.length}개`);
97
+ resources.forEach(resource => {
98
+ console.log(` - ${resource.name} (${resource.serverName})`);
99
+ console.log(` URI: ${resource.uri}`);
100
+ });
101
+
102
+ // 5. 프롬프트 목록 조회 (모든 서버)
103
+ const prompts = await client.listAllPrompts();
104
+ console.log(`\n💬 사용 가능한 프롬프트: ${prompts.length}개`);
105
+ prompts.forEach(prompt => {
106
+ console.log(` - ${prompt.name} (${prompt.serverName})`);
107
+ console.log(` ${prompt.description}`);
108
+ });
109
+
110
+ } catch (error) {
111
+ console.error('❌ 오류:', error.message);
112
+ } finally {
113
+ await client.disconnect();
114
+ }
115
+ }
116
+
117
+ main().catch(console.error);
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 에러 처리 및 재시도 예제
5
+ *
6
+ * MCP 클라이언트의 강력한 에러 처리와 자동 재시도 기능을 보여줍니다.
7
+ * - 자동 재시도 설정
8
+ * - 타임아웃 처리
9
+ * - 서버 연결 끊김 감지
10
+ * - 이벤트 기반 에러 모니터링
11
+ */
12
+
13
+ import { MCPAgentClient } from '../index.js';
14
+
15
+ async function main() {
16
+ const client = new MCPAgentClient({
17
+ logLevel: 'info',
18
+ enableConsoleDebug: true,
19
+
20
+ // 재시도 설정
21
+ timeout: 10000, // 10초 타임아웃
22
+ retries: 5, // 최대 5회 재시도
23
+ retryDelay: 1000, // 첫 재시도는 1초 후
24
+ maxRetryDelay: 30000 // 최대 30초까지 지연
25
+ });
26
+
27
+ // 1. 서버 에러 이벤트 리스너
28
+ client.on('serverError', (serverName, error) => {
29
+ console.error(`⚠️ 서버 에러 [${serverName}]:`, error.message);
30
+ });
31
+
32
+ // 2. 서버 연결 해제 이벤트 리스너
33
+ client.on('serverDisconnected', (serverName) => {
34
+ console.warn(`🔌 서버 연결 끊김: ${serverName}`);
35
+ });
36
+
37
+ // 3. 서버 상태 변경 이벤트 리스너
38
+ client.on('serverStatusChange', ({ serverName, status, previousStatus }) => {
39
+ console.log(`📡 ${serverName}: ${previousStatus} → ${status}`);
40
+ });
41
+
42
+ try {
43
+ await client.initialize({
44
+ mcpServers: {
45
+ 'test-server': {
46
+ type: 'stdio',
47
+ command: 'node',
48
+ args: ['server.js']
49
+ }
50
+ }
51
+ });
52
+
53
+ // 예제 1: 기본 재시도 (클라이언트 설정 사용)
54
+ try {
55
+ console.log('\n🔧 도구 실행 (자동 재시도 활성화)...');
56
+ const result = await client.executeTool('some-tool', {
57
+ param: 'value'
58
+ });
59
+ console.log('✅ 성공:', result);
60
+ } catch (error) {
61
+ console.error('❌ 모든 재시도 실패:', error.message);
62
+ }
63
+
64
+ // 예제 2: 커스텀 재시도 설정
65
+ try {
66
+ console.log('\n🔧 도구 실행 (커스텀 타임아웃/재시도)...');
67
+ const result = await client.executeTool(
68
+ 'slow-tool',
69
+ { query: 'test' },
70
+ {
71
+ timeout: 5000, // 이 호출만 5초 타임아웃
72
+ retries: 2 // 이 호출만 2회 재시도
73
+ }
74
+ );
75
+ console.log('✅ 성공:', result);
76
+ } catch (error) {
77
+ console.error('❌ 실패:', error.message);
78
+ }
79
+
80
+ // 예제 3: 서버 상태 확인 후 실행
81
+ const status = client.getStatus();
82
+ console.log('\n📊 현재 서버 상태:');
83
+ for (const [serverName, serverStatus] of Object.entries(status.servers)) {
84
+ console.log(`${serverName}: ${serverStatus.status}`);
85
+
86
+ if (serverStatus.status === 'connected') {
87
+ console.log(` ✅ 연결됨 - ${serverStatus.toolCount}개 도구 사용 가능`);
88
+ } else if (serverStatus.status === 'partially_connected') {
89
+ console.log(` ⚠️ 부분 연결 - 일부 기능만 사용 가능`);
90
+ } else {
91
+ console.log(` ❌ 연결 안됨 - 사용 불가`);
92
+ }
93
+ }
94
+
95
+ // 예제 4: 특정 서버 연결 해제 및 재연결 처리
96
+ console.log('\n🔌 test-server 연결 해제...');
97
+ await client.disconnectServer('test-server');
98
+
99
+ const updatedStatus = client.getStatus();
100
+ console.log(`연결된 서버: ${updatedStatus.connectedServers}/${updatedStatus.totalServers}`);
101
+
102
+ } catch (error) {
103
+ // 초기화 실패 처리
104
+ if (error.message.includes('not allowed')) {
105
+ console.error('❌ 보안 에러: 허용되지 않은 명령어 또는 인자');
106
+ } else if (error.message.includes('timeout')) {
107
+ console.error('❌ 타임아웃: 서버 응답 없음');
108
+ } else {
109
+ console.error('❌ 예상치 못한 에러:', error.message);
110
+ }
111
+ } finally {
112
+ await client.disconnect();
113
+ }
114
+ }
115
+
116
+ main().catch(console.error);