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
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 리소스와 프롬프트 사용 예제
5
+ *
6
+ * MCP 서버의 도구(Tools) 외에도 리소스(Resources)와 프롬프트(Prompts)를
7
+ * 사용하는 방법을 보여줍니다.
8
+ *
9
+ * - Resources: 파일, 데이터, 문서 등을 읽을 수 있는 URI 기반 리소스
10
+ * - Prompts: 미리 정의된 프롬프트 템플릿
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
+ try {
22
+ await client.initialize({
23
+ mcpServers: {
24
+ 'content-server': {
25
+ type: 'stdio',
26
+ command: 'node',
27
+ args: ['content-server.js']
28
+ }
29
+ }
30
+ });
31
+
32
+ // ========================================
33
+ // 1. 리소스(Resources) 사용하기
34
+ // ========================================
35
+
36
+ console.log('📄 리소스 목록 조회...\n');
37
+
38
+ // 모든 서버의 리소스 목록
39
+ const allResources = client.getAvailableResources();
40
+ console.log(`총 ${allResources.length}개의 리소스 발견:`);
41
+ allResources.forEach(resource => {
42
+ console.log(`\n- ${resource.name}`);
43
+ console.log(` 서버: ${resource.serverName}`);
44
+ console.log(` URI: ${resource.uri}`);
45
+ if (resource.description) {
46
+ console.log(` 설명: ${resource.description}`);
47
+ }
48
+ if (resource.mimeType) {
49
+ console.log(` 타입: ${resource.mimeType}`);
50
+ }
51
+ });
52
+
53
+ // 리소스 읽기 - 방법 1: URI로 자동 검색
54
+ if (allResources.length > 0) {
55
+ console.log('\n📖 리소스 읽기 (자동 서버 검색)...');
56
+ const resourceUri = allResources[0].uri;
57
+
58
+ try {
59
+ const content = await client.readResource(resourceUri);
60
+ console.log(`\n✅ ${resourceUri} 내용:`);
61
+ console.log(`타입: ${content.mimeType}`);
62
+ console.log(`데이터: ${content.data?.substring(0, 200)}...`);
63
+ } catch (error) {
64
+ console.error(`❌ 리소스 읽기 실패: ${error.message}`);
65
+ }
66
+ }
67
+
68
+ // 리소스 읽기 - 방법 2: 특정 서버에서 읽기
69
+ if (allResources.length > 0) {
70
+ console.log('\n📖 리소스 읽기 (특정 서버 지정)...');
71
+ const resource = allResources[0];
72
+
73
+ try {
74
+ const content = await client.readResourceFromServer(
75
+ resource.serverName,
76
+ resource.uri
77
+ );
78
+ console.log(`✅ 읽기 성공: ${content.uri}`);
79
+ } catch (error) {
80
+ console.error(`❌ 실패: ${error.message}`);
81
+ }
82
+ }
83
+
84
+ // ========================================
85
+ // 2. 프롬프트(Prompts) 사용하기
86
+ // ========================================
87
+
88
+ console.log('\n\n💬 프롬프트 목록 조회...\n');
89
+
90
+ // 모든 서버의 프롬프트 목록
91
+ const allPrompts = client.getAvailablePrompts();
92
+ console.log(`총 ${allPrompts.length}개의 프롬프트 발견:`);
93
+ allPrompts.forEach(prompt => {
94
+ console.log(`\n- ${prompt.name}`);
95
+ console.log(` 서버: ${prompt.serverName}`);
96
+ if (prompt.description) {
97
+ console.log(` 설명: ${prompt.description}`);
98
+ }
99
+ if (prompt.arguments && prompt.arguments.length > 0) {
100
+ console.log(` 인자:`);
101
+ prompt.arguments.forEach(arg => {
102
+ console.log(` - ${arg.name}: ${arg.description || '(설명 없음)'}`);
103
+ console.log(` 필수: ${arg.required ? '예' : '아니오'}`);
104
+ });
105
+ }
106
+ });
107
+
108
+ // 프롬프트 실행 - 방법 1: 이름으로 자동 검색
109
+ if (allPrompts.length > 0) {
110
+ console.log('\n🎯 프롬프트 실행 (자동 서버 검색)...');
111
+ const promptName = allPrompts[0].name;
112
+
113
+ try {
114
+ const result = await client.executePrompt(promptName, {
115
+ // 프롬프트에 필요한 인자 전달
116
+ // 예: { topic: 'AI', style: 'formal' }
117
+ });
118
+ console.log(`\n✅ ${promptName} 실행 결과:`);
119
+ console.log(result);
120
+ } catch (error) {
121
+ console.error(`❌ 프롬프트 실행 실패: ${error.message}`);
122
+ }
123
+ }
124
+
125
+ // 프롬프트 실행 - 방법 2: 특정 서버에서 실행
126
+ if (allPrompts.length > 0) {
127
+ console.log('\n🎯 프롬프트 실행 (특정 서버 지정)...');
128
+ const prompt = allPrompts[0];
129
+
130
+ try {
131
+ const result = await client.getPrompt(
132
+ prompt.serverName,
133
+ prompt.name,
134
+ {
135
+ // 프롬프트 인자
136
+ customParam: 'value'
137
+ }
138
+ );
139
+ console.log(`✅ 실행 성공`);
140
+ console.log(result);
141
+ } catch (error) {
142
+ console.error(`❌ 실패: ${error.message}`);
143
+ }
144
+ }
145
+
146
+ // ========================================
147
+ // 3. 통합 정보 조회
148
+ // ========================================
149
+
150
+ console.log('\n\n📊 서버별 기능 요약:\n');
151
+ const status = client.getStatus();
152
+
153
+ for (const [serverName, serverStatus] of Object.entries(status.servers)) {
154
+ console.log(`${serverName}:`);
155
+ console.log(` 상태: ${serverStatus.status}`);
156
+ console.log(` 도구: ${serverStatus.toolCount}개`);
157
+
158
+ // 해당 서버의 리소스 수
159
+ const serverResources = allResources.filter(r => r.serverName === serverName);
160
+ console.log(` 리소스: ${serverResources.length}개`);
161
+
162
+ // 해당 서버의 프롬프트 수
163
+ const serverPrompts = allPrompts.filter(p => p.serverName === serverName);
164
+ console.log(` 프롬프트: ${serverPrompts.length}개`);
165
+ }
166
+
167
+ } catch (error) {
168
+ console.error('❌ 오류:', error.message);
169
+ } finally {
170
+ await client.disconnect();
171
+ }
172
+ }
173
+
174
+ main().catch(console.error);
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 고급 설정 예제
5
+ *
6
+ * MCP Agent Client의 다양한 설정 옵션을 활용하는 방법입니다.
7
+ * - 환경변수를 통한 설정
8
+ * - 보안 설정
9
+ * - 성능 튜닝
10
+ * - 로깅 설정
11
+ */
12
+
13
+ import { MCPAgentClient } from '../index.js';
14
+
15
+ async function main() {
16
+ // ========================================
17
+ // 1. 전체 설정 옵션 예시
18
+ // ========================================
19
+
20
+ const client = new MCPAgentClient({
21
+ // === 기본 설정 ===
22
+ autoConnect: true, // 초기화 시 자동 연결 (기본값: true)
23
+ logLevel: 'debug', // 로그 레벨: debug, info, warn, error, silent
24
+ enableConsoleDebug: true, // 콘솔 출력 활성화
25
+ enableLogging: true, // 로깅 활성화
26
+
27
+ // === 타임아웃 설정 ===
28
+ timeout: 30000, // 기본 타임아웃 (30초)
29
+ serverReadyTimeout: 10000, // 서버 준비 대기 타임아웃 (10초)
30
+ processKillTimeout: 5000, // 프로세스 종료 대기 시간 (5초)
31
+
32
+ // === 재시도 설정 ===
33
+ retries: 3, // 도구 실행 실패 시 재시도 횟수
34
+ retryDelay: 1000, // 첫 재시도 지연 (1초)
35
+ maxRetryDelay: 30000, // 최대 재시도 지연 (30초)
36
+ serverReadyRetries: 5, // 서버 준비 확인 재시도 횟수
37
+
38
+ // === 보안 설정 ===
39
+ allowedCommands: ['node', 'python', 'python3', 'npx', 'deno'],
40
+ dangerousChars: ['&', ';', '|', '`', '$', '>', '<', '*', '?'],
41
+
42
+ // === 메모리 및 크기 제한 ===
43
+ maxResponseSize: 1024 * 1024, // 최대 응답 크기 (1MB)
44
+ maxJsonSize: 10 * 1024 * 1024, // 최대 JSON 크기 (10MB)
45
+ maxLogLength: 100, // 로그 문자열 최대 길이
46
+ maxRequestIds: 10000, // 최대 요청 ID 수
47
+
48
+ // === HTTP 전송 설정 ===
49
+ httpMaxRetries: 3, // HTTP 연결 최대 재시도
50
+ httpInitialDelay: 1000, // HTTP 첫 재시도 지연
51
+ httpMaxDelay: 10000, // HTTP 최대 재시도 지연
52
+ httpGrowthFactor: 1.5, // HTTP 재시도 지연 증가율
53
+
54
+ // === 메모리 관리 ===
55
+ memoryCleanupEnabled: true, // 메모리 자동 정리 활성화
56
+
57
+ // === MCP 프로토콜 설정 ===
58
+ clientInfo: {
59
+ name: 'my-custom-client',
60
+ version: '1.0.0'
61
+ },
62
+ clientCapabilities: {
63
+ roots: { listChanged: true },
64
+ sampling: {},
65
+ experimental: {}
66
+ }
67
+ });
68
+
69
+ try {
70
+ // ========================================
71
+ // 2. 환경변수를 통한 설정
72
+ // ========================================
73
+
74
+ // 환경변수 설정 예시 (실제로는 shell에서 설정)
75
+ // export MCP_LOG_LEVEL=debug
76
+ // export MCP_TIMEOUT=60000
77
+ // export MCP_RETRIES=5
78
+ // export MCP_MAX_RESPONSE_SIZE=2097152
79
+
80
+ console.log('📋 현재 설정:');
81
+ console.log(` 로그 레벨: ${client.options.logLevel}`);
82
+ console.log(` 타임아웃: ${client.options.timeout}ms`);
83
+ console.log(` 재시도: ${client.options.retries}회`);
84
+ console.log(` 최대 응답 크기: ${client.options.maxResponseSize} bytes`);
85
+
86
+ // ========================================
87
+ // 3. 보안 강화 설정
88
+ // ========================================
89
+
90
+ await client.initialize({
91
+ mcpServers: {
92
+ 'secure-server': {
93
+ type: 'stdio',
94
+ command: 'node', // allowedCommands에 있는 명령어만 허용
95
+ args: ['server.js'], // dangerousChars가 없는 안전한 인자
96
+ env: {
97
+ // 환경변수는 문자열 key-value만 허용
98
+ NODE_ENV: 'production',
99
+ SAFE_MODE: 'true'
100
+ }
101
+ }
102
+ }
103
+ });
104
+
105
+ // ========================================
106
+ // 4. 커스텀 로깅
107
+ // ========================================
108
+
109
+ // 클라이언트의 보안 로그 시스템 사용
110
+ client.secureLog('info', '커스텀 정보 로그', {
111
+ customData: 'value',
112
+ sensitiveToken: 'will-be-redacted' // 자동으로 [REDACTED] 처리됨
113
+ });
114
+
115
+ client.secureLog('warn', '경고 메시지', {
116
+ issue: 'something to check'
117
+ });
118
+
119
+ client.secureLog('error', '에러 발생', {
120
+ errorCode: 500,
121
+ errorMessage: 'Something went wrong'
122
+ });
123
+
124
+ // ========================================
125
+ // 5. 메모리 관리
126
+ // ========================================
127
+
128
+ console.log('\n🧹 메모리 정리 실행...');
129
+ client.performMemoryCleanup();
130
+ console.log('✅ 정리 완료');
131
+
132
+ // ========================================
133
+ // 6. 서버 기능(Capabilities) 조회
134
+ // ========================================
135
+
136
+ console.log('\n📋 서버 기능 조회...');
137
+
138
+ // 모든 서버의 기능
139
+ const allCapabilities = client.getServerCapabilities();
140
+ console.log('모든 서버의 기능:', allCapabilities);
141
+
142
+ // 특정 서버의 기능
143
+ const serverCaps = client.getServerCapabilities('secure-server');
144
+ console.log('secure-server의 기능:', serverCaps);
145
+
146
+ // ========================================
147
+ // 7. 이벤트 모니터링
148
+ // ========================================
149
+
150
+ // 서버 상태 변경 모니터링
151
+ client.on('serverStatusChange', ({ serverName, status, previousStatus }) => {
152
+ console.log(`\n📡 [이벤트] ${serverName}:`);
153
+ console.log(` ${previousStatus} → ${status}`);
154
+ });
155
+
156
+ // 서버 에러 모니터링
157
+ client.on('serverError', (serverName, error) => {
158
+ console.error(`\n⚠️ [이벤트] 서버 에러 [${serverName}]:`, error);
159
+ });
160
+
161
+ // 서버 연결 해제 모니터링
162
+ client.on('serverDisconnected', (serverName) => {
163
+ console.warn(`\n🔌 [이벤트] 서버 연결 해제: ${serverName}`);
164
+ });
165
+
166
+ // ========================================
167
+ // 8. 안전한 JSON 처리
168
+ // ========================================
169
+
170
+ // 순환 참조가 있는 객체도 안전하게 직렬화
171
+ const circularObj = { name: 'test' };
172
+ circularObj.self = circularObj;
173
+
174
+ const safeJson = client.safeJsonStringify(circularObj);
175
+ console.log('\n🔒 안전한 JSON 직렬화:', safeJson);
176
+
177
+ // 보안 위협이 있는 JSON도 안전하게 파싱
178
+ const dangerousJson = '{"__proto__": {"polluted": true}}';
179
+ const safeParsed = client.safeJsonParse(dangerousJson);
180
+ console.log('🔒 안전한 JSON 파싱:', safeParsed);
181
+
182
+ } catch (error) {
183
+ console.error('❌ 오류:', error.message);
184
+ } finally {
185
+ // cleanup()은 disconnect()와 메모리 정리를 모두 수행
186
+ await client.cleanup();
187
+ console.log('\n✅ 모든 리소스 정리 완료');
188
+ }
189
+ }
190
+
191
+ main().catch(console.error);
@@ -0,0 +1,331 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * 실전 예제: AI 챗봇 구현
5
+ *
6
+ * MCP Agent Client를 사용하여 실제 AI 챗봇을 만드는 예제입니다.
7
+ * 여러 MCP 서버의 도구를 활용하여 파일 검색, 데이터 조회, 코드 실행 등을
8
+ * 자연어로 수행할 수 있습니다.
9
+ */
10
+
11
+ import { MCPAgentClient } from '../index.js';
12
+ import readline from 'readline';
13
+
14
+ // ========================================
15
+ // 챗봇 클래스
16
+ // ========================================
17
+
18
+ class MCPChatbot {
19
+ constructor() {
20
+ this.client = null;
21
+ this.conversationHistory = [];
22
+ }
23
+
24
+ async initialize() {
25
+ console.log('🤖 MCP Chatbot 초기화 중...\n');
26
+
27
+ this.client = new MCPAgentClient({
28
+ logLevel: 'warn', // 챗봇 동작 중에는 경고만 표시
29
+ enableConsoleDebug: false,
30
+ timeout: 30000,
31
+ retries: 3
32
+ });
33
+
34
+ // 여러 기능을 제공하는 MCP 서버들에 연결
35
+ await this.client.initialize({
36
+ mcpServers: {
37
+ // 파일 시스템 도구
38
+ 'filesystem': {
39
+ type: 'stdio',
40
+ command: 'npx',
41
+ args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp']
42
+ },
43
+
44
+ // GitHub 도구 (예시)
45
+ 'github': {
46
+ type: 'stdio',
47
+ command: 'npx',
48
+ args: ['-y', '@modelcontextprotocol/server-github'],
49
+ env: {
50
+ GITHUB_TOKEN: process.env.GITHUB_TOKEN || ''
51
+ }
52
+ },
53
+
54
+ // 메모리/메모장 도구 (예시)
55
+ 'memory': {
56
+ type: 'stdio',
57
+ command: 'npx',
58
+ args: ['-y', '@modelcontextprotocol/server-memory']
59
+ }
60
+ }
61
+ });
62
+
63
+ // 사용 가능한 기능 출력
64
+ const tools = this.client.getAvailableTools();
65
+ const resources = this.client.getAvailableResources();
66
+ const prompts = this.client.getAvailablePrompts();
67
+
68
+ console.log('✅ 초기화 완료!\n');
69
+ console.log('📋 사용 가능한 기능:');
70
+ console.log(` - 도구: ${tools.length}개`);
71
+ console.log(` - 리소스: ${resources.length}개`);
72
+ console.log(` - 프롬프트: ${prompts.length}개\n`);
73
+
74
+ // 도구 목록 표시
75
+ if (tools.length > 0) {
76
+ console.log('🔧 사용 가능한 도구:');
77
+ const toolsByServer = {};
78
+ tools.forEach(tool => {
79
+ if (!toolsByServer[tool.server]) {
80
+ toolsByServer[tool.server] = [];
81
+ }
82
+ toolsByServer[tool.server].push(tool.name);
83
+ });
84
+
85
+ for (const [server, toolNames] of Object.entries(toolsByServer)) {
86
+ console.log(` ${server}:`);
87
+ toolNames.forEach(name => console.log(` - ${name}`));
88
+ }
89
+ console.log();
90
+ }
91
+ }
92
+
93
+ // 사용자 의도 파싱 (간단한 키워드 기반)
94
+ parseIntent(message) {
95
+ const lowerMsg = message.toLowerCase();
96
+
97
+ // 파일 관련
98
+ if (lowerMsg.includes('파일') || lowerMsg.includes('file')) {
99
+ if (lowerMsg.includes('읽') || lowerMsg.includes('read')) {
100
+ return { action: 'readFile', query: message };
101
+ }
102
+ if (lowerMsg.includes('찾') || lowerMsg.includes('search')) {
103
+ return { action: 'searchFiles', query: message };
104
+ }
105
+ if (lowerMsg.includes('쓰') || lowerMsg.includes('write')) {
106
+ return { action: 'writeFile', query: message };
107
+ }
108
+ }
109
+
110
+ // GitHub 관련
111
+ if (lowerMsg.includes('github') || lowerMsg.includes('깃허브')) {
112
+ return { action: 'github', query: message };
113
+ }
114
+
115
+ // 메모 관련
116
+ if (lowerMsg.includes('메모') || lowerMsg.includes('기억') || lowerMsg.includes('저장')) {
117
+ return { action: 'memory', query: message };
118
+ }
119
+
120
+ // 도구 목록 조회
121
+ if (lowerMsg.includes('도구') || lowerMsg.includes('기능') || lowerMsg.includes('help')) {
122
+ return { action: 'listTools', query: message };
123
+ }
124
+
125
+ return { action: 'unknown', query: message };
126
+ }
127
+
128
+ // 메시지 처리
129
+ async processMessage(message) {
130
+ this.conversationHistory.push({ role: 'user', content: message });
131
+
132
+ const intent = this.parseIntent(message);
133
+ let response = '';
134
+
135
+ try {
136
+ switch (intent.action) {
137
+ case 'listTools':
138
+ response = this.getToolsList();
139
+ break;
140
+
141
+ case 'readFile':
142
+ response = await this.handleFileRead(message);
143
+ break;
144
+
145
+ case 'searchFiles':
146
+ response = await this.handleFileSearch(message);
147
+ break;
148
+
149
+ case 'github':
150
+ response = await this.handleGitHub(message);
151
+ break;
152
+
153
+ case 'memory':
154
+ response = await this.handleMemory(message);
155
+ break;
156
+
157
+ default:
158
+ response = await this.handleGeneral(message);
159
+ }
160
+
161
+ } catch (error) {
162
+ response = `❌ 죄송합니다. 오류가 발생했습니다: ${error.message}`;
163
+ }
164
+
165
+ this.conversationHistory.push({ role: 'assistant', content: response });
166
+ return response;
167
+ }
168
+
169
+ getToolsList() {
170
+ const tools = this.client.getAvailableTools();
171
+ let response = '🔧 사용 가능한 도구:\n\n';
172
+
173
+ const byServer = {};
174
+ tools.forEach(tool => {
175
+ if (!byServer[tool.server]) byServer[tool.server] = [];
176
+ byServer[tool.server].push(tool);
177
+ });
178
+
179
+ for (const [server, toolList] of Object.entries(byServer)) {
180
+ response += `📦 ${server}:\n`;
181
+ toolList.forEach(tool => {
182
+ response += ` • ${tool.name}\n`;
183
+ if (tool.description) {
184
+ response += ` ${tool.description}\n`;
185
+ }
186
+ });
187
+ response += '\n';
188
+ }
189
+
190
+ return response;
191
+ }
192
+
193
+ async handleFileRead(message) {
194
+ // 간단한 파일 경로 추출 (실제로는 더 정교한 파싱 필요)
195
+ const pathMatch = message.match(/["']([^"']+)["']|\/[^\s]+/);
196
+ if (!pathMatch) {
197
+ return '파일 경로를 찾을 수 없습니다. 예: "/tmp/test.txt 파일 읽어줘"';
198
+ }
199
+
200
+ const filePath = pathMatch[1] || pathMatch[0];
201
+
202
+ try {
203
+ const result = await this.client.executeTool('read_file', {
204
+ path: filePath
205
+ });
206
+
207
+ return `📄 파일 내용:\n\n${result.data}`;
208
+ } catch (error) {
209
+ return `파일을 읽을 수 없습니다: ${error.message}`;
210
+ }
211
+ }
212
+
213
+ async handleFileSearch(message) {
214
+ // 검색어 추출
215
+ const searchMatch = message.match(/["']([^"']+)["']/);
216
+ if (!searchMatch) {
217
+ return '검색어를 찾을 수 없습니다. 예: "test 파일 찾아줘"';
218
+ }
219
+
220
+ try {
221
+ const result = await this.client.executeTool('search_files', {
222
+ pattern: searchMatch[1]
223
+ });
224
+
225
+ return `🔍 검색 결과:\n\n${result.data}`;
226
+ } catch (error) {
227
+ return `검색 중 오류 발생: ${error.message}`;
228
+ }
229
+ }
230
+
231
+ async handleGitHub(message) {
232
+ const tools = this.client.getAvailableTools();
233
+ const githubTools = tools.filter(t => t.server === 'github');
234
+
235
+ if (githubTools.length === 0) {
236
+ return 'GitHub 도구를 사용할 수 없습니다.';
237
+ }
238
+
239
+ // 첫 번째 GitHub 도구 실행 (예시)
240
+ try {
241
+ const result = await this.client.executeTool(githubTools[0].name);
242
+ return `🐙 GitHub 결과:\n\n${JSON.stringify(result.data, null, 2)}`;
243
+ } catch (error) {
244
+ return `GitHub 작업 실패: ${error.message}`;
245
+ }
246
+ }
247
+
248
+ async handleMemory(message) {
249
+ // 메모 저장 로직
250
+ try {
251
+ const result = await this.client.executeTool('store_memory', {
252
+ key: 'user_note',
253
+ value: message
254
+ });
255
+
256
+ return `💾 메모를 저장했습니다.`;
257
+ } catch (error) {
258
+ return `메모 저장 실패: ${error.message}`;
259
+ }
260
+ }
261
+
262
+ async handleGeneral(message) {
263
+ // 일반 메시지 처리
264
+ const tools = this.client.getAvailableTools();
265
+
266
+ return `저는 다음 기능들을 도울 수 있습니다:\n\n` +
267
+ `• 파일 읽기/쓰기/검색\n` +
268
+ `• GitHub 작업\n` +
269
+ `• 메모 저장\n\n` +
270
+ `"도구" 또는 "help"를 입력하면 상세한 기능 목록을 볼 수 있습니다.`;
271
+ }
272
+
273
+ async shutdown() {
274
+ console.log('\n👋 챗봇을 종료합니다...');
275
+ await this.client.disconnect();
276
+ }
277
+ }
278
+
279
+ // ========================================
280
+ // 메인 실행
281
+ // ========================================
282
+
283
+ async function main() {
284
+ const chatbot = new MCPChatbot();
285
+
286
+ try {
287
+ await chatbot.initialize();
288
+
289
+ // readline 인터페이스 생성
290
+ const rl = readline.createInterface({
291
+ input: process.stdin,
292
+ output: process.stdout
293
+ });
294
+
295
+ console.log('💬 채팅을 시작합니다. (종료: exit, quit, bye)\n');
296
+
297
+ // 대화 루프
298
+ const askQuestion = () => {
299
+ rl.question('You: ', async (input) => {
300
+ const message = input.trim();
301
+
302
+ // 종료 명령
303
+ if (['exit', 'quit', 'bye'].includes(message.toLowerCase())) {
304
+ rl.close();
305
+ await chatbot.shutdown();
306
+ return;
307
+ }
308
+
309
+ // 빈 입력 무시
310
+ if (!message) {
311
+ askQuestion();
312
+ return;
313
+ }
314
+
315
+ // 메시지 처리
316
+ const response = await chatbot.processMessage(message);
317
+ console.log(`\nBot: ${response}\n`);
318
+
319
+ askQuestion();
320
+ });
321
+ };
322
+
323
+ askQuestion();
324
+
325
+ } catch (error) {
326
+ console.error('❌ 챗봇 초기화 실패:', error.message);
327
+ process.exit(1);
328
+ }
329
+ }
330
+
331
+ main().catch(console.error);