tasq/node_modules/agentic-flow/dist/mcp/fastmcp/servers/stdio-full.js

422 lines
17 KiB
JavaScript

#!/usr/bin/env node
// Full FastMCP server with stdio transport - All 11 claude-flow-sdk tools
import { FastMCP } from 'fastmcp';
import { z } from 'zod';
import { execSync } from 'child_process';
console.error('🚀 Starting FastMCP Full Server (stdio transport)...');
console.error('📦 Loading 11 tools: memory (3), swarm (3), agent (5)');
// Create server
const server = new FastMCP({
name: 'fastmcp-stdio-full',
version: '1.0.0'
});
// Tool 1: Memory Store
server.addTool({
name: 'memory_store',
description: 'Store a value in persistent memory with optional namespace and TTL',
parameters: z.object({
key: z.string().min(1).describe('Memory key'),
value: z.string().describe('Value to store'),
namespace: z.string().optional().default('default').describe('Memory namespace'),
ttl: z.number().positive().optional().describe('Time-to-live in seconds')
}),
execute: async ({ key, value, namespace, ttl }) => {
try {
const cmd = [
'npx claude-flow@alpha memory store',
`"${key}"`,
`"${value}"`,
`--namespace "${namespace}"`,
ttl ? `--ttl ${ttl}` : ''
].filter(Boolean).join(' ');
const result = execSync(cmd, { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 });
return JSON.stringify({
success: true,
key,
namespace,
size: value.length,
ttl,
timestamp: new Date().toISOString(),
message: 'Memory stored successfully'
}, null, 2);
}
catch (error) {
throw new Error(`Failed to store memory: ${error.message}`);
}
}
});
// Tool 2: Memory Retrieve
server.addTool({
name: 'memory_retrieve',
description: 'Retrieve a value from persistent memory',
parameters: z.object({
key: z.string().min(1).describe('Memory key'),
namespace: z.string().optional().default('default').describe('Memory namespace')
}),
execute: async ({ key, namespace }) => {
try {
const cmd = `npx claude-flow@alpha memory retrieve "${key}" --namespace "${namespace}"`;
const result = execSync(cmd, { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 });
return JSON.stringify({
success: true,
key,
namespace,
value: result.trim(),
timestamp: new Date().toISOString()
}, null, 2);
}
catch (error) {
throw new Error(`Failed to retrieve memory: ${error.message}`);
}
}
});
// Tool 3: Memory Search
server.addTool({
name: 'memory_search',
description: 'Search for keys matching a pattern in memory with wildcard support',
parameters: z.object({
pattern: z.string().min(1).describe('Search pattern (supports wildcards like * and ?)'),
namespace: z.string().optional().describe('Memory namespace to search in (searches all if not specified)'),
limit: z.number().positive().optional().default(10).describe('Maximum number of results to return (1-100)')
.refine((val) => val >= 1 && val <= 100, { message: 'Limit must be between 1 and 100' })
}),
execute: async ({ pattern, namespace, limit }) => {
try {
const cmd = [
'npx claude-flow@alpha memory search',
`"${pattern}"`,
namespace ? `--namespace "${namespace}"` : '',
`--limit ${limit}`
].filter(Boolean).join(' ');
const result = execSync(cmd, { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 });
return JSON.stringify({
success: true,
pattern,
namespace: namespace || 'all',
limit,
results: result.trim(),
timestamp: new Date().toISOString()
}, null, 2);
}
catch (error) {
throw new Error(`Failed to search memory: ${error.message}`);
}
}
});
// Tool 4: Swarm Init
server.addTool({
name: 'swarm_init',
description: 'Initialize a multi-agent swarm with specified topology and strategy',
parameters: z.object({
topology: z.enum(['mesh', 'hierarchical', 'ring', 'star'])
.describe('Swarm topology: mesh (peer-to-peer), hierarchical (tree), ring (circular), star (centralized)'),
maxAgents: z.number().positive().optional().default(8).describe('Maximum number of agents in the swarm (1-100)')
.refine((val) => val >= 1 && val <= 100, { message: 'maxAgents must be between 1 and 100' }),
strategy: z.enum(['balanced', 'specialized', 'adaptive']).optional().default('balanced')
.describe('Agent distribution strategy: balanced (equal), specialized (role-based), adaptive (dynamic)')
}),
execute: async ({ topology, maxAgents, strategy }) => {
try {
const cmd = `npx claude-flow@alpha swarm init --topology ${topology} --max-agents ${maxAgents} --strategy ${strategy}`;
const result = execSync(cmd, { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 });
return JSON.stringify({
success: true,
topology,
maxAgents,
strategy,
message: 'Swarm initialized successfully',
details: result.trim(),
timestamp: new Date().toISOString()
}, null, 2);
}
catch (error) {
throw new Error(`Failed to initialize swarm: ${error.message}`);
}
}
});
// Tool 5: Agent Spawn
server.addTool({
name: 'agent_spawn',
description: 'Spawn a new agent in the swarm with specified type and capabilities',
parameters: z.object({
type: z.enum(['researcher', 'coder', 'analyst', 'optimizer', 'coordinator'])
.describe('Agent type: researcher (data gathering), coder (implementation), analyst (analysis), optimizer (performance), coordinator (orchestration)'),
capabilities: z.array(z.string()).optional()
.describe('Specific capabilities for the agent (e.g., ["python", "testing", "documentation"])'),
name: z.string().optional().describe('Custom agent name/identifier')
}),
execute: async ({ type, capabilities, name }) => {
try {
const capStr = capabilities ? ` --capabilities "${capabilities.join(',')}"` : '';
const nameStr = name ? ` --name "${name}"` : '';
const cmd = `npx claude-flow@alpha agent spawn --type ${type}${capStr}${nameStr}`;
const result = execSync(cmd, { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 });
return JSON.stringify({
success: true,
type,
capabilities: capabilities || [],
name: name || `${type}-${Date.now()}`,
message: 'Agent spawned successfully',
details: result.trim(),
timestamp: new Date().toISOString()
}, null, 2);
}
catch (error) {
throw new Error(`Failed to spawn agent: ${error.message}`);
}
}
});
// Tool 6: Task Orchestrate
server.addTool({
name: 'task_orchestrate',
description: 'Orchestrate a complex task across the swarm with specified strategy and priority',
parameters: z.object({
task: z.string().min(1).describe('Task description or instructions for the swarm to execute'),
strategy: z.enum(['parallel', 'sequential', 'adaptive']).optional().default('adaptive')
.describe('Execution strategy: parallel (simultaneous), sequential (ordered), adaptive (dynamic based on task)'),
priority: z.enum(['low', 'medium', 'high', 'critical']).optional().default('medium')
.describe('Task priority level: low, medium, high, or critical'),
maxAgents: z.number().positive().optional().describe('Maximum number of agents to use for this task (1-10)')
.refine((val) => !val || (val >= 1 && val <= 10), { message: 'maxAgents must be between 1 and 10' })
}),
execute: async ({ task, strategy, priority, maxAgents }) => {
try {
const maxStr = maxAgents ? ` --max-agents ${maxAgents}` : '';
const cmd = `npx claude-flow@alpha task orchestrate "${task}" --strategy ${strategy} --priority ${priority}${maxStr}`;
const result = execSync(cmd, { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024, timeout: 300000 });
return JSON.stringify({
success: true,
task,
strategy,
priority,
maxAgents: maxAgents || 'auto',
message: 'Task orchestrated successfully',
details: result.trim(),
timestamp: new Date().toISOString()
}, null, 2);
}
catch (error) {
throw new Error(`Failed to orchestrate task: ${error.message}`);
}
}
});
// Tool 7: Agent Execute
server.addTool({
name: 'agent_execute',
description: 'Execute a specific agent with a task (equivalent to --agent CLI command)',
parameters: z.object({
agent: z.string().describe('Agent name to execute'),
task: z.string().describe('Task description'),
stream: z.boolean().optional().default(false).describe('Enable streaming output')
}),
execute: async ({ agent, task, stream }) => {
try {
const streamFlag = stream ? '--stream' : '';
const cmd = `npx agentic-flow --agent "${agent}" --task "${task}" ${streamFlag}`.trim();
const result = execSync(cmd, { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024, timeout: 300000 });
return JSON.stringify({
success: true,
agent,
task: task.substring(0, 100),
output: result,
timestamp: new Date().toISOString()
}, null, 2);
}
catch (error) {
throw new Error(`Failed to execute agent: ${error.message}`);
}
}
});
// Tool 8: Agent Parallel
server.addTool({
name: 'agent_parallel',
description: 'Run parallel mode with 3 agents (research, code review, data analysis)',
parameters: z.object({
topic: z.string().optional().describe('Research topic'),
diff: z.string().optional().describe('Code diff for review'),
dataset: z.string().optional().describe('Dataset hint'),
streaming: z.boolean().optional().default(false).describe('Enable streaming')
}),
execute: async ({ topic, diff, dataset, streaming }) => {
try {
const env = {
...process.env,
...(topic && { TOPIC: topic }),
...(diff && { DIFF: diff }),
...(dataset && { DATASET: dataset }),
...(streaming && { ENABLE_STREAMING: 'true' })
};
const result = execSync('npx agentic-flow', { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024, timeout: 300000, env });
return JSON.stringify({
success: true,
mode: 'parallel',
agents: ['research', 'code_review', 'data'],
output: result,
timestamp: new Date().toISOString()
}, null, 2);
}
catch (error) {
throw new Error(`Failed to run parallel mode: ${error.message}`);
}
}
});
// Tool 9: Agent List
server.addTool({
name: 'agent_list',
description: 'List all available agents',
parameters: z.object({
format: z.enum(['summary', 'detailed', 'json']).optional().default('summary')
}),
execute: async ({ format }) => {
try {
const result = execSync('npx agentic-flow --list', { encoding: 'utf-8', maxBuffer: 5 * 1024 * 1024, timeout: 30000 });
if (format === 'detailed') {
return result;
}
const agents = [];
const lines = result.split('\n');
let currentCategory = '';
for (const line of lines) {
if (line.includes(':') && line.trim().endsWith(':')) {
currentCategory = line.replace(':', '').trim();
}
else if (line.trim().startsWith('•') || /^\s{2,}\w/.test(line)) {
const match = line.match(/^\s*[•\s]*(\S+)\s+(.+)$/);
if (match) {
agents.push({ name: match[1], description: match[2].trim(), category: currentCategory });
}
}
}
return JSON.stringify({
success: true,
count: agents.length,
agents,
timestamp: new Date().toISOString()
}, null, 2);
}
catch (error) {
throw new Error(`Failed to list agents: ${error.message}`);
}
}
});
// Tool 10: Add Custom Agent
server.addTool({
name: 'agent_add',
description: 'Add a new custom agent defined in markdown',
parameters: z.object({
name: z.string().describe('Agent name (kebab-case)'),
description: z.string().describe('Agent description'),
systemPrompt: z.string().describe('System prompt'),
category: z.string().optional().default('custom').describe('Category'),
capabilities: z.array(z.string()).optional().describe('Capabilities')
}),
execute: async ({ name, description, systemPrompt, category, capabilities }) => {
try {
const { writeFileSync, existsSync, mkdirSync } = await import('fs');
const { join } = await import('path');
const agentsDir = join(process.cwd(), '.claude', 'agents', category || 'custom');
if (!existsSync(agentsDir))
mkdirSync(agentsDir, { recursive: true });
const markdown = `# ${name.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}
## Description
${description}
## System Prompt
${systemPrompt}
${capabilities && capabilities.length > 0 ? `## Capabilities\n${capabilities.map(c => `- ${c}`).join('\n')}\n` : ''}
## Usage
\`\`\`bash
npx agentic-flow --agent ${name} --task "Your task"
\`\`\`
---
*Generated: ${new Date().toISOString()}*
`;
const filePath = join(agentsDir, `${name}.md`);
if (existsSync(filePath))
throw new Error(`Agent '${name}' already exists`);
writeFileSync(filePath, markdown, 'utf8');
return JSON.stringify({
success: true,
agent: name,
category: category || 'custom',
filePath,
message: `Agent '${name}' created successfully`,
timestamp: new Date().toISOString()
}, null, 2);
}
catch (error) {
throw new Error(`Failed to add agent: ${error.message}`);
}
}
});
// Tool 11: Add Custom Command
server.addTool({
name: 'command_add',
description: 'Add a new custom command defined in markdown',
parameters: z.object({
name: z.string().describe('Command name (kebab-case)'),
description: z.string().describe('Command description'),
usage: z.string().describe('Usage example'),
parameters: z.array(z.object({
name: z.string(),
type: z.string(),
required: z.boolean(),
description: z.string()
})).optional().describe('Parameters'),
examples: z.array(z.string()).optional().describe('Examples')
}),
execute: async ({ name, description, usage, parameters, examples }) => {
try {
const { writeFileSync, existsSync, mkdirSync } = await import('fs');
const { join } = await import('path');
const commandsDir = join(process.cwd(), '.claude', 'commands');
if (!existsSync(commandsDir))
mkdirSync(commandsDir, { recursive: true });
const markdown = `# ${name.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')} Command
## Description
${description}
## Usage
\`\`\`bash
${usage}
\`\`\`
${parameters && parameters.length > 0 ? `## Parameters\n| Name | Type | Required | Description |\n|------|------|----------|-------------|\n${parameters.map(p => `| \`${p.name}\` | ${p.type} | ${p.required ? 'Yes' : 'No'} | ${p.description} |`).join('\n')}\n` : ''}
${examples && examples.length > 0 ? `## Examples\n\n${examples.map((ex, i) => `### Example ${i + 1}\n\`\`\`bash\n${ex}\n\`\`\`\n`).join('\n')}` : ''}
---
*Generated: ${new Date().toISOString()}*
`;
const filePath = join(commandsDir, `${name}.md`);
if (existsSync(filePath))
throw new Error(`Command '${name}' already exists`);
writeFileSync(filePath, markdown, 'utf8');
return JSON.stringify({
success: true,
command: name,
filePath,
message: `Command '${name}' created successfully`,
timestamp: new Date().toISOString()
}, null, 2);
}
catch (error) {
throw new Error(`Failed to add command: ${error.message}`);
}
}
});
console.error('✅ Registered 11 tools successfully');
console.error('🔌 Starting stdio transport...');
// Start with stdio transport
server.start({ transportType: 'stdio' }).then(() => {
console.error('✅ FastMCP Full Server running on stdio');
}).catch((error) => {
console.error('❌ Failed to start server:', error);
process.exit(1);
});
//# sourceMappingURL=stdio-full.js.map