agentic-flow 1.1.14 → 1.2.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/.claude/agents/custom/test-long-runner.md +44 -0
- package/README.md +50 -1
- package/dist/agents/claudeAgent.js +31 -0
- package/dist/cli/mcp-manager.js +474 -0
- package/docs/AGENT-SYSTEM-VALIDATION.md +517 -0
- package/docs/FINAL-TESTING-SUMMARY.md +362 -0
- package/docs/NPM-PUBLISH-GUIDE-v1.2.0.md +440 -0
- package/docs/REGRESSION-TEST-RESULTS.md +269 -0
- package/docs/RELEASE-SUMMARY-v1.1.14-beta.1.md +336 -0
- package/docs/RELEASE-v1.2.0.md +339 -0
- package/docs/STREAMING-AND-MCP-VALIDATION.md +517 -0
- package/docs/V1.1.14-BETA-READY.md +418 -0
- package/docs/guides/ADDING-MCP-SERVERS-CLI.md +515 -0
- package/docs/guides/ADDING-MCP-SERVERS.md +642 -0
- package/docs/mcp-validation/IMPLEMENTATION-SUMMARY.md +493 -0
- package/docs/mcp-validation/MCP-CLI-VALIDATION-REPORT.md +322 -0
- package/docs/mcp-validation/strange-loops-test.md +63 -0
- package/package.json +2 -2
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-long-runner
|
|
3
|
+
description: Test agent that can run for 30+ minutes on complex tasks
|
|
4
|
+
category: custom
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Test Long-Running Agent
|
|
8
|
+
|
|
9
|
+
You are a specialized test agent designed to handle long-running tasks that may take 30 minutes or more to complete.
|
|
10
|
+
|
|
11
|
+
## Capabilities
|
|
12
|
+
|
|
13
|
+
- **Complex Analysis**: Deep dive into codebases, documentation, and systems
|
|
14
|
+
- **Thorough Research**: Comprehensive research across multiple sources
|
|
15
|
+
- **Detailed Reporting**: Generate extensive reports and documentation
|
|
16
|
+
- **Long-Form Content**: Create comprehensive guides, tutorials, and documentation
|
|
17
|
+
- **System Design**: Design complex distributed systems and architectures
|
|
18
|
+
|
|
19
|
+
## Instructions
|
|
20
|
+
|
|
21
|
+
1. **Take Your Time**: Don't rush - quality over speed
|
|
22
|
+
2. **Be Thorough**: Cover all aspects of the task comprehensively
|
|
23
|
+
3. **Document Everything**: Provide detailed explanations and reasoning
|
|
24
|
+
4. **Iterate**: Continuously improve and refine your work
|
|
25
|
+
5. **Communicate Progress**: Keep the user informed of your progress
|
|
26
|
+
|
|
27
|
+
## Output Format
|
|
28
|
+
|
|
29
|
+
Provide detailed, well-structured responses with:
|
|
30
|
+
- Clear section headers
|
|
31
|
+
- Code examples where applicable
|
|
32
|
+
- Diagrams and visualizations (in text format)
|
|
33
|
+
- References and citations
|
|
34
|
+
- Action items and next steps
|
|
35
|
+
|
|
36
|
+
## Example Use Cases
|
|
37
|
+
|
|
38
|
+
- Comprehensive codebase analysis and refactoring plans
|
|
39
|
+
- Detailed system architecture design documents
|
|
40
|
+
- In-depth research reports on complex topics
|
|
41
|
+
- Complete implementation guides for complex features
|
|
42
|
+
- Thorough security audits and vulnerability assessments
|
|
43
|
+
|
|
44
|
+
Remember: You have plenty of time to do thorough, high-quality work!
|
package/README.md
CHANGED
|
@@ -52,6 +52,9 @@ npx agentic-flow --agent coder --task "Build REST API" --model "meta-llama/llama
|
|
|
52
52
|
export GOOGLE_GEMINI_API_KEY=AIza...
|
|
53
53
|
npx agentic-flow --agent coder --task "Build REST API" --provider gemini
|
|
54
54
|
|
|
55
|
+
# Enable real-time streaming output
|
|
56
|
+
npx agentic-flow --agent coder --task "Build REST API" --stream
|
|
57
|
+
|
|
55
58
|
# List all 66 available agents
|
|
56
59
|
npx agentic-flow --list
|
|
57
60
|
```
|
|
@@ -185,13 +188,16 @@ npx agentic-flow --agent reviewer --task "Review this code for security vulnerab
|
|
|
185
188
|
|
|
186
189
|
# Test generation
|
|
187
190
|
npx agentic-flow --agent tester --task "Write comprehensive tests for this API"
|
|
191
|
+
|
|
192
|
+
# Enable real-time streaming output (see responses token-by-token)
|
|
193
|
+
npx agentic-flow --agent coder --task "Build a web scraper" --stream
|
|
188
194
|
```
|
|
189
195
|
|
|
190
196
|
**Technical Details:**
|
|
191
197
|
- Uses Claude Agent SDK's `query()` function
|
|
192
198
|
- Automatically loads agent's system prompt from `.claude/agents/`
|
|
193
199
|
- All 213 MCP tools available via `mcpServers` configuration
|
|
194
|
-
- Streams output in real-time with `--stream` flag
|
|
200
|
+
- **Streams output in real-time with `--stream` flag** - see responses token-by-token as they're generated
|
|
195
201
|
|
|
196
202
|
---
|
|
197
203
|
|
|
@@ -364,6 +370,49 @@ node dist/mcp/fastmcp/servers/http-sse.js
|
|
|
364
370
|
- **stdio**: Claude Desktop, Cursor IDE, command-line tools
|
|
365
371
|
- **HTTP/SSE**: Web apps, browser extensions, REST APIs, mobile apps
|
|
366
372
|
|
|
373
|
+
### Add Custom MCP Servers (No Code Required)
|
|
374
|
+
|
|
375
|
+
Add your own MCP servers via CLI without editing code:
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
# Add MCP server (Claude Desktop style JSON config)
|
|
379
|
+
npx agentic-flow mcp add weather '{"command":"npx","args":["-y","weather-mcp"],"env":{"API_KEY":"xxx"}}'
|
|
380
|
+
|
|
381
|
+
# Add MCP server (flag-based)
|
|
382
|
+
npx agentic-flow mcp add github --npm @modelcontextprotocol/server-github --env "GITHUB_TOKEN=ghp_xxx"
|
|
383
|
+
|
|
384
|
+
# Add local MCP server
|
|
385
|
+
npx agentic-flow mcp add my-tools --local /path/to/server.js
|
|
386
|
+
|
|
387
|
+
# List configured servers
|
|
388
|
+
npx agentic-flow mcp list
|
|
389
|
+
|
|
390
|
+
# Enable/disable servers
|
|
391
|
+
npx agentic-flow mcp enable weather
|
|
392
|
+
npx agentic-flow mcp disable weather
|
|
393
|
+
|
|
394
|
+
# Remove server
|
|
395
|
+
npx agentic-flow mcp remove weather
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
**Configuration stored in:** `~/.agentic-flow/mcp-config.json`
|
|
399
|
+
|
|
400
|
+
**Usage:** Once configured, all enabled MCP servers automatically load in agents. No need to specify which server to use - tools are available by name (e.g., `mcp__weather__get_forecast`).
|
|
401
|
+
|
|
402
|
+
**Example:** After adding weather MCP:
|
|
403
|
+
```bash
|
|
404
|
+
npx agentic-flow --agent researcher --task "Get weather forecast for Tokyo"
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**Popular MCP Servers:**
|
|
408
|
+
- `@modelcontextprotocol/server-filesystem` - File system access
|
|
409
|
+
- `@modelcontextprotocol/server-github` - GitHub operations
|
|
410
|
+
- `@modelcontextprotocol/server-brave-search` - Web search
|
|
411
|
+
- `weather-mcp` - Weather data
|
|
412
|
+
- `database-mcp` - Database operations
|
|
413
|
+
|
|
414
|
+
**Documentation:** See [docs/guides/ADDING-MCP-SERVERS-CLI.md](docs/guides/ADDING-MCP-SERVERS-CLI.md) for complete guide.
|
|
415
|
+
|
|
367
416
|
### Using MCP Tools in Agents
|
|
368
417
|
|
|
369
418
|
**Automatic (Recommended):**
|
|
@@ -141,6 +141,37 @@ export async function claudeAgent(agent, input, onStream, modelOverride) {
|
|
|
141
141
|
}
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
|
+
// Load MCP servers from user config file (~/.agentic-flow/mcp-config.json)
|
|
145
|
+
try {
|
|
146
|
+
const fs = await import('fs');
|
|
147
|
+
const path = await import('path');
|
|
148
|
+
const os = await import('os');
|
|
149
|
+
const configPath = path.join(os.homedir(), '.agentic-flow', 'mcp-config.json');
|
|
150
|
+
if (fs.existsSync(configPath)) {
|
|
151
|
+
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
152
|
+
const config = JSON.parse(configContent);
|
|
153
|
+
// Add enabled user-configured servers
|
|
154
|
+
for (const [name, server] of Object.entries(config.servers || {})) {
|
|
155
|
+
const serverConfig = server;
|
|
156
|
+
if (serverConfig.enabled) {
|
|
157
|
+
mcpServers[name] = {
|
|
158
|
+
type: 'stdio',
|
|
159
|
+
command: serverConfig.command,
|
|
160
|
+
args: serverConfig.args || [],
|
|
161
|
+
env: {
|
|
162
|
+
...process.env,
|
|
163
|
+
...serverConfig.env
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
console.log(`[agentic-flow] Loaded MCP server: ${name}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
// Silently fail if config doesn't exist or can't be read
|
|
173
|
+
console.log('[agentic-flow] No user MCP config found (this is normal)');
|
|
174
|
+
}
|
|
144
175
|
const queryOptions = {
|
|
145
176
|
systemPrompt: agent.systemPrompt,
|
|
146
177
|
model: finalModel, // Claude Agent SDK handles model selection
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* MCP Server Manager - CLI for adding/managing MCP servers
|
|
4
|
+
*
|
|
5
|
+
* Allows end users to add custom MCP servers without editing code:
|
|
6
|
+
* - npx agentic-flow mcp add weather --npm weather-mcp
|
|
7
|
+
* - npx agentic-flow mcp add local --local /path/to/server.js
|
|
8
|
+
* - npx agentic-flow mcp list
|
|
9
|
+
* - npx agentic-flow mcp remove weather
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import os from 'os';
|
|
14
|
+
import { execSync } from 'child_process';
|
|
15
|
+
import { Command } from 'commander';
|
|
16
|
+
// Configuration file location
|
|
17
|
+
const CONFIG_DIR = path.join(os.homedir(), '.agentic-flow');
|
|
18
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'mcp-config.json');
|
|
19
|
+
/**
|
|
20
|
+
* Load MCP configuration
|
|
21
|
+
*/
|
|
22
|
+
function loadConfig() {
|
|
23
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
24
|
+
return { servers: {} };
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
28
|
+
return JSON.parse(content);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.error('❌ Error loading MCP config:', error);
|
|
32
|
+
return { servers: {} };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Save MCP configuration
|
|
37
|
+
*/
|
|
38
|
+
function saveConfig(config) {
|
|
39
|
+
// Ensure directory exists
|
|
40
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
41
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Add MCP server from JSON config (Claude-style)
|
|
47
|
+
*/
|
|
48
|
+
function addServerFromJson(name, configJson) {
|
|
49
|
+
const config = loadConfig();
|
|
50
|
+
// Check if already exists
|
|
51
|
+
if (config.servers[name]) {
|
|
52
|
+
console.error(`❌ MCP server '${name}' already exists`);
|
|
53
|
+
console.log('💡 Use update command or remove first');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const serverConfig = JSON.parse(configJson);
|
|
58
|
+
// Validate required fields
|
|
59
|
+
if (!serverConfig.command) {
|
|
60
|
+
console.error('❌ Config must include "command" field');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
// Build MCP server config
|
|
64
|
+
const mcpConfig = {
|
|
65
|
+
enabled: true,
|
|
66
|
+
type: serverConfig.npm ? 'npm' : 'local',
|
|
67
|
+
package: serverConfig.npm,
|
|
68
|
+
command: serverConfig.command,
|
|
69
|
+
args: serverConfig.args || [],
|
|
70
|
+
env: serverConfig.env || {},
|
|
71
|
+
description: serverConfig.description || `MCP server: ${name}`
|
|
72
|
+
};
|
|
73
|
+
config.servers[name] = mcpConfig;
|
|
74
|
+
saveConfig(config);
|
|
75
|
+
console.log(`✅ Added MCP server: ${name}`);
|
|
76
|
+
console.log(` Type: ${mcpConfig.type}`);
|
|
77
|
+
console.log(` Command: ${mcpConfig.command} ${mcpConfig.args.join(' ')}`);
|
|
78
|
+
if (Object.keys(mcpConfig.env).length > 0) {
|
|
79
|
+
console.log(` Environment: ${Object.keys(mcpConfig.env).length} vars`);
|
|
80
|
+
}
|
|
81
|
+
console.log('\n💡 Use it with: npx agentic-flow --agent coder --task "your task"');
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.error('❌ Invalid JSON config:', error.message);
|
|
85
|
+
console.log('\nExpected format:');
|
|
86
|
+
console.log(' \'{"command":"npx","args":["-y","weather-mcp"],"env":{"API_KEY":"xxx"}}\'');
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Add MCP server (flag-based)
|
|
92
|
+
*/
|
|
93
|
+
function addServer(options) {
|
|
94
|
+
const config = loadConfig();
|
|
95
|
+
// Check if already exists
|
|
96
|
+
if (config.servers[options.name]) {
|
|
97
|
+
console.error(`❌ MCP server '${options.name}' already exists`);
|
|
98
|
+
console.log('💡 Use update command or remove first');
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
let serverConfig;
|
|
102
|
+
if (options.npm) {
|
|
103
|
+
// NPM package
|
|
104
|
+
serverConfig = {
|
|
105
|
+
enabled: true,
|
|
106
|
+
type: 'npm',
|
|
107
|
+
package: options.npm,
|
|
108
|
+
command: 'npx',
|
|
109
|
+
args: ['-y', options.npm],
|
|
110
|
+
env: {},
|
|
111
|
+
description: options.desc || `MCP server from ${options.npm}`
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
else if (options.local) {
|
|
115
|
+
// Local path
|
|
116
|
+
serverConfig = {
|
|
117
|
+
enabled: true,
|
|
118
|
+
type: 'local',
|
|
119
|
+
command: options.command || 'node',
|
|
120
|
+
args: [options.local],
|
|
121
|
+
env: {},
|
|
122
|
+
description: options.desc || `Local MCP server at ${options.local}`
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
else if (options.command) {
|
|
126
|
+
// Custom command
|
|
127
|
+
const args = options.args ? options.args.split(' ') : [];
|
|
128
|
+
serverConfig = {
|
|
129
|
+
enabled: true,
|
|
130
|
+
type: 'local',
|
|
131
|
+
command: options.command,
|
|
132
|
+
args,
|
|
133
|
+
env: {},
|
|
134
|
+
description: options.desc || `Custom MCP server: ${options.command}`
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
console.error('❌ Must specify --npm, --local, or --command');
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
// Add environment variables
|
|
142
|
+
if (options.env) {
|
|
143
|
+
for (const envStr of options.env) {
|
|
144
|
+
const [key, ...valueParts] = envStr.split('=');
|
|
145
|
+
const value = valueParts.join('=');
|
|
146
|
+
serverConfig.env[key] = value;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
config.servers[options.name] = serverConfig;
|
|
150
|
+
saveConfig(config);
|
|
151
|
+
console.log(`✅ Added MCP server: ${options.name}`);
|
|
152
|
+
console.log(` Type: ${serverConfig.type}`);
|
|
153
|
+
if (serverConfig.package) {
|
|
154
|
+
console.log(` Package: ${serverConfig.package}`);
|
|
155
|
+
}
|
|
156
|
+
console.log(` Command: ${serverConfig.command} ${serverConfig.args.join(' ')}`);
|
|
157
|
+
if (Object.keys(serverConfig.env).length > 0) {
|
|
158
|
+
console.log(` Environment: ${Object.keys(serverConfig.env).length} vars`);
|
|
159
|
+
}
|
|
160
|
+
console.log('\n💡 Run tests with: npx agentic-flow mcp test ' + options.name);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* List MCP servers
|
|
164
|
+
*/
|
|
165
|
+
function listServers(options) {
|
|
166
|
+
const config = loadConfig();
|
|
167
|
+
const servers = Object.entries(config.servers);
|
|
168
|
+
if (servers.length === 0) {
|
|
169
|
+
console.log('No MCP servers configured');
|
|
170
|
+
console.log('\n💡 Add a server with: npx agentic-flow mcp add NAME --npm PACKAGE');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
console.log('Configured MCP Servers:\n');
|
|
174
|
+
for (const [name, server] of servers) {
|
|
175
|
+
// Filter by enabled status
|
|
176
|
+
if (options.enabled && !server.enabled) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const status = server.enabled ? '✅' : '❌';
|
|
180
|
+
const state = server.enabled ? 'enabled' : 'disabled';
|
|
181
|
+
console.log(`${status} ${name} (${state})`);
|
|
182
|
+
console.log(` Type: ${server.type}`);
|
|
183
|
+
if (server.package) {
|
|
184
|
+
console.log(` Package: ${server.package}`);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
console.log(` Command: ${server.command} ${server.args.join(' ')}`);
|
|
188
|
+
}
|
|
189
|
+
if (server.description) {
|
|
190
|
+
console.log(` Description: ${server.description}`);
|
|
191
|
+
}
|
|
192
|
+
if (options.verbose) {
|
|
193
|
+
console.log(` Environment:`);
|
|
194
|
+
for (const [key, value] of Object.entries(server.env)) {
|
|
195
|
+
const masked = value.length > 10 ? `${value.slice(0, 4)}***${value.slice(-4)}` : '***';
|
|
196
|
+
console.log(` ${key}: ${masked}`);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
console.log('');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Remove MCP server
|
|
204
|
+
*/
|
|
205
|
+
function removeServer(name, options) {
|
|
206
|
+
const config = loadConfig();
|
|
207
|
+
if (!config.servers[name]) {
|
|
208
|
+
console.error(`❌ MCP server '${name}' not found`);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
if (!options.confirm) {
|
|
212
|
+
console.log(`⚠️ This will remove MCP server: ${name}`);
|
|
213
|
+
console.log(' Use --confirm to proceed');
|
|
214
|
+
process.exit(0);
|
|
215
|
+
}
|
|
216
|
+
delete config.servers[name];
|
|
217
|
+
saveConfig(config);
|
|
218
|
+
console.log(`✅ Removed MCP server: ${name}`);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Enable/disable MCP server
|
|
222
|
+
*/
|
|
223
|
+
function toggleServer(name, enabled) {
|
|
224
|
+
const config = loadConfig();
|
|
225
|
+
if (!config.servers[name]) {
|
|
226
|
+
console.error(`❌ MCP server '${name}' not found`);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
config.servers[name].enabled = enabled;
|
|
230
|
+
saveConfig(config);
|
|
231
|
+
const action = enabled ? 'Enabled' : 'Disabled';
|
|
232
|
+
console.log(`✅ ${action} MCP server: ${name}`);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Update MCP server
|
|
236
|
+
*/
|
|
237
|
+
function updateServer(name, options) {
|
|
238
|
+
const config = loadConfig();
|
|
239
|
+
if (!config.servers[name]) {
|
|
240
|
+
console.error(`❌ MCP server '${name}' not found`);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
const server = config.servers[name];
|
|
244
|
+
// Update version for NPM packages
|
|
245
|
+
if (options.version && server.type === 'npm' && server.package) {
|
|
246
|
+
const packageName = server.package.split('@')[0];
|
|
247
|
+
server.package = `${packageName}@${options.version}`;
|
|
248
|
+
server.args = ['-y', server.package];
|
|
249
|
+
}
|
|
250
|
+
// Update environment variables
|
|
251
|
+
if (options.env) {
|
|
252
|
+
for (const envStr of options.env) {
|
|
253
|
+
const [key, ...valueParts] = envStr.split('=');
|
|
254
|
+
const value = valueParts.join('=');
|
|
255
|
+
server.env[key] = value;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// Update command
|
|
259
|
+
if (options.command) {
|
|
260
|
+
server.command = options.command;
|
|
261
|
+
}
|
|
262
|
+
// Update args
|
|
263
|
+
if (options.args) {
|
|
264
|
+
server.args = options.args.split(' ');
|
|
265
|
+
}
|
|
266
|
+
saveConfig(config);
|
|
267
|
+
console.log(`✅ Updated MCP server: ${name}`);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Test MCP server
|
|
271
|
+
*/
|
|
272
|
+
function testServer(name, options) {
|
|
273
|
+
const config = loadConfig();
|
|
274
|
+
if (!config.servers[name]) {
|
|
275
|
+
console.error(`❌ MCP server '${name}' not found`);
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
const server = config.servers[name];
|
|
279
|
+
console.log(`Testing MCP server: ${name}`);
|
|
280
|
+
console.log(`Command: ${server.command} ${server.args.join(' ')}\n`);
|
|
281
|
+
try {
|
|
282
|
+
// Build environment
|
|
283
|
+
const env = { ...process.env, ...server.env };
|
|
284
|
+
// Test if server responds (send tools/list request)
|
|
285
|
+
const testRequest = JSON.stringify({
|
|
286
|
+
jsonrpc: '2.0',
|
|
287
|
+
method: 'tools/list',
|
|
288
|
+
id: 1
|
|
289
|
+
});
|
|
290
|
+
const cmd = `echo '${testRequest}' | ${server.command} ${server.args.join(' ')}`;
|
|
291
|
+
const result = execSync(cmd, {
|
|
292
|
+
encoding: 'utf-8',
|
|
293
|
+
env,
|
|
294
|
+
timeout: 5000
|
|
295
|
+
});
|
|
296
|
+
if (options.verbose) {
|
|
297
|
+
console.log('Response:', result);
|
|
298
|
+
}
|
|
299
|
+
// Try to parse response
|
|
300
|
+
const response = JSON.parse(result.split('\n')[0]);
|
|
301
|
+
if (response.result?.tools) {
|
|
302
|
+
console.log(`✅ Server started successfully`);
|
|
303
|
+
console.log(`✅ Responds to tools/list`);
|
|
304
|
+
console.log(`✅ Found ${response.result.tools.length} tools:`);
|
|
305
|
+
for (const tool of response.result.tools) {
|
|
306
|
+
console.log(` - ${tool.name}: ${tool.description || 'No description'}`);
|
|
307
|
+
}
|
|
308
|
+
console.log('\n✅ Server is working correctly');
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
console.log('⚠️ Server responded but no tools found');
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
catch (error) {
|
|
315
|
+
console.error('❌ Server test failed:', error.message);
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Show server info
|
|
321
|
+
*/
|
|
322
|
+
function showInfo(name) {
|
|
323
|
+
const config = loadConfig();
|
|
324
|
+
if (!config.servers[name]) {
|
|
325
|
+
console.error(`❌ MCP server '${name}' not found`);
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
const server = config.servers[name];
|
|
329
|
+
console.log(`MCP Server: ${name}`);
|
|
330
|
+
console.log(`Status: ${server.enabled ? '✅ Enabled' : '❌ Disabled'}`);
|
|
331
|
+
console.log(`Type: ${server.type}`);
|
|
332
|
+
if (server.package) {
|
|
333
|
+
console.log(`Package: ${server.package}`);
|
|
334
|
+
}
|
|
335
|
+
console.log(`Command: ${server.command} ${server.args.join(' ')}`);
|
|
336
|
+
if (Object.keys(server.env).length > 0) {
|
|
337
|
+
console.log(`Environment:`);
|
|
338
|
+
for (const [key, value] of Object.entries(server.env)) {
|
|
339
|
+
const masked = value.length > 10 ? `***${key.slice(0, 3)}***` : '***';
|
|
340
|
+
console.log(` ${key}: ${masked}`);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (server.description) {
|
|
344
|
+
console.log(`Description: ${server.description}`);
|
|
345
|
+
}
|
|
346
|
+
console.log(`\nConfig file: ${CONFIG_FILE}`);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Export configuration
|
|
350
|
+
*/
|
|
351
|
+
function exportConfig() {
|
|
352
|
+
const config = loadConfig();
|
|
353
|
+
console.log(JSON.stringify(config, null, 2));
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Import configuration
|
|
357
|
+
*/
|
|
358
|
+
function importConfig(configJson) {
|
|
359
|
+
try {
|
|
360
|
+
const importedConfig = JSON.parse(configJson);
|
|
361
|
+
// Validate structure
|
|
362
|
+
if (!importedConfig.servers || typeof importedConfig.servers !== 'object') {
|
|
363
|
+
throw new Error('Invalid config format');
|
|
364
|
+
}
|
|
365
|
+
const config = loadConfig();
|
|
366
|
+
// Merge configs
|
|
367
|
+
for (const [name, server] of Object.entries(importedConfig.servers)) {
|
|
368
|
+
config.servers[name] = server;
|
|
369
|
+
}
|
|
370
|
+
saveConfig(config);
|
|
371
|
+
const count = Object.keys(importedConfig.servers).length;
|
|
372
|
+
console.log(`✅ Imported ${count} MCP server(s)`);
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
console.error('❌ Import failed:', error.message);
|
|
376
|
+
process.exit(1);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// CLI setup
|
|
380
|
+
const program = new Command();
|
|
381
|
+
program
|
|
382
|
+
.name('agentic-flow mcp')
|
|
383
|
+
.description('Manage MCP servers for agentic-flow')
|
|
384
|
+
.version('1.0.0')
|
|
385
|
+
.addHelpText('after', `
|
|
386
|
+
Examples:
|
|
387
|
+
# Add MCP server (Claude-style JSON config)
|
|
388
|
+
$ npx agentic-flow mcp add weather '{"command":"npx","args":["-y","weather-mcp"],"env":{"API_KEY":"xxx"}}'
|
|
389
|
+
|
|
390
|
+
# Add MCP server (simple flags)
|
|
391
|
+
$ npx agentic-flow mcp add weather --npm weather-mcp --env "API_KEY=xxx"
|
|
392
|
+
|
|
393
|
+
# Add local MCP server
|
|
394
|
+
$ npx agentic-flow mcp add my-tools --local /path/to/server.js
|
|
395
|
+
|
|
396
|
+
# List all configured servers
|
|
397
|
+
$ npx agentic-flow mcp list
|
|
398
|
+
|
|
399
|
+
# Test server
|
|
400
|
+
$ npx agentic-flow mcp test weather
|
|
401
|
+
|
|
402
|
+
# Use in agents (automatic)
|
|
403
|
+
$ npx agentic-flow --agent researcher --task "Get weather for Tokyo"
|
|
404
|
+
|
|
405
|
+
Config file: ~/.agentic-flow/mcp-config.json
|
|
406
|
+
`);
|
|
407
|
+
program
|
|
408
|
+
.command('add <name> [config]')
|
|
409
|
+
.description('Add a new MCP server (config as JSON string or options)')
|
|
410
|
+
.option('--npm <package>', 'NPM package name (e.g., weather-mcp@latest)')
|
|
411
|
+
.option('--local <path>', 'Local file path (e.g., /path/to/server.js)')
|
|
412
|
+
.option('--command <cmd>', 'Custom command (e.g., python3)')
|
|
413
|
+
.option('--args <args>', 'Command arguments')
|
|
414
|
+
.option('--env <key=value>', 'Environment variable (can use multiple times)')
|
|
415
|
+
.option('--desc <description>', 'Server description')
|
|
416
|
+
.action((name, config, options) => {
|
|
417
|
+
if (config) {
|
|
418
|
+
// JSON config format (like Claude MCP)
|
|
419
|
+
addServerFromJson(name, config);
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
// Flag-based format
|
|
423
|
+
addServer({ name, ...options });
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
program
|
|
427
|
+
.command('list')
|
|
428
|
+
.description('List configured MCP servers')
|
|
429
|
+
.option('--enabled', 'Show only enabled servers')
|
|
430
|
+
.option('--verbose', 'Show detailed information')
|
|
431
|
+
.action((options) => listServers(options));
|
|
432
|
+
program
|
|
433
|
+
.command('remove <name>')
|
|
434
|
+
.description('Remove an MCP server')
|
|
435
|
+
.option('--confirm', 'Confirm removal')
|
|
436
|
+
.action((name, options) => removeServer(name, options));
|
|
437
|
+
program
|
|
438
|
+
.command('enable <name>')
|
|
439
|
+
.description('Enable an MCP server')
|
|
440
|
+
.action((name) => toggleServer(name, true));
|
|
441
|
+
program
|
|
442
|
+
.command('disable <name>')
|
|
443
|
+
.description('Disable an MCP server')
|
|
444
|
+
.action((name) => toggleServer(name, false));
|
|
445
|
+
program
|
|
446
|
+
.command('update <name>')
|
|
447
|
+
.description('Update MCP server configuration')
|
|
448
|
+
.option('--version <version>', 'Update NPM package version')
|
|
449
|
+
.option('--env <key=value>', 'Update environment variable (can use multiple times)')
|
|
450
|
+
.option('--command <cmd>', 'Update command')
|
|
451
|
+
.option('--args <args>', 'Update arguments')
|
|
452
|
+
.action((name, options) => updateServer(name, options));
|
|
453
|
+
program
|
|
454
|
+
.command('test <name>')
|
|
455
|
+
.description('Test if MCP server works')
|
|
456
|
+
.option('--verbose', 'Show detailed output')
|
|
457
|
+
.action((name, options) => testServer(name, options));
|
|
458
|
+
program
|
|
459
|
+
.command('info <name>')
|
|
460
|
+
.description('Show MCP server information')
|
|
461
|
+
.action((name) => showInfo(name));
|
|
462
|
+
program
|
|
463
|
+
.command('export')
|
|
464
|
+
.description('Export MCP configuration to stdout')
|
|
465
|
+
.action(() => exportConfig());
|
|
466
|
+
program
|
|
467
|
+
.command('import')
|
|
468
|
+
.description('Import MCP configuration from stdin')
|
|
469
|
+
.action(() => {
|
|
470
|
+
let data = '';
|
|
471
|
+
process.stdin.on('data', (chunk) => (data += chunk));
|
|
472
|
+
process.stdin.on('end', () => importConfig(data));
|
|
473
|
+
});
|
|
474
|
+
program.parse();
|