@mcp-use/cli 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/InputPrompt.d.ts +13 -0
- package/dist/InputPrompt.js +188 -0
- package/dist/MultilineInput.d.ts +13 -0
- package/dist/MultilineInput.js +154 -0
- package/dist/MultilineTextInput.d.ts +11 -0
- package/dist/MultilineTextInput.js +97 -0
- package/dist/PasteAwareInput.d.ts +13 -0
- package/dist/PasteAwareInput.js +183 -0
- package/dist/SimpleMultilineInput.d.ts +11 -0
- package/dist/SimpleMultilineInput.js +125 -0
- package/dist/app.d.ts +1 -5
- package/dist/app.js +291 -186
- package/dist/cli.js +2 -5
- package/dist/commands.d.ts +15 -30
- package/dist/commands.js +308 -568
- package/dist/components/AsciiLogo.d.ts +2 -0
- package/dist/components/AsciiLogo.js +7 -0
- package/dist/components/Footer.d.ts +5 -0
- package/dist/components/Footer.js +19 -0
- package/dist/components/InputPrompt.d.ts +13 -0
- package/dist/components/InputPrompt.js +188 -0
- package/dist/components/Messages.d.ts +21 -0
- package/dist/components/Messages.js +80 -0
- package/dist/components/ServerStatus.d.ts +7 -0
- package/dist/components/ServerStatus.js +36 -0
- package/dist/components/Spinner.d.ts +16 -0
- package/dist/components/Spinner.js +63 -0
- package/dist/components/ToolStatus.d.ts +8 -0
- package/dist/components/ToolStatus.js +33 -0
- package/dist/components/textInput.d.ts +1 -0
- package/dist/components/textInput.js +1 -0
- package/dist/logger.d.ts +10 -0
- package/dist/logger.js +48 -0
- package/dist/mcp-service.d.ts +5 -4
- package/dist/mcp-service.js +98 -207
- package/dist/services/agent-service.d.ts +56 -0
- package/dist/services/agent-service.js +203 -0
- package/dist/services/cli-service.d.ts +132 -0
- package/dist/services/cli-service.js +591 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +4 -0
- package/dist/services/llm-service.d.ts +174 -0
- package/dist/services/llm-service.js +567 -0
- package/dist/services/mcp-config-service.d.ts +69 -0
- package/dist/services/mcp-config-service.js +426 -0
- package/dist/services/mcp-service.d.ts +1 -0
- package/dist/services/mcp-service.js +1 -0
- package/dist/services/utility-service.d.ts +47 -0
- package/dist/services/utility-service.js +208 -0
- package/dist/storage.js +4 -4
- package/dist/types.d.ts +30 -0
- package/dist/types.js +1 -0
- package/package.json +22 -8
- package/readme.md +68 -39
package/dist/app.js
CHANGED
|
@@ -1,83 +1,13 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
1
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import { Box, Text, useInput, useStdout } from 'ink';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return React.createElement(UserMessageRenderer, { message: message });
|
|
12
|
-
case "assistant":
|
|
13
|
-
return React.createElement(AssistantMessageRenerer, { message: message });
|
|
14
|
-
case "command":
|
|
15
|
-
return React.createElement(CommandMessageRenderer, { message: message });
|
|
16
|
-
default:
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
const UserMessageRenderer = ({ message }) => {
|
|
21
|
-
return React.createElement(React.Fragment, null,
|
|
22
|
-
React.createElement(Box, { key: message.id, marginBottom: 1 },
|
|
23
|
-
React.createElement(Box, { marginRight: 1 },
|
|
24
|
-
React.createElement(Text, { color: 'green', bold: true }, "'\u276F'")),
|
|
25
|
-
React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
|
|
26
|
-
React.createElement(Text, { wrap: "wrap" }, message.content))));
|
|
27
|
-
};
|
|
28
|
-
const AssistantMessageRenerer = ({ message }) => {
|
|
29
|
-
return (React.createElement(React.Fragment, null,
|
|
30
|
-
React.createElement(Box, { key: message.id, marginBottom: 1 },
|
|
31
|
-
React.createElement(Box, { marginRight: 1 },
|
|
32
|
-
React.createElement(Text, { color: 'blue', bold: true }, "'\u25E6'")),
|
|
33
|
-
React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
|
|
34
|
-
React.createElement(Text, { wrap: "wrap" }, message.content)))));
|
|
35
|
-
};
|
|
36
|
-
const ToolCallRenderer = ({ message }) => {
|
|
37
|
-
return React.createElement(React.Fragment, null,
|
|
38
|
-
React.createElement(Box, { key: message.id, marginBottom: 1, borderStyle: "round", flexDirection: 'column', gap: 1 },
|
|
39
|
-
React.createElement(Box, { marginRight: 1 },
|
|
40
|
-
React.createElement(Text, { color: 'white', bold: true },
|
|
41
|
-
"\uD83D\uDD28 Tool: ",
|
|
42
|
-
message.tool_name)),
|
|
43
|
-
React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
|
|
44
|
-
React.createElement(Text, { wrap: "wrap" },
|
|
45
|
-
" Input: ",
|
|
46
|
-
message.tool_input.toString(),
|
|
47
|
-
" "),
|
|
48
|
-
React.createElement(Text, { wrap: "wrap" },
|
|
49
|
-
" Output:",
|
|
50
|
-
message.tool_output.toString(),
|
|
51
|
-
" "))));
|
|
52
|
-
};
|
|
53
|
-
const CommandMessageRenderer = ({ message }) => {
|
|
54
|
-
const { commandResult } = message;
|
|
55
|
-
let icon = '💻';
|
|
56
|
-
let color = 'cyan';
|
|
57
|
-
if (commandResult.type === 'error') {
|
|
58
|
-
icon = '❌';
|
|
59
|
-
color = 'red';
|
|
60
|
-
}
|
|
61
|
-
else if (commandResult.type === 'success') {
|
|
62
|
-
icon = '✅';
|
|
63
|
-
color = 'green';
|
|
64
|
-
}
|
|
65
|
-
else if (commandResult.type === 'prompt_key') {
|
|
66
|
-
icon = '🔑';
|
|
67
|
-
color = 'yellow';
|
|
68
|
-
}
|
|
69
|
-
else if (commandResult.type === 'prompt_server_config') {
|
|
70
|
-
icon = '🔧';
|
|
71
|
-
color = 'blue';
|
|
72
|
-
}
|
|
73
|
-
return React.createElement(React.Fragment, null,
|
|
74
|
-
React.createElement(Box, { key: message.id, marginBottom: 1 },
|
|
75
|
-
React.createElement(Box, { marginRight: 1 },
|
|
76
|
-
React.createElement(Text, { color: color, bold: true }, icon)),
|
|
77
|
-
React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
|
|
78
|
-
React.createElement(Text, { wrap: "wrap", color: color }, message.content))));
|
|
79
|
-
};
|
|
80
|
-
export default function App({ name }) {
|
|
3
|
+
import { cliService } from './services/cli-service.js';
|
|
4
|
+
import { Logger } from './logger.js';
|
|
5
|
+
import { InputPrompt } from './components/InputPrompt.js';
|
|
6
|
+
import Spinner from './components/Spinner.js';
|
|
7
|
+
import AsciiLogo from './components/AsciiLogo.js';
|
|
8
|
+
import { MessageRenderer } from './components/Messages.js';
|
|
9
|
+
import { Footer } from './components/Footer.js';
|
|
10
|
+
export default function App() {
|
|
81
11
|
const [messages, setMessages] = useState([]);
|
|
82
12
|
const [input, setInput] = useState('');
|
|
83
13
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -91,19 +21,36 @@ export default function App({ name }) {
|
|
|
91
21
|
const [isWaitingForServerConfig, setIsWaitingForServerConfig] = useState(false);
|
|
92
22
|
const [serverConfigStep, setServerConfigStep] = useState('');
|
|
93
23
|
const [currentServerConfig, setCurrentServerConfig] = useState(null);
|
|
24
|
+
const [inputHistory, setInputHistory] = useState([]);
|
|
25
|
+
const [historyIndex, setHistoryIndex] = useState(-1);
|
|
26
|
+
const [tempInput, setTempInput] = useState('');
|
|
94
27
|
const { stdout } = useStdout();
|
|
95
28
|
// Initialize MCP service on component mount
|
|
96
29
|
useEffect(() => {
|
|
97
30
|
const initializeMCP = async () => {
|
|
98
31
|
try {
|
|
32
|
+
Logger.info('Initializing MCP service...');
|
|
99
33
|
setIsLoading(true);
|
|
100
|
-
await
|
|
101
|
-
|
|
102
|
-
|
|
34
|
+
await cliService.initialize();
|
|
35
|
+
const model = cliService.getCurrentModel();
|
|
36
|
+
const servers = cliService.getConnectedServers();
|
|
37
|
+
Logger.info('MCP service initialized successfully', {
|
|
38
|
+
model,
|
|
39
|
+
connectedServers: servers,
|
|
40
|
+
});
|
|
41
|
+
setCurrentModel(model);
|
|
42
|
+
setConnectedServers(servers);
|
|
103
43
|
setShowInput(true);
|
|
104
44
|
}
|
|
105
45
|
catch (error) {
|
|
106
|
-
|
|
46
|
+
const errorMsg = error instanceof Error
|
|
47
|
+
? error.message
|
|
48
|
+
: 'Failed to initialize MCP service';
|
|
49
|
+
Logger.error('MCP initialization failed', {
|
|
50
|
+
error: errorMsg,
|
|
51
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
52
|
+
});
|
|
53
|
+
setInitializationError(errorMsg);
|
|
107
54
|
}
|
|
108
55
|
finally {
|
|
109
56
|
setIsLoading(false);
|
|
@@ -111,23 +58,93 @@ export default function App({ name }) {
|
|
|
111
58
|
};
|
|
112
59
|
initializeMCP();
|
|
113
60
|
}, []);
|
|
114
|
-
|
|
115
|
-
|
|
61
|
+
// Handle keyboard shortcuts
|
|
62
|
+
useInput((inputChar, key) => {
|
|
63
|
+
if (key.ctrl && inputChar === 'c') {
|
|
116
64
|
process.exit(0);
|
|
117
65
|
}
|
|
118
|
-
if (key.ctrl &&
|
|
66
|
+
if (key.ctrl && inputChar === 'd') {
|
|
119
67
|
process.exit(0);
|
|
120
68
|
}
|
|
121
69
|
});
|
|
70
|
+
// History navigation callbacks
|
|
71
|
+
const handleHistoryUp = useCallback(() => {
|
|
72
|
+
Logger.debug('History up requested', {
|
|
73
|
+
historyIndex,
|
|
74
|
+
historyLength: inputHistory.length,
|
|
75
|
+
});
|
|
76
|
+
if (inputHistory.length === 0)
|
|
77
|
+
return;
|
|
78
|
+
// If we're at the bottom of history, save current input
|
|
79
|
+
if (historyIndex === -1) {
|
|
80
|
+
setTempInput(input);
|
|
81
|
+
}
|
|
82
|
+
// Move up in history
|
|
83
|
+
const newIndex = Math.min(historyIndex + 1, inputHistory.length - 1);
|
|
84
|
+
if (newIndex !== historyIndex) {
|
|
85
|
+
setHistoryIndex(newIndex);
|
|
86
|
+
const historyItem = inputHistory[inputHistory.length - 1 - newIndex];
|
|
87
|
+
if (historyItem !== undefined) {
|
|
88
|
+
setInput(historyItem);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}, [
|
|
92
|
+
historyIndex,
|
|
93
|
+
inputHistory,
|
|
94
|
+
input,
|
|
95
|
+
setInput,
|
|
96
|
+
setHistoryIndex,
|
|
97
|
+
setTempInput,
|
|
98
|
+
]);
|
|
99
|
+
const handleHistoryDown = useCallback(() => {
|
|
100
|
+
Logger.debug('History down requested', {
|
|
101
|
+
historyIndex,
|
|
102
|
+
historyLength: inputHistory.length,
|
|
103
|
+
});
|
|
104
|
+
if (historyIndex === -1)
|
|
105
|
+
return;
|
|
106
|
+
// Move down in history
|
|
107
|
+
const newIndex = historyIndex - 1;
|
|
108
|
+
if (newIndex === -1) {
|
|
109
|
+
// Back to current input
|
|
110
|
+
setHistoryIndex(-1);
|
|
111
|
+
setInput(tempInput);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
setHistoryIndex(newIndex);
|
|
115
|
+
const historyItem = inputHistory[inputHistory.length - 1 - newIndex];
|
|
116
|
+
if (historyItem !== undefined) {
|
|
117
|
+
setInput(historyItem);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}, [historyIndex, inputHistory, tempInput, setInput, setHistoryIndex]);
|
|
121
|
+
// Handle submit of commands
|
|
122
122
|
const handleSubmit = async (userInput) => {
|
|
123
123
|
if (!userInput.trim())
|
|
124
124
|
return;
|
|
125
|
+
// Add input to history (avoid duplicates and empty strings)
|
|
126
|
+
const trimmedInput = userInput.trim();
|
|
127
|
+
if (trimmedInput &&
|
|
128
|
+
(inputHistory.length === 0 ||
|
|
129
|
+
inputHistory[inputHistory.length - 1] !== trimmedInput)) {
|
|
130
|
+
setInputHistory(prev => [...prev, trimmedInput]);
|
|
131
|
+
}
|
|
132
|
+
// Reset history navigation
|
|
133
|
+
setHistoryIndex(-1);
|
|
134
|
+
setTempInput('');
|
|
135
|
+
Logger.debug('User input received', {
|
|
136
|
+
input: trimmedInput,
|
|
137
|
+
isWaitingForApiKey,
|
|
138
|
+
isWaitingForServerConfig,
|
|
139
|
+
historyLength: inputHistory.length + 1,
|
|
140
|
+
});
|
|
125
141
|
// Check if we're waiting for server configuration input
|
|
126
142
|
if (isWaitingForServerConfig) {
|
|
143
|
+
Logger.debug('Processing server config input', { step: serverConfigStep });
|
|
127
144
|
const userMessage = {
|
|
128
145
|
id: Date.now().toString(),
|
|
129
146
|
role: 'user',
|
|
130
|
-
content:
|
|
147
|
+
content: trimmedInput,
|
|
131
148
|
timestamp: new Date(),
|
|
132
149
|
};
|
|
133
150
|
setMessages(prev => [...prev, userMessage]);
|
|
@@ -135,35 +152,46 @@ export default function App({ name }) {
|
|
|
135
152
|
setIsLoading(true);
|
|
136
153
|
try {
|
|
137
154
|
// Import CommandHandler to access handleServerConfigInput
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
setMessages(prev => [...prev, commandMessage]);
|
|
148
|
-
// Check if we're continuing server config or done
|
|
149
|
-
if (result.commandResult.type === 'prompt_server_config' && result.commandResult.data) {
|
|
150
|
-
setServerConfigStep(result.commandResult.data.step);
|
|
151
|
-
setCurrentServerConfig(result.commandResult.data.config);
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
// Server config is done
|
|
155
|
-
setIsWaitingForServerConfig(false);
|
|
156
|
-
setServerConfigStep('');
|
|
157
|
-
setCurrentServerConfig(null);
|
|
158
|
-
// Update connected servers if servers were connected or disconnected
|
|
159
|
-
if (result.commandResult.data?.serverConnected || result.commandResult.data?.serverDisconnected) {
|
|
160
|
-
setConnectedServers(mcpService.getConnectedServers());
|
|
155
|
+
const stream = cliService.sendMessage(trimmedInput, false, '', '', true, serverConfigStep, currentServerConfig);
|
|
156
|
+
for await (const result of stream) {
|
|
157
|
+
Logger.debug('Server config result received', { result });
|
|
158
|
+
if (result.commandResult) {
|
|
159
|
+
// Check if we're continuing server config or done
|
|
160
|
+
if (result.commandResult.type === 'prompt_server_config' &&
|
|
161
|
+
result.commandResult.data) {
|
|
162
|
+
setServerConfigStep(result.commandResult.data.step);
|
|
163
|
+
setCurrentServerConfig(result.commandResult.data.config);
|
|
161
164
|
}
|
|
165
|
+
else {
|
|
166
|
+
// Server config is done
|
|
167
|
+
setIsWaitingForServerConfig(false);
|
|
168
|
+
setServerConfigStep('');
|
|
169
|
+
setCurrentServerConfig(null);
|
|
170
|
+
// Update connected servers if servers were connected or disconnected
|
|
171
|
+
if (result.commandResult.data?.reinitializeAgent) {
|
|
172
|
+
await cliService.initializeAgent();
|
|
173
|
+
setConnectedServers([...cliService.getConnectedServers()]);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const commandMessage = {
|
|
177
|
+
id: (Date.now() + 1).toString(),
|
|
178
|
+
role: 'command',
|
|
179
|
+
content: result.response || '',
|
|
180
|
+
commandResult: result.commandResult,
|
|
181
|
+
timestamp: new Date(),
|
|
182
|
+
};
|
|
183
|
+
setMessages(prev => [...prev, commandMessage]);
|
|
184
|
+
}
|
|
185
|
+
if (result.done) {
|
|
186
|
+
setIsLoading(false);
|
|
162
187
|
}
|
|
163
188
|
}
|
|
164
|
-
setIsLoading(false);
|
|
165
189
|
}
|
|
166
190
|
catch (error) {
|
|
191
|
+
Logger.error('Server config error', {
|
|
192
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
193
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
194
|
+
});
|
|
167
195
|
const errorMessage = {
|
|
168
196
|
id: (Date.now() + 1).toString(),
|
|
169
197
|
role: 'assistant',
|
|
@@ -181,7 +209,11 @@ export default function App({ name }) {
|
|
|
181
209
|
}
|
|
182
210
|
// Check if we're waiting for an API key
|
|
183
211
|
if (isWaitingForApiKey) {
|
|
184
|
-
|
|
212
|
+
Logger.debug('Processing API key input', {
|
|
213
|
+
provider: pendingProvider,
|
|
214
|
+
model: pendingModel,
|
|
215
|
+
});
|
|
216
|
+
const maskedInput = trimmedInput.replace(/./g, '*');
|
|
185
217
|
const userMessage = {
|
|
186
218
|
id: Date.now().toString(),
|
|
187
219
|
role: 'user',
|
|
@@ -192,28 +224,39 @@ export default function App({ name }) {
|
|
|
192
224
|
setInput('');
|
|
193
225
|
setIsLoading(true);
|
|
194
226
|
try {
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
227
|
+
const stream = cliService.sendMessage(trimmedInput.trim(), true, pendingProvider, pendingModel);
|
|
228
|
+
for await (const result of stream) {
|
|
229
|
+
Logger.debug('API key result received', {
|
|
230
|
+
success: !!result.commandResult?.data?.llmConfig,
|
|
231
|
+
});
|
|
232
|
+
if (result.commandResult) {
|
|
233
|
+
const commandMessage = {
|
|
234
|
+
id: (Date.now() + 1).toString(),
|
|
235
|
+
role: 'command',
|
|
236
|
+
content: result.response || '',
|
|
237
|
+
commandResult: result.commandResult,
|
|
238
|
+
timestamp: new Date(),
|
|
239
|
+
};
|
|
240
|
+
setMessages(prev => [...prev, commandMessage]);
|
|
241
|
+
// Update current model if successful
|
|
242
|
+
if (result.commandResult.data?.llmConfig) {
|
|
243
|
+
setCurrentModel(cliService.getCurrentModel());
|
|
244
|
+
}
|
|
245
|
+
// Reset API key input state
|
|
246
|
+
setIsWaitingForApiKey(false);
|
|
247
|
+
setPendingProvider('');
|
|
248
|
+
setPendingModel('');
|
|
249
|
+
}
|
|
250
|
+
if (result.done) {
|
|
251
|
+
setIsLoading(false);
|
|
208
252
|
}
|
|
209
|
-
// Reset API key input state
|
|
210
|
-
setIsWaitingForApiKey(false);
|
|
211
|
-
setPendingProvider('');
|
|
212
|
-
setPendingModel('');
|
|
213
253
|
}
|
|
214
|
-
setIsLoading(false);
|
|
215
254
|
}
|
|
216
255
|
catch (error) {
|
|
256
|
+
Logger.error('API key error', {
|
|
257
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
258
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
259
|
+
});
|
|
217
260
|
const errorMessage = {
|
|
218
261
|
id: (Date.now() + 1).toString(),
|
|
219
262
|
role: 'assistant',
|
|
@@ -229,61 +272,107 @@ export default function App({ name }) {
|
|
|
229
272
|
}
|
|
230
273
|
return;
|
|
231
274
|
}
|
|
275
|
+
Logger.debug('Processing regular message');
|
|
232
276
|
const userMessage = {
|
|
233
277
|
id: Date.now().toString(),
|
|
234
278
|
role: 'user',
|
|
235
|
-
content:
|
|
279
|
+
content: trimmedInput,
|
|
236
280
|
timestamp: new Date(),
|
|
237
281
|
};
|
|
238
282
|
setMessages(prev => [...prev, userMessage]);
|
|
239
283
|
setInput('');
|
|
240
284
|
setIsLoading(true);
|
|
241
285
|
try {
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
286
|
+
const stream = cliService.sendMessage(trimmedInput);
|
|
287
|
+
let assistantMessageId = null;
|
|
288
|
+
for await (const chunk of stream) {
|
|
289
|
+
Logger.debug('Message chunk received', {
|
|
290
|
+
isCommand: chunk.isCommand,
|
|
291
|
+
hasContent: !!chunk.response,
|
|
292
|
+
toolCallsCount: chunk.toolCalls?.length || 0,
|
|
293
|
+
});
|
|
294
|
+
if (chunk.isCommand && chunk.commandResult) {
|
|
295
|
+
// Check if we need to prompt for API key
|
|
296
|
+
if (chunk.commandResult.data?.reinitializeAgent) {
|
|
297
|
+
await cliService.initializeAgent();
|
|
298
|
+
setConnectedServers([...cliService.getConnectedServers()]);
|
|
299
|
+
}
|
|
300
|
+
// Check if we need to prompt for API key
|
|
301
|
+
if (chunk.commandResult.type === 'prompt_key' &&
|
|
302
|
+
chunk.commandResult.data) {
|
|
303
|
+
setIsWaitingForApiKey(true);
|
|
304
|
+
setPendingProvider(chunk.commandResult.data.provider);
|
|
305
|
+
setPendingModel(chunk.commandResult.data.model);
|
|
306
|
+
}
|
|
307
|
+
else if (chunk.commandResult.type === 'prompt_server_config' &&
|
|
308
|
+
chunk.commandResult.data) {
|
|
309
|
+
setIsWaitingForServerConfig(true);
|
|
310
|
+
setServerConfigStep(chunk.commandResult.data.step);
|
|
311
|
+
setCurrentServerConfig(chunk.commandResult.data.config || null);
|
|
312
|
+
}
|
|
313
|
+
else if (chunk.commandResult.data?.hasOwnProperty('llmConfig')) {
|
|
314
|
+
// Update current model if it changed (including null for clearkeys)
|
|
315
|
+
setCurrentModel(cliService.getCurrentModel());
|
|
316
|
+
}
|
|
317
|
+
const commandMessage = {
|
|
318
|
+
id: (Date.now() + 1).toString(),
|
|
319
|
+
role: 'command',
|
|
320
|
+
content: chunk.response || '',
|
|
321
|
+
commandResult: chunk.commandResult,
|
|
322
|
+
timestamp: new Date(),
|
|
323
|
+
};
|
|
324
|
+
setMessages(prev => [...prev, commandMessage]);
|
|
263
325
|
}
|
|
264
|
-
else
|
|
265
|
-
//
|
|
266
|
-
|
|
326
|
+
else {
|
|
327
|
+
// Handle streaming agent response
|
|
328
|
+
if (chunk.toolCalls && chunk.toolCalls.length > 0) {
|
|
329
|
+
setMessages(prev => [...prev, ...chunk.toolCalls]);
|
|
330
|
+
}
|
|
331
|
+
if (chunk.thought) {
|
|
332
|
+
const thoughtMessage = {
|
|
333
|
+
id: (Date.now() + Math.random()).toString(),
|
|
334
|
+
role: 'thought',
|
|
335
|
+
content: chunk.thought,
|
|
336
|
+
timestamp: new Date(),
|
|
337
|
+
};
|
|
338
|
+
setMessages(prev => [...prev, thoughtMessage]);
|
|
339
|
+
}
|
|
340
|
+
if (chunk.response) {
|
|
341
|
+
if (assistantMessageId === null) {
|
|
342
|
+
// First chunk of an assistant message
|
|
343
|
+
const assistantMessage = {
|
|
344
|
+
id: (Date.now() + 1).toString(),
|
|
345
|
+
role: 'assistant',
|
|
346
|
+
content: chunk.response,
|
|
347
|
+
timestamp: new Date(),
|
|
348
|
+
};
|
|
349
|
+
assistantMessageId = assistantMessage.id;
|
|
350
|
+
setMessages(prev => [...prev, assistantMessage]);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
// Subsequent chunks: find and update the message
|
|
354
|
+
setMessages(prev => prev.map(msg => {
|
|
355
|
+
if (msg.id === assistantMessageId && msg.role === 'assistant') {
|
|
356
|
+
return {
|
|
357
|
+
...msg,
|
|
358
|
+
content: msg.content + chunk.response,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
return msg;
|
|
362
|
+
}));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
267
365
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
setCurrentModel(mcpService.getCurrentModel());
|
|
366
|
+
if (chunk.done) {
|
|
367
|
+
setIsLoading(false);
|
|
271
368
|
}
|
|
272
369
|
}
|
|
273
|
-
else {
|
|
274
|
-
// Handle regular assistant response
|
|
275
|
-
const assistantMessage = {
|
|
276
|
-
id: (Date.now() + 1).toString(),
|
|
277
|
-
role: 'assistant',
|
|
278
|
-
content: result.response,
|
|
279
|
-
timestamp: new Date(),
|
|
280
|
-
};
|
|
281
|
-
// Add assistant message and any tool calls
|
|
282
|
-
setMessages(prev => [...prev, assistantMessage, ...result.toolCalls]);
|
|
283
|
-
}
|
|
284
|
-
setIsLoading(false);
|
|
285
370
|
}
|
|
286
371
|
catch (error) {
|
|
372
|
+
Logger.error('Message processing error', {
|
|
373
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
374
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
375
|
+
});
|
|
287
376
|
const errorMessage = {
|
|
288
377
|
id: (Date.now() + 1).toString(),
|
|
289
378
|
role: 'assistant',
|
|
@@ -298,23 +387,24 @@ export default function App({ name }) {
|
|
|
298
387
|
React.createElement(Box, { borderStyle: "round", borderColor: "blue", paddingX: 1, marginBottom: 1 },
|
|
299
388
|
React.createElement(Box, { flexDirection: "column", width: "100%" },
|
|
300
389
|
React.createElement(Box, { flexDirection: "row", justifyContent: "space-between", width: "100%" },
|
|
301
|
-
React.createElement(Text, { color: "blue",
|
|
302
|
-
"MCP-Use CLI ",
|
|
303
|
-
name ? `- ${name}` : ' '),
|
|
390
|
+
React.createElement(Text, { color: "blue" }, "mcp use"),
|
|
304
391
|
React.createElement(Text, { color: "gray" },
|
|
305
392
|
"Model: ",
|
|
306
393
|
currentModel)),
|
|
307
394
|
React.createElement(Box, { flexDirection: "row", justifyContent: "flex-start", width: "100%" },
|
|
308
395
|
React.createElement(Text, { color: "gray" },
|
|
309
|
-
"Connected servers:
|
|
310
|
-
|
|
396
|
+
"Connected servers:",
|
|
397
|
+
' ',
|
|
398
|
+
connectedServers.length > 0
|
|
399
|
+
? connectedServers.join(', ')
|
|
400
|
+
: 'none')))),
|
|
311
401
|
React.createElement(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1 },
|
|
312
402
|
initializationError && (React.createElement(Box, { marginBottom: 1 },
|
|
313
403
|
React.createElement(Text, { color: "red" },
|
|
314
404
|
"\u274C ",
|
|
315
405
|
initializationError))),
|
|
316
406
|
!initializationError && messages.length === 0 && !isLoading && (React.createElement(Box, { marginBottom: 1, flexDirection: "column" },
|
|
317
|
-
React.createElement(
|
|
407
|
+
React.createElement(AsciiLogo, null),
|
|
318
408
|
React.createElement(Text, { color: "gray" }, "Welcome to MCP-Use CLI!"),
|
|
319
409
|
currentModel.includes('No') ? (React.createElement(Box, { flexDirection: "column" },
|
|
320
410
|
React.createElement(Text, { color: "yellow" },
|
|
@@ -327,17 +417,32 @@ export default function App({ name }) {
|
|
|
327
417
|
React.createElement(Text, { color: "gray" }, "Use slash commands like /help, /model, or /status for configuration."))))),
|
|
328
418
|
!initializationError && messages.length === 0 && isLoading && (React.createElement(Box, { marginBottom: 1 },
|
|
329
419
|
React.createElement(Text, { color: "blue" }, "\uD83D\uDD04 Initializing MCP service..."))),
|
|
330
|
-
messages.map(message => React.createElement(MessageRenderer, { message: message })),
|
|
420
|
+
messages.map(message => (React.createElement(MessageRenderer, { message: message }))),
|
|
331
421
|
isLoading && (React.createElement(Box, { marginBottom: 1 },
|
|
332
422
|
React.createElement(Box, { marginRight: 1 },
|
|
333
|
-
React.createElement(Text, { color: "blue"
|
|
334
|
-
|
|
335
|
-
showInput && !initializationError && (React.createElement(Box, {
|
|
336
|
-
React.createElement(Box, {
|
|
337
|
-
|
|
338
|
-
React.createElement(TextInput, { value: input, onChange: setInput, onSubmit: handleSubmit, placeholder: isWaitingForApiKey
|
|
339
|
-
? `Enter ${pendingProvider.toUpperCase()} API key...`
|
|
423
|
+
React.createElement(Text, { color: "blue" },
|
|
424
|
+
React.createElement(Spinner, { type: "mcpuse" })))))),
|
|
425
|
+
showInput && !initializationError && (React.createElement(Box, { flexDirection: "column", marginTop: 1 },
|
|
426
|
+
React.createElement(Box, { borderStyle: "round", borderColor: isWaitingForApiKey
|
|
427
|
+
? 'yellow'
|
|
340
428
|
: isWaitingForServerConfig
|
|
341
|
-
?
|
|
342
|
-
:
|
|
429
|
+
? 'blue'
|
|
430
|
+
: 'gray', minHeight: 3 },
|
|
431
|
+
React.createElement(Box, { flexDirection: "row", width: "100%" },
|
|
432
|
+
React.createElement(Box, { marginRight: 1, alignSelf: "flex-start", flexShrink: 0 },
|
|
433
|
+
React.createElement(Text, { color: isWaitingForApiKey
|
|
434
|
+
? 'yellow'
|
|
435
|
+
: isWaitingForServerConfig
|
|
436
|
+
? 'blue'
|
|
437
|
+
: 'green', bold: true }, isWaitingForApiKey
|
|
438
|
+
? '🔑'
|
|
439
|
+
: isWaitingForServerConfig
|
|
440
|
+
? '🔧'
|
|
441
|
+
: '❯')),
|
|
442
|
+
React.createElement(InputPrompt, { value: input, onChange: setInput, onSubmit: handleSubmit, onHistoryUp: handleHistoryUp, onHistoryDown: handleHistoryDown, placeholder: isWaitingForApiKey
|
|
443
|
+
? `Enter ${pendingProvider.toUpperCase()} API key...`
|
|
444
|
+
: isWaitingForServerConfig
|
|
445
|
+
? 'Enter server configuration...'
|
|
446
|
+
: 'Type your message...', mask: isWaitingForApiKey ? '*' : undefined }))))),
|
|
447
|
+
React.createElement(Footer, { servers: connectedServers, modelSlug: currentModel })));
|
|
343
448
|
}
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { render } from 'ink';
|
|
4
4
|
import meow from 'meow';
|
|
5
5
|
import App from './app.js';
|
|
6
|
-
|
|
6
|
+
meow(`
|
|
7
7
|
Usage
|
|
8
8
|
$ mcp-use-cli
|
|
9
9
|
|
|
@@ -26,12 +26,9 @@ const cli = meow(`
|
|
|
26
26
|
`, {
|
|
27
27
|
importMeta: import.meta,
|
|
28
28
|
flags: {
|
|
29
|
-
name: {
|
|
30
|
-
type: 'string',
|
|
31
|
-
},
|
|
32
29
|
config: {
|
|
33
30
|
type: 'string',
|
|
34
31
|
},
|
|
35
32
|
},
|
|
36
33
|
});
|
|
37
|
-
render(React.createElement(App,
|
|
34
|
+
render(React.createElement(App, null));
|