Skip to main content
Glama
use-tool.ts8.39 kB
/** * Use Tool Command * * DESIGN PATTERNS: * - Command pattern with Commander for CLI argument parsing * - Async/await pattern for asynchronous operations * - Error handling pattern with try-catch and proper exit codes * * CODING STANDARDS: * - Use async action handlers for asynchronous operations * - Provide clear option descriptions and default values * - Handle errors gracefully with process.exit() * - Log progress and errors to console * - Use Commander's .option() and .argument() for inputs * * AVOID: * - Synchronous blocking operations in action handlers * - Missing error handling (always use try-catch) * - Hardcoded values (use options or environment variables) * - Not exiting with appropriate exit codes on errors */ import { Command } from 'commander'; import { ConfigFetcherService } from '../services/ConfigFetcherService'; import { McpClientManagerService } from '../services/McpClientManagerService'; import { SkillService } from '../services/SkillService'; import { findConfigFile } from '../utils'; /** * Execute an MCP tool with arguments */ export const useToolCommand = new Command('use-tool') .description('Execute an MCP tool with arguments') .argument('<toolName>', 'Tool name to execute') .option('-c, --config <path>', 'Path to MCP server configuration file') .option('-s, --server <name>', 'Server name (required if tool exists on multiple servers)') .option('-a, --args <json>', 'Tool arguments as JSON string', '{}') .option('-j, --json', 'Output as JSON', false) .action(async (toolName: string, options) => { try { // Find config file: use provided path, or search PROJECT_PATH then cwd const configFilePath = options.config || findConfigFile(); if (!configFilePath) { console.error('Error: No config file found. Use --config or create mcp-config.yaml'); process.exit(1); } // Parse tool arguments let toolArgs: any = {}; try { toolArgs = JSON.parse(options.args); } catch (error) { console.error('Error: Invalid JSON in --args'); process.exit(1); } // Initialize services const configFetcher = new ConfigFetcherService({ configFilePath, }); const config = await configFetcher.fetchConfiguration(); const clientManager = new McpClientManagerService(); // Connect to all configured MCP servers const connectionPromises = Object.entries(config.mcpServers).map( async ([serverName, serverConfig]) => { try { await clientManager.connectToServer(serverName, serverConfig); if (!options.json) { console.error(`✓ Connected to ${serverName}`); } } catch (error) { if (!options.json) { console.error(`✗ Failed to connect to ${serverName}:`, error); } } } ); await Promise.all(connectionPromises); const clients = clientManager.getAllClients(); if (clients.length === 0) { console.error('No MCP servers connected'); process.exit(1); } // If server is specified, use that server if (options.server) { const client = clientManager.getClient(options.server); if (!client) { console.error(`Server "${options.server}" not found`); process.exit(1); } try { if (!options.json) { console.error(`Executing ${toolName} on ${options.server}...`); } const result = await client.callTool(toolName, toolArgs); if (options.json) { console.log(JSON.stringify(result, null, 2)); } else { console.log('\nResult:'); if (result.content) { for (const content of result.content) { if (content.type === 'text') { console.log(content.text); } else { console.log(JSON.stringify(content, null, 2)); } } } if (result.isError) { console.error('\n⚠️ Tool execution returned an error'); process.exit(1); } } await clientManager.disconnectAll(); return; } catch (error) { console.error(`Failed to execute tool "${toolName}":`, error); await clientManager.disconnectAll(); process.exit(1); } } // Search for the tool across all servers const matchingServers: string[] = []; for (const client of clients) { try { const tools = await client.listTools(); const hasTool = tools.some((t: any) => t.name === toolName); if (hasTool) { matchingServers.push(client.serverName); } } catch (error) { if (!options.json) { console.error(`Failed to list tools from ${client.serverName}:`, error); } } } if (matchingServers.length === 0) { // Tool not found in MCP servers - check if it's a skill const cwd = process.env.PROJECT_PATH || process.cwd(); const skillPaths = config.skills?.paths || []; if (skillPaths.length > 0) { try { const skillService = new SkillService(cwd, skillPaths); // Handle skill__ prefix const skillName = toolName.startsWith('skill__') ? toolName.slice('skill__'.length) : toolName; const skill = await skillService.getSkill(skillName); if (skill) { // Skills return their content when "executed" const result = { content: [ { type: 'text', text: skill.content, }, ], }; if (options.json) { console.log(JSON.stringify(result, null, 2)); } else { console.log('\nSkill content:'); console.log(skill.content); } await clientManager.disconnectAll(); return; } } catch (error) { if (!options.json) { console.error(`Failed to lookup skill "${toolName}":`, error); } } } console.error(`Tool or skill "${toolName}" not found on any connected server or configured skill paths`); await clientManager.disconnectAll(); process.exit(1); } if (matchingServers.length > 1) { console.error(`Tool "${toolName}" found on multiple servers: ${matchingServers.join(', ')}`); console.error('Please specify --server to disambiguate'); await clientManager.disconnectAll(); process.exit(1); } // Execute on the single matching server const targetServer = matchingServers[0]; const client = clientManager.getClient(targetServer); if (!client) { console.error(`Internal error: Server "${targetServer}" not connected`); await clientManager.disconnectAll(); process.exit(1); } try { if (!options.json) { console.error(`Executing ${toolName} on ${targetServer}...`); } const result = await client.callTool(toolName, toolArgs); if (options.json) { console.log(JSON.stringify(result, null, 2)); } else { console.log('\nResult:'); if (result.content) { for (const content of result.content) { if (content.type === 'text') { console.log(content.text); } else { console.log(JSON.stringify(content, null, 2)); } } } if (result.isError) { console.error('\n⚠️ Tool execution returned an error'); await clientManager.disconnectAll(); process.exit(1); } } await clientManager.disconnectAll(); } catch (error) { console.error(`Failed to execute tool "${toolName}":`, error); await clientManager.disconnectAll(); process.exit(1); } } catch (error) { console.error('Error executing use-tool:', error); process.exit(1); } });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/AgiFlow/aicode-toolkit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server