protoagent 0.0.5 → 0.1.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/README.md +99 -19
- package/dist/App.js +602 -0
- package/dist/agentic-loop.js +492 -525
- package/dist/cli.js +39 -0
- package/dist/components/CollapsibleBox.js +26 -0
- package/dist/components/ConfigDialog.js +40 -0
- package/dist/components/ConsolidatedToolMessage.js +41 -0
- package/dist/components/FormattedMessage.js +93 -0
- package/dist/components/Table.js +275 -0
- package/dist/config.js +171 -0
- package/dist/mcp.js +170 -0
- package/dist/providers.js +137 -0
- package/dist/sessions.js +161 -0
- package/dist/skills.js +229 -0
- package/dist/sub-agent.js +103 -0
- package/dist/system-prompt.js +131 -0
- package/dist/tools/bash.js +178 -0
- package/dist/tools/edit-file.js +65 -171
- package/dist/tools/index.js +79 -134
- package/dist/tools/list-directory.js +20 -73
- package/dist/tools/read-file.js +57 -101
- package/dist/tools/search-files.js +74 -162
- package/dist/tools/todo.js +57 -140
- package/dist/tools/webfetch.js +310 -0
- package/dist/tools/write-file.js +44 -135
- package/dist/utils/approval.js +69 -0
- package/dist/utils/compactor.js +87 -0
- package/dist/utils/cost-tracker.js +26 -81
- package/dist/utils/format-message.js +26 -0
- package/dist/utils/logger.js +101 -307
- package/dist/utils/path-validation.js +74 -0
- package/package.json +45 -51
- package/LICENSE +0 -21
- package/dist/config/client.js +0 -315
- package/dist/config/commands.js +0 -223
- package/dist/config/manager.js +0 -117
- package/dist/config/mcp-commands.js +0 -266
- package/dist/config/mcp-manager.js +0 -240
- package/dist/config/mcp-types.js +0 -28
- package/dist/config/providers.js +0 -229
- package/dist/config/setup.js +0 -209
- package/dist/config/system-prompt.js +0 -397
- package/dist/config/types.js +0 -4
- package/dist/index.js +0 -229
- package/dist/tools/create-directory.js +0 -76
- package/dist/tools/directory-operations.js +0 -195
- package/dist/tools/file-operations.js +0 -211
- package/dist/tools/run-shell-command.js +0 -746
- package/dist/tools/search-operations.js +0 -179
- package/dist/tools/shell-operations.js +0 -342
- package/dist/tools/task-complete.js +0 -26
- package/dist/tools/view-directory-tree.js +0 -125
- package/dist/tools.js +0 -2
- package/dist/utils/conversation-compactor.js +0 -140
- package/dist/utils/enhanced-prompt.js +0 -23
- package/dist/utils/file-operations-approval.js +0 -373
- package/dist/utils/interrupt-handler.js +0 -127
- package/dist/utils/user-cancellation.js +0 -34
package/dist/config/manager.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configuration manager for ProtoAgent
|
|
3
|
-
*/
|
|
4
|
-
import fs from 'fs/promises';
|
|
5
|
-
import path from 'path';
|
|
6
|
-
import os from 'os';
|
|
7
|
-
import { geminiProvider, openaiProvider, cerebrasProvider } from './providers.js';
|
|
8
|
-
/**
|
|
9
|
-
* Get the config directory path
|
|
10
|
-
*/
|
|
11
|
-
function getConfigDir() {
|
|
12
|
-
const homeDir = os.homedir();
|
|
13
|
-
// Use XDG Base Directory specification on Unix-like systems
|
|
14
|
-
if (process.platform === 'win32') {
|
|
15
|
-
return path.join(homeDir, 'AppData', 'Local', 'protoagent');
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
return path.join(homeDir, '.local', 'share', 'protoagent');
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Get the config file path
|
|
23
|
-
*/
|
|
24
|
-
function getConfigPath() {
|
|
25
|
-
return path.join(getConfigDir(), 'config.json');
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Ensure config directory exists
|
|
29
|
-
*/
|
|
30
|
-
async function ensureConfigDir() {
|
|
31
|
-
const configDir = getConfigDir();
|
|
32
|
-
try {
|
|
33
|
-
await fs.access(configDir);
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
await fs.mkdir(configDir, { recursive: true });
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Check if configuration exists
|
|
41
|
-
*/
|
|
42
|
-
export async function hasConfig() {
|
|
43
|
-
try {
|
|
44
|
-
await fs.access(getConfigPath());
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Load user configuration
|
|
53
|
-
*/
|
|
54
|
-
export async function loadConfig() {
|
|
55
|
-
try {
|
|
56
|
-
const configPath = getConfigPath();
|
|
57
|
-
const configData = await fs.readFile(configPath, 'utf-8');
|
|
58
|
-
return JSON.parse(configData);
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
throw new Error(`Failed to load configuration: ${error.message}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Save user configuration
|
|
66
|
-
*/
|
|
67
|
-
export async function saveConfig(config) {
|
|
68
|
-
try {
|
|
69
|
-
await ensureConfigDir();
|
|
70
|
-
const configPath = getConfigPath();
|
|
71
|
-
await fs.writeFile(configPath, JSON.stringify(config, null, 2));
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
throw new Error(`Failed to save configuration: ${error.message}`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Validate configuration
|
|
79
|
-
*/
|
|
80
|
-
export function validateConfig(config) {
|
|
81
|
-
if (!config || typeof config !== 'object') {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
const { provider, model, credentials } = config;
|
|
85
|
-
if (!model || !credentials || !(credentials.OPENAI_API_KEY || credentials.GEMINI_API_KEY || credentials.CEREBRAS_API_KEY)) {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
if (provider === 'gemini') {
|
|
89
|
-
// Check if model is available for Gemini
|
|
90
|
-
if (!geminiProvider.models.includes(model)) {
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
// Additional model validation for Gemini can be added here
|
|
94
|
-
return true;
|
|
95
|
-
}
|
|
96
|
-
if (provider === 'openai') {
|
|
97
|
-
// Check if model is available for OpenAI
|
|
98
|
-
if (!openaiProvider.models.includes(model)) {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
return true;
|
|
102
|
-
}
|
|
103
|
-
if (provider === 'cerebras') {
|
|
104
|
-
// Check if model is available for Cerebras
|
|
105
|
-
if (!cerebrasProvider.models.includes(model)) {
|
|
106
|
-
return false;
|
|
107
|
-
}
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Get configuration directory path for display
|
|
114
|
-
*/
|
|
115
|
-
export function getConfigDirectory() {
|
|
116
|
-
return getConfigDir();
|
|
117
|
-
}
|
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP management commands for ProtoAgent CLI
|
|
3
|
-
*/
|
|
4
|
-
import inquirer from 'inquirer';
|
|
5
|
-
import { MCPManager } from './mcp-manager.js';
|
|
6
|
-
const mcpManager = new MCPManager();
|
|
7
|
-
/**
|
|
8
|
-
* Show current MCP configuration and status
|
|
9
|
-
*/
|
|
10
|
-
export async function showMCPStatus() {
|
|
11
|
-
try {
|
|
12
|
-
await mcpManager.loadConfig();
|
|
13
|
-
console.log('\n🔌 MCP Configuration & Status:');
|
|
14
|
-
console.log('─'.repeat(50));
|
|
15
|
-
const servers = mcpManager.listServers();
|
|
16
|
-
const connectionStatus = mcpManager.getConnectionStatus();
|
|
17
|
-
if (Object.keys(servers).length === 0) {
|
|
18
|
-
console.log('No MCP servers configured');
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
for (const [name, config] of Object.entries(servers)) {
|
|
22
|
-
const status = connectionStatus[name];
|
|
23
|
-
const statusIcon = status === true ? '🟢' : status === false ? '🔴' : '⚪';
|
|
24
|
-
const typeLabel = config.isBuiltIn ? '(built-in)' : '(custom)';
|
|
25
|
-
console.log(`${statusIcon} ${name} ${typeLabel}`);
|
|
26
|
-
console.log(` Description: ${config.description}`);
|
|
27
|
-
console.log(` Command: ${config.command} ${(config.args || []).join(' ')}`);
|
|
28
|
-
console.log(` Enabled: ${config.enabled ? 'Yes' : 'No'}`);
|
|
29
|
-
console.log('');
|
|
30
|
-
}
|
|
31
|
-
// Show available tools if connected
|
|
32
|
-
const tools = await mcpManager.getAllTools();
|
|
33
|
-
if (tools.length > 0) {
|
|
34
|
-
console.log('🛠️ Available Tools:');
|
|
35
|
-
for (const tool of tools) {
|
|
36
|
-
console.log(` • ${tool.server}:${tool.name} - ${tool.description || 'No description'}`);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
console.log('─'.repeat(50));
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
console.error(`❌ Error showing MCP status: ${error.message}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Connect to MCP servers
|
|
47
|
-
*/
|
|
48
|
-
export async function connectMCPServers() {
|
|
49
|
-
try {
|
|
50
|
-
await mcpManager.loadConfig();
|
|
51
|
-
await mcpManager.connectToAllServers();
|
|
52
|
-
}
|
|
53
|
-
catch (error) {
|
|
54
|
-
console.error(`❌ Error connecting to MCP servers: ${error.message}`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Add a custom MCP server
|
|
59
|
-
*/
|
|
60
|
-
export async function addCustomMCPServer() {
|
|
61
|
-
try {
|
|
62
|
-
console.log('\n🔧 Add Custom MCP Server');
|
|
63
|
-
console.log('Configure a new MCP server for ProtoAgent\n');
|
|
64
|
-
const serverConfig = await inquirer.prompt([
|
|
65
|
-
{
|
|
66
|
-
type: 'input',
|
|
67
|
-
name: 'name',
|
|
68
|
-
message: 'Server name (unique identifier):',
|
|
69
|
-
validate: (input) => {
|
|
70
|
-
if (!input || input.trim().length === 0) {
|
|
71
|
-
return 'Server name is required';
|
|
72
|
-
}
|
|
73
|
-
if (!/^[a-zA-Z0-9\-_]+$/.test(input.trim())) {
|
|
74
|
-
return 'Server name can only contain letters, numbers, hyphens, and underscores';
|
|
75
|
-
}
|
|
76
|
-
return true;
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
type: 'input',
|
|
81
|
-
name: 'description',
|
|
82
|
-
message: 'Description:',
|
|
83
|
-
validate: (input) => input.trim().length > 0 ? true : 'Description is required'
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
type: 'input',
|
|
87
|
-
name: 'command',
|
|
88
|
-
message: 'Command to run the server:',
|
|
89
|
-
validate: (input) => input.trim().length > 0 ? true : 'Command is required'
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
type: 'input',
|
|
93
|
-
name: 'args',
|
|
94
|
-
message: 'Arguments (space-separated, optional):',
|
|
95
|
-
default: ''
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
type: 'confirm',
|
|
99
|
-
name: 'enabled',
|
|
100
|
-
message: 'Enable this server?',
|
|
101
|
-
default: true
|
|
102
|
-
}
|
|
103
|
-
]);
|
|
104
|
-
const newServer = {
|
|
105
|
-
name: serverConfig.name.trim(),
|
|
106
|
-
description: serverConfig.description.trim(),
|
|
107
|
-
command: serverConfig.command.trim(),
|
|
108
|
-
args: serverConfig.args.trim() ? serverConfig.args.trim().split(' ') : [],
|
|
109
|
-
enabled: serverConfig.enabled,
|
|
110
|
-
isBuiltIn: false
|
|
111
|
-
};
|
|
112
|
-
await mcpManager.loadConfig();
|
|
113
|
-
await mcpManager.addCustomServer(newServer);
|
|
114
|
-
console.log(`\n✅ Custom MCP server '${newServer.name}' added successfully!`);
|
|
115
|
-
if (newServer.enabled) {
|
|
116
|
-
const { connectNow } = await inquirer.prompt([
|
|
117
|
-
{
|
|
118
|
-
type: 'confirm',
|
|
119
|
-
name: 'connectNow',
|
|
120
|
-
message: 'Connect to this server now?',
|
|
121
|
-
default: true
|
|
122
|
-
}
|
|
123
|
-
]);
|
|
124
|
-
if (connectNow) {
|
|
125
|
-
const connection = await mcpManager.connectToServer(newServer.name);
|
|
126
|
-
if (connection) {
|
|
127
|
-
console.log(`🎉 Successfully connected to ${newServer.name}!`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
catch (error) {
|
|
133
|
-
console.error(`❌ Error adding custom MCP server: ${error.message}`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Remove a custom MCP server
|
|
138
|
-
*/
|
|
139
|
-
export async function removeCustomMCPServer() {
|
|
140
|
-
try {
|
|
141
|
-
await mcpManager.loadConfig();
|
|
142
|
-
const servers = mcpManager.listServers();
|
|
143
|
-
const customServers = Object.entries(servers).filter(([_, config]) => !config.isBuiltIn);
|
|
144
|
-
if (customServers.length === 0) {
|
|
145
|
-
console.log('📭 No custom MCP servers configured');
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
const { serverToRemove } = await inquirer.prompt([
|
|
149
|
-
{
|
|
150
|
-
type: 'list',
|
|
151
|
-
name: 'serverToRemove',
|
|
152
|
-
message: 'Select server to remove:',
|
|
153
|
-
choices: customServers.map(([name, config]) => ({
|
|
154
|
-
name: `${name} - ${config.description}`,
|
|
155
|
-
value: name
|
|
156
|
-
}))
|
|
157
|
-
}
|
|
158
|
-
]);
|
|
159
|
-
const { confirm } = await inquirer.prompt([
|
|
160
|
-
{
|
|
161
|
-
type: 'confirm',
|
|
162
|
-
name: 'confirm',
|
|
163
|
-
message: `Are you sure you want to remove '${serverToRemove}'?`,
|
|
164
|
-
default: false
|
|
165
|
-
}
|
|
166
|
-
]);
|
|
167
|
-
if (confirm) {
|
|
168
|
-
await mcpManager.removeCustomServer(serverToRemove);
|
|
169
|
-
console.log(`✅ Custom MCP server '${serverToRemove}' removed successfully!`);
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
console.log('Operation cancelled.');
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
catch (error) {
|
|
176
|
-
console.error(`❌ Error removing custom MCP server: ${error.message}`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Toggle MCP server enabled/disabled status
|
|
181
|
-
*/
|
|
182
|
-
export async function toggleMCPServer() {
|
|
183
|
-
try {
|
|
184
|
-
await mcpManager.loadConfig();
|
|
185
|
-
const servers = mcpManager.listServers();
|
|
186
|
-
if (Object.keys(servers).length === 0) {
|
|
187
|
-
console.log('📭 No MCP servers configured');
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
const { serverToToggle } = await inquirer.prompt([
|
|
191
|
-
{
|
|
192
|
-
type: 'list',
|
|
193
|
-
name: 'serverToToggle',
|
|
194
|
-
message: 'Select server to enable/disable:',
|
|
195
|
-
choices: Object.entries(servers).map(([name, config]) => ({
|
|
196
|
-
name: `${name} - ${config.enabled ? '🟢 Enabled' : '🔴 Disabled'} - ${config.description}`,
|
|
197
|
-
value: name
|
|
198
|
-
}))
|
|
199
|
-
}
|
|
200
|
-
]);
|
|
201
|
-
const currentConfig = servers[serverToToggle];
|
|
202
|
-
const newStatus = !currentConfig.enabled;
|
|
203
|
-
// Update the configuration
|
|
204
|
-
await mcpManager.loadConfig();
|
|
205
|
-
const updatedServers = mcpManager.listServers();
|
|
206
|
-
updatedServers[serverToToggle].enabled = newStatus;
|
|
207
|
-
// Save the updated configuration
|
|
208
|
-
const updatedConfig = {
|
|
209
|
-
servers: updatedServers,
|
|
210
|
-
globalTimeout: 30000,
|
|
211
|
-
maxConcurrentConnections: 5,
|
|
212
|
-
retryAttempts: 3
|
|
213
|
-
};
|
|
214
|
-
const mcpManagerForSave = new MCPManager(updatedConfig);
|
|
215
|
-
await mcpManagerForSave.saveConfig();
|
|
216
|
-
console.log(`✅ Server '${serverToToggle}' ${newStatus ? 'enabled' : 'disabled'}`);
|
|
217
|
-
}
|
|
218
|
-
catch (error) {
|
|
219
|
-
console.error(`❌ Error toggling MCP server: ${error.message}`);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Test connection to a specific MCP server
|
|
224
|
-
*/
|
|
225
|
-
export async function testMCPServer() {
|
|
226
|
-
try {
|
|
227
|
-
await mcpManager.loadConfig();
|
|
228
|
-
const servers = mcpManager.listServers();
|
|
229
|
-
const enabledServers = Object.entries(servers).filter(([_, config]) => config.enabled);
|
|
230
|
-
if (enabledServers.length === 0) {
|
|
231
|
-
console.log('📭 No enabled MCP servers to test');
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
const { serverToTest } = await inquirer.prompt([
|
|
235
|
-
{
|
|
236
|
-
type: 'list',
|
|
237
|
-
name: 'serverToTest',
|
|
238
|
-
message: 'Select server to test:',
|
|
239
|
-
choices: enabledServers.map(([name, config]) => ({
|
|
240
|
-
name: `${name} - ${config.description}`,
|
|
241
|
-
value: name
|
|
242
|
-
}))
|
|
243
|
-
}
|
|
244
|
-
]);
|
|
245
|
-
console.log(`🧪 Testing connection to ${serverToTest}...`);
|
|
246
|
-
const connection = await mcpManager.connectToServer(serverToTest);
|
|
247
|
-
if (connection) {
|
|
248
|
-
console.log(`✅ Successfully connected to ${serverToTest}!`);
|
|
249
|
-
console.log(`🛠️ Available tools: ${connection.capabilities.join(', ')}`);
|
|
250
|
-
// Clean up test connection
|
|
251
|
-
await mcpManager.disconnectServer(serverToTest);
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
console.log(`❌ Failed to connect to ${serverToTest}`);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
catch (error) {
|
|
258
|
-
console.error(`❌ Error testing MCP server: ${error.message}`);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Get the MCP manager instance (for use in main application)
|
|
263
|
-
*/
|
|
264
|
-
export function getMCPManager() {
|
|
265
|
-
return mcpManager;
|
|
266
|
-
}
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP (Model Context Protocol) Manager
|
|
3
|
-
* Handles connections to MCP servers and tool execution
|
|
4
|
-
*/
|
|
5
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
6
|
-
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
7
|
-
import { DEFAULT_MCP_CONFIG } from './mcp-types.js';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
import fs from 'fs/promises';
|
|
10
|
-
import { getConfigDirectory } from './manager.js';
|
|
11
|
-
export class MCPManager {
|
|
12
|
-
constructor(config) {
|
|
13
|
-
this.connections = new Map();
|
|
14
|
-
this.processes = new Map();
|
|
15
|
-
this.config = config || DEFAULT_MCP_CONFIG;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Load MCP configuration from file
|
|
19
|
-
*/
|
|
20
|
-
async loadConfig() {
|
|
21
|
-
try {
|
|
22
|
-
const configPath = path.join(getConfigDirectory(), 'mcp-config.json');
|
|
23
|
-
const configData = await fs.readFile(configPath, 'utf-8');
|
|
24
|
-
this.config = { ...DEFAULT_MCP_CONFIG, ...JSON.parse(configData) };
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
// If no config file exists, use defaults
|
|
28
|
-
console.log('📡 Using default MCP configuration');
|
|
29
|
-
this.config = DEFAULT_MCP_CONFIG;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Save MCP configuration to file
|
|
34
|
-
*/
|
|
35
|
-
async saveConfig() {
|
|
36
|
-
try {
|
|
37
|
-
const configPath = path.join(getConfigDirectory(), 'mcp-config.json');
|
|
38
|
-
await fs.writeFile(configPath, JSON.stringify(this.config, null, 2));
|
|
39
|
-
}
|
|
40
|
-
catch (error) {
|
|
41
|
-
console.error('❌ Failed to save MCP configuration:', error);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Connect to a specific MCP server
|
|
46
|
-
*/
|
|
47
|
-
async connectToServer(serverName) {
|
|
48
|
-
const serverConfig = this.config.servers[serverName];
|
|
49
|
-
if (!serverConfig || !serverConfig.enabled) {
|
|
50
|
-
console.log(`⚠️ Server ${serverName} is not configured or disabled`);
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
try {
|
|
54
|
-
console.log(`🔌 Connecting to MCP server: ${serverName}`);
|
|
55
|
-
// Create transport for stdio communication
|
|
56
|
-
const transport = new StdioClientTransport({
|
|
57
|
-
command: serverConfig.command,
|
|
58
|
-
args: serverConfig.args || [],
|
|
59
|
-
env: {
|
|
60
|
-
...Object.fromEntries(Object.entries(process.env).filter(([_, v]) => v !== undefined)),
|
|
61
|
-
...serverConfig.env
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
// Create MCP client
|
|
65
|
-
const client = new Client({
|
|
66
|
-
name: 'protoagent',
|
|
67
|
-
version: '1.0.0'
|
|
68
|
-
}, {
|
|
69
|
-
capabilities: {
|
|
70
|
-
tools: {}
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
// Connect to the server
|
|
74
|
-
await client.connect(transport);
|
|
75
|
-
// Get server capabilities
|
|
76
|
-
const serverCapabilities = await client.listTools();
|
|
77
|
-
const capabilities = serverCapabilities.tools.map(tool => tool.name);
|
|
78
|
-
const connection = {
|
|
79
|
-
name: serverName,
|
|
80
|
-
client,
|
|
81
|
-
capabilities,
|
|
82
|
-
connected: true
|
|
83
|
-
};
|
|
84
|
-
this.connections.set(serverName, connection);
|
|
85
|
-
console.log(`✅ Connected to ${serverName} with ${capabilities.length} tools`);
|
|
86
|
-
return connection;
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
console.error(`❌ Failed to connect to MCP server ${serverName}:`, error);
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Connect to all enabled MCP servers
|
|
95
|
-
*/
|
|
96
|
-
async connectToAllServers() {
|
|
97
|
-
console.log('🚀 Initializing MCP connections...');
|
|
98
|
-
const enabledServers = Object.keys(this.config.servers).filter(name => this.config.servers[name].enabled);
|
|
99
|
-
if (enabledServers.length === 0) {
|
|
100
|
-
console.log('ℹ️ No MCP servers enabled');
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
const connectionPromises = enabledServers.map(serverName => this.connectToServer(serverName).catch(error => {
|
|
104
|
-
console.error(`Failed to connect to ${serverName}:`, error);
|
|
105
|
-
return null;
|
|
106
|
-
}));
|
|
107
|
-
const results = await Promise.all(connectionPromises);
|
|
108
|
-
const successfulConnections = results.filter(conn => conn !== null);
|
|
109
|
-
console.log(`📡 MCP Status: ${successfulConnections.length}/${enabledServers.length} servers connected`);
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Get all available tools from connected servers
|
|
113
|
-
*/
|
|
114
|
-
async getAllTools() {
|
|
115
|
-
const allTools = [];
|
|
116
|
-
for (const [serverName, connection] of this.connections) {
|
|
117
|
-
if (!connection.connected)
|
|
118
|
-
continue;
|
|
119
|
-
try {
|
|
120
|
-
const tools = await connection.client.listTools();
|
|
121
|
-
for (const tool of tools.tools) {
|
|
122
|
-
allTools.push({
|
|
123
|
-
server: serverName,
|
|
124
|
-
name: tool.name,
|
|
125
|
-
description: tool.description,
|
|
126
|
-
schema: tool.inputSchema
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
131
|
-
console.error(`❌ Failed to get tools from ${serverName}:`, error);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return allTools;
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Execute a tool on a specific MCP server
|
|
138
|
-
*/
|
|
139
|
-
async callTool(serverName, toolName, args) {
|
|
140
|
-
const connection = this.connections.get(serverName);
|
|
141
|
-
if (!connection || !connection.connected) {
|
|
142
|
-
throw new Error(`Server ${serverName} is not connected`);
|
|
143
|
-
}
|
|
144
|
-
try {
|
|
145
|
-
console.log(`🛠️ Calling ${serverName}:${toolName}`);
|
|
146
|
-
const result = await connection.client.callTool({
|
|
147
|
-
name: toolName,
|
|
148
|
-
arguments: args
|
|
149
|
-
});
|
|
150
|
-
return result;
|
|
151
|
-
}
|
|
152
|
-
catch (error) {
|
|
153
|
-
console.error(`❌ Tool execution failed ${serverName}:${toolName}:`, error);
|
|
154
|
-
throw error;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Find which server has a specific tool
|
|
159
|
-
*/
|
|
160
|
-
findToolServer(toolName) {
|
|
161
|
-
for (const [serverName, connection] of this.connections) {
|
|
162
|
-
if (connection.capabilities.includes(toolName)) {
|
|
163
|
-
return serverName;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Get connection status
|
|
170
|
-
*/
|
|
171
|
-
getConnectionStatus() {
|
|
172
|
-
const status = {};
|
|
173
|
-
for (const [serverName, connection] of this.connections) {
|
|
174
|
-
status[serverName] = connection.connected;
|
|
175
|
-
}
|
|
176
|
-
return status;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Add a custom MCP server configuration
|
|
180
|
-
*/
|
|
181
|
-
async addCustomServer(config) {
|
|
182
|
-
this.config.servers[config.name] = config;
|
|
183
|
-
await this.saveConfig();
|
|
184
|
-
console.log(`✅ Added custom MCP server: ${config.name}`);
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Remove a custom MCP server
|
|
188
|
-
*/
|
|
189
|
-
async removeCustomServer(serverName) {
|
|
190
|
-
const serverConfig = this.config.servers[serverName];
|
|
191
|
-
if (serverConfig?.isBuiltIn) {
|
|
192
|
-
throw new Error('Cannot remove built-in MCP servers');
|
|
193
|
-
}
|
|
194
|
-
// Disconnect if connected
|
|
195
|
-
const connection = this.connections.get(serverName);
|
|
196
|
-
if (connection) {
|
|
197
|
-
await this.disconnectServer(serverName);
|
|
198
|
-
}
|
|
199
|
-
delete this.config.servers[serverName];
|
|
200
|
-
await this.saveConfig();
|
|
201
|
-
console.log(`✅ Removed custom MCP server: ${serverName}`);
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Disconnect from a specific server
|
|
205
|
-
*/
|
|
206
|
-
async disconnectServer(serverName) {
|
|
207
|
-
const connection = this.connections.get(serverName);
|
|
208
|
-
if (connection) {
|
|
209
|
-
try {
|
|
210
|
-
await connection.client.close();
|
|
211
|
-
connection.connected = false;
|
|
212
|
-
this.connections.delete(serverName);
|
|
213
|
-
console.log(`🔌 Disconnected from ${serverName}`);
|
|
214
|
-
}
|
|
215
|
-
catch (error) {
|
|
216
|
-
console.error(`❌ Error disconnecting from ${serverName}:`, error);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Disconnect from all servers
|
|
222
|
-
*/
|
|
223
|
-
async disconnectAll() {
|
|
224
|
-
console.log('🔌 Disconnecting from all MCP servers...');
|
|
225
|
-
const disconnectPromises = Array.from(this.connections.keys()).map(serverName => this.disconnectServer(serverName));
|
|
226
|
-
await Promise.all(disconnectPromises);
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Get server configuration
|
|
230
|
-
*/
|
|
231
|
-
getServerConfig(serverName) {
|
|
232
|
-
return this.config.servers[serverName] || null;
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* List all configured servers
|
|
236
|
-
*/
|
|
237
|
-
listServers() {
|
|
238
|
-
return { ...this.config.servers };
|
|
239
|
-
}
|
|
240
|
-
}
|
package/dist/config/mcp-types.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP (Model Context Protocol) configuration types
|
|
3
|
-
*/
|
|
4
|
-
// Built-in server configurations
|
|
5
|
-
export const BUILTIN_MCP_SERVERS = {
|
|
6
|
-
filesystem: {
|
|
7
|
-
name: 'filesystem',
|
|
8
|
-
description: 'File system operations via MCP',
|
|
9
|
-
command: 'npx',
|
|
10
|
-
args: ['@modelcontextprotocol/server-filesystem'],
|
|
11
|
-
enabled: true,
|
|
12
|
-
isBuiltIn: true
|
|
13
|
-
},
|
|
14
|
-
'sequential-thinking': {
|
|
15
|
-
name: 'sequential-thinking',
|
|
16
|
-
description: 'Sequential thinking and reasoning tools',
|
|
17
|
-
command: 'npx',
|
|
18
|
-
args: ['@modelcontextprotocol/server-sequential-thinking'],
|
|
19
|
-
enabled: true,
|
|
20
|
-
isBuiltIn: true
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
export const DEFAULT_MCP_CONFIG = {
|
|
24
|
-
servers: { ...BUILTIN_MCP_SERVERS },
|
|
25
|
-
globalTimeout: 30000, // 30 seconds
|
|
26
|
-
maxConcurrentConnections: 5,
|
|
27
|
-
retryAttempts: 3
|
|
28
|
-
};
|