UNPKG

@grebyn/toolflow-mcp-server

Version:

MCP server for managing other MCP servers - discover, install, organize into bundles, and automate with workflows. Uses StreamableHTTP transport with dual OAuth/API key authentication.

186 lines (177 loc) 8.18 kB
import { ApiClient } from '../../utils/api-client.js'; import { exec } from 'child_process'; import { promisify } from 'util'; const execAsync = promisify(exec); export const performWorkflowTool = { name: 'perform_workflow', description: `Check if a workflow's required MCP servers are installed and return either the workflow instructions or a list of missing servers. This tool performs a quick name-based check to see if all required servers are present in the client's configuration. If servers are missing, use list_missing_workflow_servers to get the full installation configurations. If all servers are present, you'll receive the workflow instructions to execute.`, inputSchema: { type: 'object', properties: { workflow_id: { type: 'string', description: 'The workflow ID from list_workflows results' }, config_path: { type: 'string', description: 'Optional custom configuration file path. If not provided, uses CLIENT environment variable.' } }, required: ['workflow_id'] }, async execute(args, context) { try { // Fetch the workflow from API const workflow = await ApiClient.getWorkflow(args.workflow_id, context); if (!workflow) { return { content: [{ type: 'text', text: 'Workflow not found or access denied.' }] }; } // Get the current MCP configuration using the CLI let command; if (args.config_path) { command = `npx @grebyn/toolflow-cli@latest read --path "${args.config_path}"`; } else { const client = process.env.CLIENT; if (!client) { throw new Error('CLIENT environment variable not set. Please configure your MCP client connection.'); } command = `npx @grebyn/toolflow-cli@latest read ${client}`; } let currentConfig = {}; try { const { stdout } = await execAsync(command, { timeout: 30000, maxBuffer: 1024 * 1024 }); currentConfig = JSON.parse(stdout); } catch (error) { console.error('Failed to read current configuration:', error); // Continue with empty config to show all servers as missing } // Extract installed servers from the config const installedServers = new Set(); // Check different config formats if (currentConfig.mcpServers) { Object.keys(currentConfig.mcpServers).forEach(name => installedServers.add(name)); } else if (currentConfig.servers) { Object.keys(currentConfig.servers).forEach(name => installedServers.add(name)); } else if (currentConfig.context_servers) { Object.keys(currentConfig.context_servers).forEach(name => installedServers.add(name)); } // Check for missing servers const requiredServers = Object.keys(workflow.required_servers || {}); const missingServers = requiredServers.filter(server => !installedServers.has(server)); if (missingServers.length > 0) { // Servers are missing const result = { status: 'missing_servers', workflow_id: workflow.id, workflow_name: workflow.name, can_perform: false, missing_servers: missingServers, instructions: undefined, required_servers: workflow.required_servers, install_commands: workflow.install_commands }; return { content: [{ type: 'text', text: formatWorkflowResult(result, workflow) }] }; } // All servers are installed const result = { status: 'ready', workflow_id: workflow.id, workflow_name: workflow.name, can_perform: true, missing_servers: [], instructions: workflow.instructions, required_servers: workflow.required_servers, install_commands: workflow.install_commands }; return { content: [{ type: 'text', text: formatWorkflowResult(result, workflow) }] }; } catch (error) { console.error('Error performing workflow:', error); return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : 'An unexpected error occurred'}` }] }; } } }; function formatWorkflowResult(result, workflow) { if (!result.can_perform) { // Missing servers - format installation instructions const hasInstallCommands = result.install_commands && result.install_commands.length > 0; return `**Cannot Perform Workflow: Missing MCP Servers** **Workflow:** ${result.workflow_name} **Missing Servers:** ${result.missing_servers?.join(', ') || 'None'} ${hasInstallCommands ? ` **Installation Commands Required:** Before configuring the servers, run these commands: ${result.install_commands.map(cmd => `- \`${cmd}\``).join('\n')} ` : ''} **Required Actions:** ${hasInstallCommands ? '1. Run the installation commands listed above\n' : ''}${hasInstallCommands ? '2' : '1'}. Use \`list_missing_workflow_servers\` with these parameters: - workflow_id: "${result.workflow_id}" - missing_servers: ${JSON.stringify(result.missing_servers || [])} ${hasInstallCommands ? '3' : '2'}. Use \`write_client_config\` to install the servers ${hasInstallCommands ? '4' : '3'}. Call \`perform_workflow\` again after installation **Required Servers:** ${result.required_servers ? Object.entries(result.required_servers) .map(([name, config]) => { const isMissing = result.missing_servers?.includes(name) || false; const status = isMissing ? '❌ Missing' : '✅ Installed'; return `- **${name}** (${status}): ${config.command} ${config.args.join(' ')}`; }) .join('\n') : 'None'}`; } // All servers installed - format workflow instructions return `**Ready to Perform Workflow** **Workflow:** ${result.workflow_name} **Description:** ${workflow.description} **All Required Servers Installed:** ✅ ${result.required_servers ? Object.keys(result.required_servers).map(name => `- ${name}`).join('\n') : 'None'} **Workflow Instructions:** ${workflow.user_provided_instructions ? `\n**User Instructions:**\n${workflow.user_provided_instructions}\n` : ''} **Steps to Execute:** ${result.instructions?.steps.map((step, index) => { let stepText = `${index + 1}. **${step.action}**`; if (step.description) stepText += `\n ${step.description}`; if (step.tool) stepText += `\n Tool: ${step.tool}`; if (step.command) stepText += `\n Command: \`${step.command}\``; if (step.expected_outcome) stepText += `\n Expected: ${step.expected_outcome}`; if (step.on_failure) stepText += `\n On Failure: ${step.on_failure}`; return stepText; }).join('\n\n')} **Tags:** ${workflow.tags ? workflow.tags.join(', ') : 'None'} **Next Steps:** Execute the workflow steps in order. Each step should be performed carefully, checking for the expected outcomes before proceeding to the next step.`; } //# sourceMappingURL=performWorkflow.js.map