jay-code
Version:
Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability
1,324 lines (1,189 loc) • 37.1 kB
text/typescript
/**
* Jay-Code specific MCP tools
*/
import type { MCPTool, MCPContext, AgentProfile, Task, MemoryEntry } from '../utils/types.js';
import type { ILogger } from '../core/logger.js';
import { getAvailableAgentTypes, getAgentTypeSchema } from '../constants/agent-types.js';
import type { Permissions } from './auth.js';
export interface ClaudeFlowToolContext extends MCPContext {
orchestrator?: any; // Reference to orchestrator instance
}
/**
* Enhance tool schema with dynamic agent types
*/
async function enhanceToolWithAgentTypes(tool: MCPTool): Promise<MCPTool> {
const availableTypes = await getAvailableAgentTypes();
// Clone the tool to avoid modifying the original
const enhancedTool = JSON.parse(JSON.stringify(tool));
// Find and populate enum fields for agent types
function addEnumToAgentTypeFields(obj: any) {
if (typeof obj !== 'object' || obj === null) return;
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'object' && value !== null) {
// Check if this is an agent type field
if (key === 'type' || key === 'filterByType' || key === 'assignToAgentType') {
const field = value as any;
if (field.type === 'string' && field.description?.includes('loaded dynamically from .claude/agents/')) {
field.enum = availableTypes;
}
}
addEnumToAgentTypeFields(value);
}
}
}
addEnumToAgentTypeFields(enhancedTool.inputSchema);
return enhancedTool;
}
/**
* Create all Jay-Code specific MCP tools
*/
export async function createClaudeFlowTools(logger: ILogger): Promise<MCPTool[]> {
const tools = [
// Agent management tools
createSpawnAgentTool(logger),
createListAgentsTool(logger),
createTerminateAgentTool(logger),
createGetAgentInfoTool(logger),
// Task management tools
createCreateTaskTool(logger),
createListTasksTool(logger),
createGetTaskStatusTool(logger),
createCancelTaskTool(logger),
createAssignTaskTool(logger),
// Memory management tools
createQueryMemoryTool(logger),
createStoreMemoryTool(logger),
createDeleteMemoryTool(logger),
createExportMemoryTool(logger),
createImportMemoryTool(logger),
// System monitoring tools
createGetSystemStatusTool(logger),
createGetMetricsTool(logger),
createHealthCheckTool(logger),
// Configuration tools
createGetConfigTool(logger),
createUpdateConfigTool(logger),
createValidateConfigTool(logger),
// Workflow tools
createExecuteWorkflowTool(logger),
createCreateWorkflowTool(logger),
createListWorkflowsTool(logger),
// Terminal management tools
createExecuteCommandTool(logger),
createListTerminalsTool(logger),
createCreateTerminalTool(logger),
];
// Enhance tools with dynamic agent types
const enhancedTools = await Promise.all(
tools.map(tool => enhanceToolWithAgentTypes(tool))
);
return enhancedTools;
}
function createSpawnAgentTool(logger: ILogger): MCPTool {
return {
name: 'agents/spawn',
description: 'Spawn a new Claude agent with specified configuration',
inputSchema: {
type: 'object',
properties: {
type: {
type: 'string',
// Note: enum will be populated dynamically at runtime
description: 'Type of specialized agent to spawn (loaded dynamically from .claude/agents/)',
},
name: {
type: 'string',
description: 'Display name for the agent',
},
capabilities: {
type: 'array',
items: { type: 'string' },
description: 'List of capabilities for the agent',
},
systemPrompt: {
type: 'string',
description: 'Custom system prompt for the agent',
},
maxConcurrentTasks: {
type: 'number',
default: 3,
description: 'Maximum number of concurrent tasks',
},
priority: {
type: 'number',
default: 5,
description: 'Agent priority level (1-10)',
},
environment: {
type: 'object',
description: 'Environment variables for the agent',
},
workingDirectory: {
type: 'string',
description: 'Working directory for the agent',
},
},
required: ['type', 'name'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Spawning agent', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const profile: AgentProfile = {
id: `agent_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
name: input.name,
type: input.type,
capabilities: input.capabilities || [],
systemPrompt: input.systemPrompt || getDefaultSystemPrompt(input.type),
maxConcurrentTasks: input.maxConcurrentTasks || 3,
priority: input.priority || 5,
environment: input.environment,
workingDirectory: input.workingDirectory,
};
const sessionId = await context.orchestrator.spawnAgent(profile);
return {
agentId: profile.id,
sessionId,
profile,
status: 'spawned',
timestamp: new Date().toISOString(),
};
},
};
}
function createListAgentsTool(logger: ILogger): MCPTool {
return {
name: 'agents/list',
description: 'List all active agents in the system',
inputSchema: {
type: 'object',
properties: {
includeTerminated: {
type: 'boolean',
default: false,
description: 'Include terminated agents in the list',
},
filterByType: {
type: 'string',
// Note: enum will be populated dynamically at runtime
description: 'Filter agents by type (loaded dynamically from .claude/agents/)',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Listing agents', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const agents = await context.orchestrator.listAgents();
let filteredAgents = agents;
if (!input.includeTerminated) {
filteredAgents = filteredAgents.filter((agent: any) => agent.status !== 'terminated');
}
if (input.filterByType) {
filteredAgents = filteredAgents.filter((agent: any) => agent.type === input.filterByType);
}
return {
agents: filteredAgents,
count: filteredAgents.length,
timestamp: new Date().toISOString(),
};
},
};
}
function createTerminateAgentTool(logger: ILogger): MCPTool {
return {
name: 'agents/terminate',
description: 'Terminate a specific agent',
inputSchema: {
type: 'object',
properties: {
agentId: {
type: 'string',
description: 'ID of the agent to terminate',
},
reason: {
type: 'string',
description: 'Reason for termination',
},
graceful: {
type: 'boolean',
default: true,
description: 'Whether to perform graceful shutdown',
},
},
required: ['agentId'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Terminating agent', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
await context.orchestrator.terminateAgent(input.agentId, {
reason: input.reason || 'Manual termination',
graceful: input.graceful !== false,
});
return {
agentId: input.agentId,
status: 'terminated',
reason: input.reason || 'Manual termination',
timestamp: new Date().toISOString(),
};
},
};
}
function createGetAgentInfoTool(logger: ILogger): MCPTool {
return {
name: 'agents/info',
description: 'Get detailed information about a specific agent',
inputSchema: {
type: 'object',
properties: {
agentId: {
type: 'string',
description: 'ID of the agent',
},
},
required: ['agentId'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Getting agent info', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const agentInfo = await context.orchestrator.getAgentInfo(input.agentId);
if (!agentInfo) {
throw new Error(`Agent not found: ${input.agentId}`);
}
return {
agent: agentInfo,
timestamp: new Date().toISOString(),
};
},
};
}
function createCreateTaskTool(logger: ILogger): MCPTool {
return {
name: 'tasks/create',
description: 'Create a new task for execution',
inputSchema: {
type: 'object',
properties: {
type: {
type: 'string',
description: 'Type of task to create',
},
description: {
type: 'string',
description: 'Description of the task',
},
priority: {
type: 'number',
default: 5,
description: 'Task priority (1-10)',
},
dependencies: {
type: 'array',
items: { type: 'string' },
description: 'List of task IDs this task depends on',
},
assignToAgent: {
type: 'string',
description: 'Specific agent ID to assign the task to',
},
assignToAgentType: {
type: 'string',
// Note: enum will be populated dynamically at runtime
description: 'Type of specialized agent to assign the task to (loaded dynamically from .claude/agents/)',
},
input: {
type: 'object',
description: 'Input data for the task',
},
timeout: {
type: 'number',
description: 'Task timeout in milliseconds',
},
},
required: ['type', 'description'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Creating task', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const task: Partial<Task> = {
type: input.type,
description: input.description,
priority: input.priority || 5,
dependencies: input.dependencies || [],
input: input.input || {},
status: 'pending',
createdAt: new Date(),
};
const taskId = await context.orchestrator.createTask(task);
// Handle assignment
if (input.assignToAgent) {
await context.orchestrator.assignTask(taskId, input.assignToAgent);
} else if (input.assignToAgentType) {
await context.orchestrator.assignTaskToType(taskId, input.assignToAgentType);
}
return {
taskId,
task: { ...task, id: taskId },
timestamp: new Date().toISOString(),
};
},
};
}
function createListTasksTool(logger: ILogger): MCPTool {
return {
name: 'tasks/list',
description: 'List tasks with optional filtering',
inputSchema: {
type: 'object',
properties: {
status: {
type: 'string',
enum: ['pending', 'queued', 'assigned', 'running', 'completed', 'failed', 'cancelled'],
description: 'Filter by task status',
},
agentId: {
type: 'string',
description: 'Filter by assigned agent ID',
},
type: {
type: 'string',
description: 'Filter by task type',
},
limit: {
type: 'number',
default: 50,
description: 'Maximum number of tasks to return',
},
offset: {
type: 'number',
default: 0,
description: 'Number of tasks to skip',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Listing tasks', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const tasks = await context.orchestrator.listTasks({
status: input.status,
agentId: input.agentId,
type: input.type,
limit: input.limit || 50,
offset: input.offset || 0,
});
return {
tasks,
count: tasks.length,
timestamp: new Date().toISOString(),
};
},
};
}
function createGetTaskStatusTool(logger: ILogger): MCPTool {
return {
name: 'tasks/status',
description: 'Get detailed status of a specific task',
inputSchema: {
type: 'object',
properties: {
taskId: {
type: 'string',
description: 'ID of the task',
},
},
required: ['taskId'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Getting task status', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const task = await context.orchestrator.getTask(input.taskId);
if (!task) {
throw new Error(`Task not found: ${input.taskId}`);
}
return {
task,
timestamp: new Date().toISOString(),
};
},
};
}
function createCancelTaskTool(logger: ILogger): MCPTool {
return {
name: 'tasks/cancel',
description: 'Cancel a pending or running task',
inputSchema: {
type: 'object',
properties: {
taskId: {
type: 'string',
description: 'ID of the task to cancel',
},
reason: {
type: 'string',
description: 'Reason for cancellation',
},
},
required: ['taskId'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Cancelling task', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
await context.orchestrator.cancelTask(input.taskId, input.reason || 'Manual cancellation');
return {
taskId: input.taskId,
status: 'cancelled',
reason: input.reason || 'Manual cancellation',
timestamp: new Date().toISOString(),
};
},
};
}
function createAssignTaskTool(logger: ILogger): MCPTool {
return {
name: 'tasks/assign',
description: 'Assign a task to a specific agent',
inputSchema: {
type: 'object',
properties: {
taskId: {
type: 'string',
description: 'ID of the task to assign',
},
agentId: {
type: 'string',
description: 'ID of the agent to assign the task to',
},
},
required: ['taskId', 'agentId'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Assigning task', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
await context.orchestrator.assignTask(input.taskId, input.agentId);
return {
taskId: input.taskId,
agentId: input.agentId,
status: 'assigned',
timestamp: new Date().toISOString(),
};
},
};
}
function createQueryMemoryTool(logger: ILogger): MCPTool {
return {
name: 'memory/query',
description: 'Query agent memory with filters and search',
inputSchema: {
type: 'object',
properties: {
agentId: {
type: 'string',
description: 'Filter by agent ID',
},
sessionId: {
type: 'string',
description: 'Filter by session ID',
},
type: {
type: 'string',
enum: ['observation', 'insight', 'decision', 'artifact', 'error'],
description: 'Filter by entry type',
},
tags: {
type: 'array',
items: { type: 'string' },
description: 'Filter by tags',
},
search: {
type: 'string',
description: 'Full-text search query',
},
startTime: {
type: 'string',
format: 'date-time',
description: 'Filter entries after this time',
},
endTime: {
type: 'string',
format: 'date-time',
description: 'Filter entries before this time',
},
limit: {
type: 'number',
default: 50,
description: 'Maximum number of entries to return',
},
offset: {
type: 'number',
default: 0,
description: 'Number of entries to skip',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Querying memory', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const query = {
agentId: input.agentId,
sessionId: input.sessionId,
type: input.type,
tags: input.tags,
search: input.search,
startTime: input.startTime ? new Date(input.startTime) : undefined,
endTime: input.endTime ? new Date(input.endTime) : undefined,
limit: input.limit || 50,
offset: input.offset || 0,
};
const entries = await context.orchestrator.queryMemory(query);
return {
entries,
count: entries.length,
query,
timestamp: new Date().toISOString(),
};
},
};
}
function createStoreMemoryTool(logger: ILogger): MCPTool {
return {
name: 'memory/store',
description: 'Store a new memory entry',
inputSchema: {
type: 'object',
properties: {
agentId: {
type: 'string',
description: 'Agent ID for the memory entry',
},
sessionId: {
type: 'string',
description: 'Session ID for the memory entry',
},
type: {
type: 'string',
enum: ['observation', 'insight', 'decision', 'artifact', 'error'],
description: 'Type of memory entry',
},
content: {
type: 'string',
description: 'Content of the memory entry',
},
context: {
type: 'object',
description: 'Context data for the memory entry',
},
tags: {
type: 'array',
items: { type: 'string' },
description: 'Tags for the memory entry',
},
parentId: {
type: 'string',
description: 'Parent memory entry ID',
},
},
required: ['agentId', 'sessionId', 'type', 'content'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Storing memory', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const entry: Partial<MemoryEntry> = {
agentId: input.agentId,
sessionId: input.sessionId,
type: input.type,
content: input.content,
context: input.context || {},
tags: input.tags || [],
parentId: input.parentId,
timestamp: new Date(),
version: 1,
};
const entryId = await context.orchestrator.storeMemory(entry);
return {
entryId,
entry: { ...entry, id: entryId },
timestamp: new Date().toISOString(),
};
},
};
}
function createDeleteMemoryTool(logger: ILogger): MCPTool {
return {
name: 'memory/delete',
description: 'Delete a memory entry',
inputSchema: {
type: 'object',
properties: {
entryId: {
type: 'string',
description: 'ID of the memory entry to delete',
},
},
required: ['entryId'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Deleting memory', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
await context.orchestrator.deleteMemory(input.entryId);
return {
entryId: input.entryId,
status: 'deleted',
timestamp: new Date().toISOString(),
};
},
};
}
function createExportMemoryTool(logger: ILogger): MCPTool {
return {
name: 'memory/export',
description: 'Export memory entries to a file',
inputSchema: {
type: 'object',
properties: {
format: {
type: 'string',
enum: ['json', 'csv', 'markdown'],
default: 'json',
description: 'Export format',
},
agentId: {
type: 'string',
description: 'Filter by agent ID',
},
sessionId: {
type: 'string',
description: 'Filter by session ID',
},
startTime: {
type: 'string',
format: 'date-time',
description: 'Export entries after this time',
},
endTime: {
type: 'string',
format: 'date-time',
description: 'Export entries before this time',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Exporting memory', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const exportResult = await context.orchestrator.exportMemory({
format: input.format || 'json',
agentId: input.agentId,
sessionId: input.sessionId,
startTime: input.startTime ? new Date(input.startTime) : undefined,
endTime: input.endTime ? new Date(input.endTime) : undefined,
});
return {
...exportResult,
timestamp: new Date().toISOString(),
};
},
};
}
function createImportMemoryTool(logger: ILogger): MCPTool {
return {
name: 'memory/import',
description: 'Import memory entries from a file',
inputSchema: {
type: 'object',
properties: {
filePath: {
type: 'string',
description: 'Path to the file to import',
},
format: {
type: 'string',
enum: ['json', 'csv'],
default: 'json',
description: 'Import format',
},
mergeStrategy: {
type: 'string',
enum: ['skip', 'overwrite', 'version'],
default: 'skip',
description: 'Strategy for handling duplicate entries',
},
},
required: ['filePath'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Importing memory', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const importResult = await context.orchestrator.importMemory({
filePath: input.filePath,
format: input.format || 'json',
mergeStrategy: input.mergeStrategy || 'skip',
});
return {
...importResult,
timestamp: new Date().toISOString(),
};
},
};
}
function createGetSystemStatusTool(logger: ILogger): MCPTool {
return {
name: 'system/status',
description: 'Get comprehensive system status information',
inputSchema: {
type: 'object',
properties: {},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Getting system status', { sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const status = await context.orchestrator.getSystemStatus();
return {
...status,
timestamp: new Date().toISOString(),
};
},
};
}
function createGetMetricsTool(logger: ILogger): MCPTool {
return {
name: 'system/metrics',
description: 'Get system performance metrics',
inputSchema: {
type: 'object',
properties: {
timeRange: {
type: 'string',
enum: ['1h', '6h', '24h', '7d'],
default: '1h',
description: 'Time range for metrics',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Getting system metrics', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const metrics = await context.orchestrator.getMetrics(input.timeRange || '1h');
return {
metrics,
timeRange: input.timeRange || '1h',
timestamp: new Date().toISOString(),
};
},
};
}
function createHealthCheckTool(logger: ILogger): MCPTool {
return {
name: 'system/health',
description: 'Perform a comprehensive health check',
inputSchema: {
type: 'object',
properties: {
deep: {
type: 'boolean',
default: false,
description: 'Perform deep health check including component tests',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Performing health check', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const healthCheck = await context.orchestrator.performHealthCheck(input.deep || false);
return {
...healthCheck,
timestamp: new Date().toISOString(),
};
},
};
}
function createGetConfigTool(logger: ILogger): MCPTool {
return {
name: 'config/get',
description: 'Get current system configuration',
inputSchema: {
type: 'object',
properties: {
section: {
type: 'string',
enum: ['orchestrator', 'terminal', 'memory', 'coordination', 'mcp', 'logging'],
description: 'Specific configuration section to retrieve',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Getting configuration', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const config = await context.orchestrator.getConfig(input.section);
return {
config,
section: input.section,
timestamp: new Date().toISOString(),
};
},
};
}
function createUpdateConfigTool(logger: ILogger): MCPTool {
return {
name: 'config/update',
description: 'Update system configuration',
inputSchema: {
type: 'object',
properties: {
section: {
type: 'string',
enum: ['orchestrator', 'terminal', 'memory', 'coordination', 'mcp', 'logging'],
description: 'Configuration section to update',
},
config: {
type: 'object',
description: 'Configuration values to update',
},
restart: {
type: 'boolean',
default: false,
description: 'Restart affected components after update',
},
},
required: ['section', 'config'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Updating configuration', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const result = await context.orchestrator.updateConfig(
input.section,
input.config,
input.restart || false,
);
return {
...result,
timestamp: new Date().toISOString(),
};
},
};
}
function createValidateConfigTool(logger: ILogger): MCPTool {
return {
name: 'config/validate',
description: 'Validate a configuration object',
inputSchema: {
type: 'object',
properties: {
config: {
type: 'object',
description: 'Configuration object to validate',
},
},
required: ['config'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Validating configuration', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const validation = await context.orchestrator.validateConfig(input.config);
return {
...validation,
timestamp: new Date().toISOString(),
};
},
};
}
function createExecuteWorkflowTool(logger: ILogger): MCPTool {
return {
name: 'workflow/execute',
description: 'Execute a workflow from a file or definition',
inputSchema: {
type: 'object',
properties: {
filePath: {
type: 'string',
description: 'Path to workflow file',
},
workflow: {
type: 'object',
description: 'Inline workflow definition',
},
parameters: {
type: 'object',
description: 'Parameters to pass to the workflow',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Executing workflow', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
if (!input.filePath && !input.workflow) {
throw new Error('Either filePath or workflow must be provided');
}
const result = await context.orchestrator.executeWorkflow({
filePath: input.filePath,
workflow: input.workflow,
parameters: input.parameters || {},
});
return {
...result,
timestamp: new Date().toISOString(),
};
},
};
}
function createCreateWorkflowTool(logger: ILogger): MCPTool {
return {
name: 'workflow/create',
description: 'Create a new workflow definition',
inputSchema: {
type: 'object',
properties: {
name: {
type: 'string',
description: 'Name of the workflow',
},
description: {
type: 'string',
description: 'Description of the workflow',
},
tasks: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'string' },
type: { type: 'string' },
description: { type: 'string' },
dependencies: {
type: 'array',
items: { type: 'string' },
},
assignTo: { type: 'string' },
},
required: ['id', 'type', 'description'],
},
description: 'List of tasks in the workflow',
},
savePath: {
type: 'string',
description: 'Path to save the workflow file',
},
},
required: ['name', 'tasks'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Creating workflow', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const workflow = {
name: input.name,
description: input.description,
tasks: input.tasks,
created: new Date().toISOString(),
};
const result = await context.orchestrator.createWorkflow(workflow, input.savePath);
return {
...result,
workflow,
timestamp: new Date().toISOString(),
};
},
};
}
function createListWorkflowsTool(logger: ILogger): MCPTool {
return {
name: 'workflow/list',
description: 'List available workflows',
inputSchema: {
type: 'object',
properties: {
directory: {
type: 'string',
description: 'Directory to search for workflows',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Listing workflows', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const workflows = await context.orchestrator.listWorkflows(input.directory);
return {
workflows,
count: workflows.length,
timestamp: new Date().toISOString(),
};
},
};
}
function createExecuteCommandTool(logger: ILogger): MCPTool {
return {
name: 'terminal/execute',
description: 'Execute a command in a terminal session',
inputSchema: {
type: 'object',
properties: {
command: {
type: 'string',
description: 'Command to execute',
},
args: {
type: 'array',
items: { type: 'string' },
description: 'Command arguments',
},
cwd: {
type: 'string',
description: 'Working directory for the command',
},
env: {
type: 'object',
description: 'Environment variables',
},
timeout: {
type: 'number',
default: 30000,
description: 'Command timeout in milliseconds',
},
terminalId: {
type: 'string',
description: 'Specific terminal ID to use',
},
},
required: ['command'],
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Executing command', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const result = await context.orchestrator.executeCommand({
command: input.command,
args: input.args,
cwd: input.cwd,
env: input.env,
timeout: input.timeout || 30000,
terminalId: input.terminalId,
});
return {
...result,
timestamp: new Date().toISOString(),
};
},
};
}
function createListTerminalsTool(logger: ILogger): MCPTool {
return {
name: 'terminal/list',
description: 'List all terminal sessions',
inputSchema: {
type: 'object',
properties: {
includeIdle: {
type: 'boolean',
default: true,
description: 'Include idle terminals',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Listing terminals', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const terminals = await context.orchestrator.listTerminals(input.includeIdle !== false);
return {
terminals,
count: terminals.length,
timestamp: new Date().toISOString(),
};
},
};
}
function createCreateTerminalTool(logger: ILogger): MCPTool {
return {
name: 'terminal/create',
description: 'Create a new terminal session',
inputSchema: {
type: 'object',
properties: {
cwd: {
type: 'string',
description: 'Working directory for the terminal',
},
env: {
type: 'object',
description: 'Environment variables',
},
shell: {
type: 'string',
description: 'Shell to use (bash, zsh, etc.)',
},
},
},
handler: async (input: any, context?: ClaudeFlowToolContext) => {
logger.info('Creating terminal', { input, sessionId: context?.sessionId });
if (!context?.orchestrator) {
throw new Error('Orchestrator not available');
}
const terminal = await context.orchestrator.createTerminal({
cwd: input.cwd,
env: input.env,
shell: input.shell,
});
return {
terminal,
timestamp: new Date().toISOString(),
};
},
};
}
function getDefaultSystemPrompt(type: string): string {
const prompts = {
coordinator:
'You are a coordinator agent responsible for planning, delegating, and orchestrating tasks across multiple agents.',
researcher:
'You are a research agent specialized in gathering, analyzing, and synthesizing information from various sources.',
implementer:
'You are an implementation agent focused on writing code, creating solutions, and executing technical tasks.',
analyst:
'You are an analysis agent that identifies patterns, generates insights, and provides data-driven recommendations.',
custom: 'You are a specialized agent with custom capabilities defined by your configuration.',
};
return prompts[type as keyof typeof prompts] || prompts.custom;
}