Skip to main content
Glama

claude_code

Execute code operations, manage files, run Git workflows, and handle terminal commands through natural language prompts for development tasks.

Instructions

Claude Code Agent: Your versatile multi-modal assistant for code, file, Git, and terminal operations via Claude CLI. Use workFolder for contextual execution.

• File ops: Create, read, (fuzzy) edit, move, copy, delete, list files, analyze/ocr images, file content analysis └─ e.g., "Create /tmp/log.txt with 'system boot'", "Edit main.py to replace 'debug_mode = True' with 'debug_mode = False'", "List files in /src", "Move a specific section somewhere else"

• Code: Generate / analyse / refactor / fix └─ e.g. "Generate Python to parse CSV→JSON", "Find bugs in my_script.py"

• Git: Stage ▸ commit ▸ push ▸ tag (any workflow) └─ "Commit '/workspace/src/main.java' with 'feat: user auth' to develop."

• Terminal: Run any CLI cmd or open URLs └─ "npm run build", "Open https://developer.mozilla.org"

• Web search + summarise content on-the-fly

• Multi-step workflows (Version bumps, changelog updates, release tagging, etc.)

• GitHub integration Create PRs, check CI status

• Confused or stuck on an issue? Ask Claude Code for a second opinion, it might surprise you!

• Task Orchestration with "Boomerang" pattern └─ Break down complex tasks into subtasks for Claude Code to execute separately └─ Pass parent task ID and get results back for complex workflows └─ Specify return mode (summary or full) for tailored responses

Prompt tips

  1. Be concise, explicit & step-by-step for complex tasks. No need for niceties, this is a tool to get things done.

  2. For multi-line text, write it to a temporary file in the project root, use that file, then delete it.

  3. If you get a timeout, split the task into smaller steps.

  4. Seeking a second opinion/analysis: If you're stuck or want advice, you can ask claude_code to analyze a problem and suggest solutions. Clearly state in your prompt that you are looking for analysis only and no actual file modifications should be made.

  5. If workFolder is set to the project path, there is no need to repeat that path in the prompt and you can use relative paths for files.

  6. Claude Code is really good at complex multi-step file operations and refactorings and faster than your native edit features.

  7. Combine file operations, README updates, and Git commands in a sequence.

  8. Task Orchestration: For complex workflows, use parentTaskId to create subtasks and returnMode: "summary" to get concise results back.

  9. Claude can do much more, just ask it!

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
promptYesThe detailed natural language prompt for Claude to execute.
workFolderNoMandatory when using file operations or referencing any file. The working directory for the Claude CLI execution.
parentTaskIdNoOptional ID of the parent task that created this task (for task orchestration/boomerang).
returnModeNoHow results should be returned: summary (concise) or full (detailed). Defaults to full.
taskDescriptionNoShort description of the task for better organization and tracking in orchestrated workflows.
modeNoWhen MCP_USE_ROOMODES=true, specifies the mode from .roomodes to use (e.g., "boomerang-mode", "coder", "designer", etc.).

Implementation Reference

  • Input schema definition for the 'claude_code' tool, specifying parameters like prompt, workFolder, parentTaskId, returnMode, taskDescription, and mode.
              name: 'claude_code',
              description: `Claude Code Agent: Your versatile multi-modal assistant for code, file, Git, and terminal operations via Claude CLI. Use \`workFolder\` for contextual execution.
    
    • File ops: Create, read, (fuzzy) edit, move, copy, delete, list files, analyze/ocr images, file content analysis
        └─ e.g., "Create /tmp/log.txt with 'system boot'", "Edit main.py to replace 'debug_mode = True' with 'debug_mode = False'", "List files in /src", "Move a specific section somewhere else"
    
    • Code: Generate / analyse / refactor / fix
        └─ e.g. "Generate Python to parse CSV→JSON", "Find bugs in my_script.py"
    
    • Git: Stage ▸ commit ▸ push ▸ tag (any workflow)
        └─ "Commit '/workspace/src/main.java' with 'feat: user auth' to develop."
    
    • Terminal: Run any CLI cmd or open URLs
        └─ "npm run build", "Open https://developer.mozilla.org"
    
    • Web search + summarise content on-the-fly
    
    • Multi-step workflows  (Version bumps, changelog updates, release tagging, etc.)
    
    • GitHub integration  Create PRs, check CI status
    
    • Confused or stuck on an issue? Ask Claude Code for a second opinion, it might surprise you!
    
    • Task Orchestration with "Boomerang" pattern
        └─ Break down complex tasks into subtasks for Claude Code to execute separately
        └─ Pass parent task ID and get results back for complex workflows
        └─ Specify return mode (summary or full) for tailored responses
    
    **Prompt tips**
    
    1. Be concise, explicit & step-by-step for complex tasks. No need for niceties, this is a tool to get things done.
    2. For multi-line text, write it to a temporary file in the project root, use that file, then delete it.
    3. If you get a timeout, split the task into smaller steps.
    4. **Seeking a second opinion/analysis**: If you're stuck or want advice, you can ask \`claude_code\` to analyze a problem and suggest solutions. Clearly state in your prompt that you are looking for analysis only and no actual file modifications should be made.
    5. If workFolder is set to the project path, there is no need to repeat that path in the prompt and you can use relative paths for files.
    6. Claude Code is really good at complex multi-step file operations and refactorings and faster than your native edit features.
    7. Combine file operations, README updates, and Git commands in a sequence.
    8. **Task Orchestration**: For complex workflows, use \`parentTaskId\` to create subtasks and \`returnMode: "summary"\` to get concise results back.
    9. Claude can do much more, just ask it!
    
            `,
              inputSchema: {
                type: 'object',
                properties: {
                  prompt: {
                    type: 'string',
                    description: 'The detailed natural language prompt for Claude to execute.',
                  },
                  workFolder: {
                    type: 'string',
                    description: 'Mandatory when using file operations or referencing any file. The working directory for the Claude CLI execution.',
                  },
                  parentTaskId: {
                    type: 'string',
                    description: 'Optional ID of the parent task that created this task (for task orchestration/boomerang).',
                  },
                  returnMode: {
                    type: 'string',
                    enum: ['summary', 'full'],
                    description: 'How results should be returned: summary (concise) or full (detailed). Defaults to full.',
                  },
                  taskDescription: {
                    type: 'string',
                    description: 'Short description of the task for better organization and tracking in orchestrated workflows.',
                  },
                  mode: {
                    type: 'string',
                    description: 'When MCP_USE_ROOMODES=true, specifies the mode from .roomodes to use (e.g., "boomerang-mode", "coder", "designer", etc.).',
                  },
                },
                required: ['prompt'],
              },
            }
  • src/server.ts:288-392 (registration)
    Registration of the 'claude_code' tool (along with health and convert_task_markdown) in the ListToolsRequestSchema handler.
        this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
          tools: [
            {
              name: 'health',
              description: 'Returns health status, version information, and current configuration of the Claude Code MCP server.',
              inputSchema: {
                type: 'object',
                properties: {},
                required: [],
              },
            },
            {
              name: 'convert_task_markdown',
              description: 'Converts markdown task files into Claude Code MCP-compatible JSON format. Returns an array of tasks that can be executed using the claude_code tool.',
              inputSchema: {
                type: 'object',
                properties: {
                  markdownPath: {
                    type: 'string',
                    description: 'Path to the markdown task file to convert.',
                  },
                  outputPath: {
                    type: 'string',
                    description: 'Optional path where to save the JSON output. If not provided, returns the JSON directly.',
                  },
                },
                required: ['markdownPath'],
              },
            },
            {
              name: 'claude_code',
              description: `Claude Code Agent: Your versatile multi-modal assistant for code, file, Git, and terminal operations via Claude CLI. Use \`workFolder\` for contextual execution.
    
    • File ops: Create, read, (fuzzy) edit, move, copy, delete, list files, analyze/ocr images, file content analysis
        └─ e.g., "Create /tmp/log.txt with 'system boot'", "Edit main.py to replace 'debug_mode = True' with 'debug_mode = False'", "List files in /src", "Move a specific section somewhere else"
    
    • Code: Generate / analyse / refactor / fix
        └─ e.g. "Generate Python to parse CSV→JSON", "Find bugs in my_script.py"
    
    • Git: Stage ▸ commit ▸ push ▸ tag (any workflow)
        └─ "Commit '/workspace/src/main.java' with 'feat: user auth' to develop."
    
    • Terminal: Run any CLI cmd or open URLs
        └─ "npm run build", "Open https://developer.mozilla.org"
    
    • Web search + summarise content on-the-fly
    
    • Multi-step workflows  (Version bumps, changelog updates, release tagging, etc.)
    
    • GitHub integration  Create PRs, check CI status
    
    • Confused or stuck on an issue? Ask Claude Code for a second opinion, it might surprise you!
    
    • Task Orchestration with "Boomerang" pattern
        └─ Break down complex tasks into subtasks for Claude Code to execute separately
        └─ Pass parent task ID and get results back for complex workflows
        └─ Specify return mode (summary or full) for tailored responses
    
    **Prompt tips**
    
    1. Be concise, explicit & step-by-step for complex tasks. No need for niceties, this is a tool to get things done.
    2. For multi-line text, write it to a temporary file in the project root, use that file, then delete it.
    3. If you get a timeout, split the task into smaller steps.
    4. **Seeking a second opinion/analysis**: If you're stuck or want advice, you can ask \`claude_code\` to analyze a problem and suggest solutions. Clearly state in your prompt that you are looking for analysis only and no actual file modifications should be made.
    5. If workFolder is set to the project path, there is no need to repeat that path in the prompt and you can use relative paths for files.
    6. Claude Code is really good at complex multi-step file operations and refactorings and faster than your native edit features.
    7. Combine file operations, README updates, and Git commands in a sequence.
    8. **Task Orchestration**: For complex workflows, use \`parentTaskId\` to create subtasks and \`returnMode: "summary"\` to get concise results back.
    9. Claude can do much more, just ask it!
    
            `,
              inputSchema: {
                type: 'object',
                properties: {
                  prompt: {
                    type: 'string',
                    description: 'The detailed natural language prompt for Claude to execute.',
                  },
                  workFolder: {
                    type: 'string',
                    description: 'Mandatory when using file operations or referencing any file. The working directory for the Claude CLI execution.',
                  },
                  parentTaskId: {
                    type: 'string',
                    description: 'Optional ID of the parent task that created this task (for task orchestration/boomerang).',
                  },
                  returnMode: {
                    type: 'string',
                    enum: ['summary', 'full'],
                    description: 'How results should be returned: summary (concise) or full (detailed). Defaults to full.',
                  },
                  taskDescription: {
                    type: 'string',
                    description: 'Short description of the task for better organization and tracking in orchestrated workflows.',
                  },
                  mode: {
                    type: 'string',
                    description: 'When MCP_USE_ROOMODES=true, specifies the mode from .roomodes to use (e.g., "boomerang-mode", "coder", "designer", etc.).',
                  },
                },
                required: ['prompt'],
              },
            }
          ],
        }));
  • Primary handler for CallToolRequestSchema. Dispatches to claude_code logic: extracts parameters, builds CLI arguments, spawns Claude CLI process using spawnAsync with retries, heartbeats, and timeout handling, processes output.
        // Handle tool calls using the configurable execution timeout
        this.server.setRequestHandler(CallToolRequestSchema, async (args, call): Promise<ServerResult> => {
          // Generate a unique request ID
          const requestId = `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
          this.activeRequests.add(requestId);
          
          debugLog(`[Debug] Handling CallToolRequest: ${requestId}`, args);
    
          // Correctly access toolName from args.params.name (may include namespace)
          const fullToolName = args.params.name;
          // Extract the local tool name (remove namespace if present)
          const toolName = fullToolName.includes(':') ? fullToolName.split(':')[1] : fullToolName;
          
          debugLog(`[Debug] Tool request: ${fullToolName}, Local tool name: ${toolName}`);
          
          // Handle health check tool
          if (toolName === 'health') {
            // Check if Claude CLI is accessible
            let claudeCliStatus = 'unknown';
            try {
              const { stdout } = await spawnAsync('/bin/bash', [this.claudeCliPath, '--version'], { timeout: 5000 });
              claudeCliStatus = 'available';
            } catch (error) {
              claudeCliStatus = 'unavailable';
            }
    
            // Collect and return system information
            const healthInfo = {
              status: 'ok',
              version: this.packageVersion,
              claudeCli: {
                path: this.claudeCliPath,
                status: claudeCliStatus
              },
              config: {
                debugMode,
                heartbeatIntervalMs,
                executionTimeoutMs,
                useRooModes,
                maxRetries,
                retryDelayMs
              },
              system: {
                platform: os.platform(),
                release: os.release(),
                arch: os.arch(),
                cpus: os.cpus().length,
                memory: {
                  total: Math.round(os.totalmem() / (1024 * 1024)) + 'MB',
                  free: Math.round(os.freemem() / (1024 * 1024)) + 'MB'
                },
                uptime: Math.round(os.uptime() / 60) + ' minutes'
              },
              timestamp: new Date().toISOString()
            };
            
            // Health check request completed, remove from tracking
            this.activeRequests.delete(requestId);
            debugLog(`[Debug] Health check request ${requestId} completed`);
    
            return { content: [{ type: 'text', text: JSON.stringify(healthInfo, null, 2) }] };
          }
          
          // Handle convert_task_markdown tool
          if (toolName === 'convert_task_markdown') {
            const toolArguments = args.params.arguments;
            
            // Extract markdownPath (required)
            let markdownPath: string;
            if (
              toolArguments &&
              typeof toolArguments === 'object' &&
              'markdownPath' in toolArguments &&
              typeof toolArguments.markdownPath === 'string'
            ) {
              markdownPath = toolArguments.markdownPath;
            } else {
              throw new McpError(ErrorCode.InvalidParams, 'Missing or invalid required parameter: markdownPath for convert_task_markdown tool');
            }
            
            // Extract outputPath (optional)
            let outputPath: string | undefined;
            if (toolArguments.outputPath && typeof toolArguments.outputPath === 'string') {
              outputPath = toolArguments.outputPath;
            }
            
            debugLog(`[Debug] Converting markdown task file: ${markdownPath}`);
            
            let stderr = '';
            
            try {
              // Prepare command to run task_converter.py
              const pythonPath = 'python3';
              const converterPath = pathResolve(__dirname, '../docs/task_converter.py');
              
              // Use --json-output flag to get JSON to stdout
              const args = ['--json-output', markdownPath];
              
              const result = await spawnAsync(pythonPath, [converterPath, ...args], {
                cwd: homedir(),
                timeout: 30000 // 30 seconds timeout
              });
              
              const stdout = result.stdout;
              stderr = result.stderr;
              
              // Extract progress messages and actual errors
              const stderrLines = stderr.split('\n');
              const progressMessages = stderrLines.filter(line => line.includes('[Progress]'));
              const errorMessages = stderrLines.filter(line => !line.includes('[Progress]') && line.trim());
              
              // Log progress messages
              progressMessages.forEach(msg => {
                console.error(msg); // Send to client
                debugLog(msg);
              });
              
              if (errorMessages.length > 0) {
                stderr = errorMessages.join('\n');
                debugLog(`[Debug] Task converter stderr: ${stderr}`);
              }
              
              // Check if there was an error from the converter
              if (stderr && stderr.includes('Markdown format validation failed')) {
                // Return validation error as a structured response
                const validationError = {
                  status: 'error',
                  error: 'Markdown format validation failed',
                  details: stderr,
                  helpUrl: 'https://github.com/grahama1970/claude-code-mcp/blob/main/README.md#markdown-task-file-format'
                };
                
                this.activeRequests.delete(requestId);
                return { content: [{ type: 'text', text: JSON.stringify(validationError, null, 2) }] };
              }
              
              // Parse the JSON output
              const tasks = JSON.parse(stdout);
              
              // If outputPath is provided, also save to file
              if (outputPath) {
                await fs.writeFile(outputPath, JSON.stringify(tasks, null, 2));
                debugLog(`[Debug] Saved converted tasks to: ${outputPath}`);
              }
              
              // Return the converted tasks
              const response = {
                status: 'success',
                tasksCount: tasks.length,
                outputPath: outputPath || 'none',
                tasks: tasks
              };
              
              this.activeRequests.delete(requestId);
              return { content: [{ type: 'text', text: JSON.stringify(response, null, 2) }] };
              
            } catch (error) {
              this.activeRequests.delete(requestId);
              const errorMessage = error instanceof Error ? error.message : String(error);
              
              // Check if this is a JSON parsing error (indicating validation failure)
              if (errorMessage.includes('JSON') && stderr) {
                const validationError = {
                  status: 'error',
                  error: 'Task conversion failed',
                  details: stderr || errorMessage,
                  helpUrl: 'https://github.com/grahama1970/claude-code-mcp/blob/main/README.md#markdown-task-file-format'
                };
                return { content: [{ type: 'text', text: JSON.stringify(validationError, null, 2) }] };
              }
              
              throw new McpError(ErrorCode.InternalError, `Failed to convert markdown tasks: ${errorMessage}`);
            }
          }
          
          // Handle tools - we support 'health', 'claude_code', and 'convert_task_markdown'
          if (toolName !== 'claude_code' && toolName !== 'health' && toolName !== 'convert_task_markdown') {
            // ErrorCode.ToolNotFound should be ErrorCode.MethodNotFound as per SDK for tools
            throw new McpError(ErrorCode.MethodNotFound, `Tool ${toolName} not found`);
          }
    
          // Robustly access arguments from args.params.arguments
          const toolArguments = args.params.arguments;
          let prompt: string;
          let parentTaskId: string | undefined;
          let returnMode: 'summary' | 'full' = 'full';
          let taskDescription: string | undefined;
          let mode: string | undefined;
    
          // Validate and extract prompt (required)
          if (
            toolArguments &&
            typeof toolArguments === 'object' &&
            'prompt' in toolArguments &&
            typeof toolArguments.prompt === 'string'
          ) {
            prompt = toolArguments.prompt;
          } else {
            throw new McpError(ErrorCode.InvalidParams, 'Missing or invalid required parameter: prompt (must be an object with a string "prompt" property) for claude_code tool');
          }
    
          // Extract optional parameters for task orchestration
          if (toolArguments.parentTaskId && typeof toolArguments.parentTaskId === 'string') {
            parentTaskId = toolArguments.parentTaskId;
            debugLog(`[Debug] Task has parent ID: ${parentTaskId}`);
          }
    
          if (toolArguments.returnMode && 
              (toolArguments.returnMode === 'summary' || toolArguments.returnMode === 'full')) {
            returnMode = toolArguments.returnMode;
            debugLog(`[Debug] Task return mode: ${returnMode}`);
          }
    
          if (toolArguments.taskDescription && typeof toolArguments.taskDescription === 'string') {
            taskDescription = toolArguments.taskDescription;
            debugLog(`[Debug] Task description: ${taskDescription}`);
          }
          
          // Check for Roo mode
          if (useRooModes && toolArguments.mode && typeof toolArguments.mode === 'string') {
            mode = toolArguments.mode;
            debugLog(`[Debug] Using Roo mode: ${mode}`);
          }
    
          // Determine the working directory
          let effectiveCwd = homedir(); // Default CWD is user's home directory
    
          // Check if workFolder is provided in the tool arguments
          if (toolArguments.workFolder && typeof toolArguments.workFolder === 'string') {
            const resolvedCwd = pathResolve(toolArguments.workFolder);
            debugLog(`[Debug] Specified workFolder: ${toolArguments.workFolder}, Resolved to: ${resolvedCwd}`);
    
            // Check if the resolved path exists
            if (existsSync(resolvedCwd)) {
              effectiveCwd = resolvedCwd;
              debugLog(`[Debug] Using workFolder as CWD: ${effectiveCwd}`);
            } else {
              debugLog(`[Warning] Specified workFolder does not exist: ${resolvedCwd}. Using default: ${effectiveCwd}`);
            }
          } else {
            debugLog(`[Debug] No workFolder provided, using default CWD: ${effectiveCwd}`);
          }
          
          // For tasks with a parent, add boomerang context to the prompt
          if (parentTaskId) {
            // Prepend task context to prompt
            const taskContext = `
    # Boomerang Task
    ${taskDescription ? `## Task Description\n${taskDescription}\n\n` : ''}
    ## Parent Task ID
    ${parentTaskId}
    
    ## Return Instructions
    You are part of a larger workflow. After completing your task, you should ${returnMode === 'summary' ? 'provide a BRIEF SUMMARY of the results' : 'return your FULL RESULTS'}.
    
    ${returnMode === 'summary' ? 'IMPORTANT: Keep your response concise and focused on key findings/changes only!' : ''}
    
    ---
    
    `;
            prompt = taskContext + prompt;
            debugLog(`[Debug] Prepended boomerang task context to prompt`);
          }
    
          try {
            debugLog(`[Debug] Attempting to execute Claude CLI with prompt: "${prompt}" in CWD: "${effectiveCwd}"`);
    
            let claudeProcessArgs = [this.claudeCliPath, '--dangerously-skip-permissions'];
            
            // Handle Roo mode selection if enabled and specified
            if (useRooModes && mode) {
              // Load room modes configuration
              const roomodes = loadRooModes();
              if (roomodes && roomodes.customModes) {
                // Find the matching mode
                const selectedMode = roomodes.customModes.find((m: any) => m.slug === mode);
                if (selectedMode) {
                  debugLog(`[Debug] Found Roo mode configuration for: ${mode}`);
                  // Add the mode parameter to the Claude CLI command
                  claudeProcessArgs.push('--role', selectedMode.roleDefinition);
                  // If the mode has a specific model, use it
                  if (selectedMode.apiConfiguration && selectedMode.apiConfiguration.modelId) {
                    claudeProcessArgs.push('--model', selectedMode.apiConfiguration.modelId);
                  }
                } else {
                  debugLog(`[Warning] Specified Roo mode not found: ${mode}`);
                }
              } else {
                debugLog(`[Warning] Roo modes configuration not found or invalid`);
              }
            }
            
            // Add the prompt
            claudeProcessArgs.push('-p', prompt);
            
            debugLog(`[Debug] Invoking /bin/bash with args: ${claudeProcessArgs.join(' ')}`);
    
            // Use retry for robust execution
            const { stdout, stderr } = await retry(
              async (bail: (err: Error) => void, attemptNumber: number) => {
                try {
                  if (attemptNumber > 1) {
                    debugLog(`[Retry] Attempt ${attemptNumber}/${maxRetries + 1} for Claude CLI execution`);
                  }
                  
                  return await spawnAsync(
                    '/bin/bash', // Explicitly use /bin/bash as the command
                    claudeProcessArgs, // Pass the script path as the first argument to bash
                    { timeout: executionTimeoutMs, cwd: effectiveCwd }
                  );
                } catch (err: any) {
                  // Log the error
                  debugLog(`[Retry] Error during attempt ${attemptNumber}/${maxRetries + 1}: ${err.message}`);
                  
                  // Determine if we should retry based on the error
                  const isNetworkError = err.message.includes('ECONNRESET') || 
                                        err.message.includes('ETIMEDOUT') ||
                                        err.message.includes('ECONNREFUSED');
                                        
                  const isTransientError = isNetworkError || 
                                          err.message.includes('429') || // Rate limit
                                          err.message.includes('500'); // Server error
                  
                  // If it's not a transient error, bail immediately
                  if (!isTransientError) {
                    debugLog(`[Retry] Non-retryable error: ${err.message}. Bailing out.`);
                    bail(err);
                    return { stdout: '', stderr: '' }; // This never happens due to bail
                  }
                  
                  // Otherwise, throw to trigger retry
                  throw err;
                }
              },
              {
                retries: maxRetries,
                minTimeout: retryDelayMs,
                onRetry: (err: Error, attempt: number) => {
                  console.error(`[Progress] Retry attempt ${attempt}/${maxRetries} due to: ${err.message}`);
                }
              }
            );
    
            debugLog('[Debug] Claude CLI stdout:', stdout.trim());
            if (stderr) {
              debugLog('[Debug] Claude CLI stderr:', stderr.trim());
            }
    
            // Process the output
            let processedOutput = stdout;
            
            // For tasks with a parent, add a boomerang marker to help identify responses
            if (parentTaskId) {
              // Add a boomerang marker with task info
              const boomerangInfo = {
                parentTaskId,
                returnMode,
                taskDescription: taskDescription || 'Unknown task',
                completed: new Date().toISOString()
              };
              
              // Add a hidden JSON marker that can be detected by the parent task
              // Format is a special comment that won't interfere with normal content
              const boomerangMarker = `\n\n<!-- BOOMERANG_RESULT ${JSON.stringify(boomerangInfo)} -->`;
              processedOutput += boomerangMarker;
              
              debugLog(`[Debug] Added boomerang marker to output for parent task: ${parentTaskId}`);
            }
    
            // Request completed successfully, remove from tracking
            this.activeRequests.delete(requestId);
            debugLog(`[Debug] Request ${requestId} completed successfully`);
            
            // Return processed output
            return { content: [{ type: 'text', text: processedOutput }] };
    
          } catch (error: any) {
            debugLog('[Error] Error executing Claude CLI:', error);
            let errorMessage = error.message || 'Unknown error';
            // Attempt to include stderr and stdout from the error object if spawnAsync attached them
            if (error.stderr) {
              errorMessage += `\nStderr: ${error.stderr}`;
            }
            if (error.stdout) {
              errorMessage += `\nStdout: ${error.stdout}`;
            }
    
            // Request failed, remove from tracking
            this.activeRequests.delete(requestId);
            debugLog(`[Debug] Request ${requestId} failed: ${errorMessage}`);
            
            if (error.signal === 'SIGTERM' || (error.message && error.message.includes('ETIMEDOUT')) || (error.code === 'ETIMEDOUT')) {
              // Reverting to InternalError due to lint issues, but with a specific timeout message.
              throw new McpError(ErrorCode.InternalError, `Claude CLI command timed out after ${executionTimeoutMs / 1000}s. Details: ${errorMessage}`);
            }
            // ErrorCode.ToolCallFailed should be ErrorCode.InternalError or a more specific execution error if available
            throw new McpError(ErrorCode.InternalError, `Claude CLI execution failed: ${errorMessage}`);
          }
        });
  • spawnAsync helper: Executes subprocesses with stdout/stderr capture, heartbeat progress messages to prevent timeouts, and proper error handling.
    async function spawnAsync(command: string, args: string[], options?: { timeout?: number, cwd?: string }): Promise<{ stdout: string; stderr: string }> {
      return new Promise((resolve, reject) => {
        debugLog(`[Spawn] Running command: ${command} ${args.join(' ')}`);
        const process = spawn(command, args, {
          shell: false, // Reverted to false
          timeout: options?.timeout,
          cwd: options?.cwd,
          stdio: ['ignore', 'pipe', 'pipe']
        });
    
        let stdout = '';
        let stderr = '';
        let executionStartTime = Date.now();
        let heartbeatCounter = 0;
    
        // Set up progress reporter to prevent client timeouts
        // Send a heartbeat message at the configured interval
        const progressReporter = setInterval(() => {
          heartbeatCounter++;
          const elapsedSeconds = Math.floor((Date.now() - executionStartTime) / 1000);
          const heartbeatMessage = `[Progress] Claude Code execution in progress: ${elapsedSeconds}s elapsed (heartbeat #${heartbeatCounter})`;
          
          // Log heartbeat to stderr which will be seen by the client
          console.error(heartbeatMessage);
          debugLog(heartbeatMessage);
        }, heartbeatIntervalMs);
    
        process.stdout.on('data', (data) => { stdout += data.toString(); });
        process.stderr.on('data', (data) => {
          stderr += data.toString();
          debugLog(`[Spawn Stderr Chunk] ${data.toString()}`);
        });
    
        process.on('error', (error: NodeJS.ErrnoException) => {
          clearInterval(progressReporter); // Clean up the interval
          debugLog(`[Spawn Error Event] Full error object:`, error);
          let errorMessage = `Spawn error: ${error.message}`;
          if (error.path) {
            errorMessage += ` | Path: ${error.path}`;
          }
          if (error.syscall) {
            errorMessage += ` | Syscall: ${error.syscall}`;
          }
          errorMessage += `\nStderr: ${stderr.trim()}`;
          reject(new Error(errorMessage));
        });
    
        process.on('close', (code) => {
          clearInterval(progressReporter); // Clean up the interval
          const executionTimeMs = Date.now() - executionStartTime;
          debugLog(`[Spawn Close] Exit code: ${code}, Execution time: ${executionTimeMs}ms`);
          debugLog(`[Spawn Stderr Full] ${stderr.trim()}`);
          debugLog(`[Spawn Stdout Full] ${stdout.trim()}`);
          if (code === 0) {
            resolve({ stdout, stderr });
          } else {
            reject(new Error(`Command failed with exit code ${code}\nStderr: ${stderr.trim()}\nStdout: ${stdout.trim()}`));
          }
        });
      });
    }
  • findClaudeCli helper: Locates the Claude CLI executable, preferring local install at ~/.claude/local/claude, falling back to PATH.
    function findClaudeCli(): string {
      debugLog('[Debug] Attempting to find Claude CLI...');
    
      // 1. Try local install path: ~/.claude/local/claude
      const userPath = join(homedir(), '.claude', 'local', 'claude');
      debugLog(`[Debug] Checking for Claude CLI at local user path: ${userPath}`);
    
      if (existsSync(userPath)) {
        debugLog(`[Debug] Found Claude CLI at local user path: ${userPath}. Using this path.`);
        return userPath;
      } else {
        debugLog(`[Debug] Claude CLI not found at local user path: ${userPath}.`);
      }
    
      // 2. Fallback to 'claude' (PATH lookup)
      debugLog('[Debug] Falling back to "claude" command name, relying on spawn/PATH lookup.');
      console.warn('[Warning] Claude CLI not found at ~/.claude/local/claude. Falling back to "claude" in PATH. Ensure it is installed and accessible.');
      return 'claude';
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It does describe some behavioral traits like timeout handling ('split the task into smaller steps'), analysis-only mode ('no actual file modifications should be made'), and task orchestration patterns. However, it doesn't cover important aspects like authentication requirements, rate limits, error handling, or what happens when operations fail.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is excessively long (over 500 words) with multiple sections, bullet points, and promotional language ('it might surprise you!', 'Claude can do much more, just ask it!'). While well-structured with clear categories, it contains redundant information and marketing fluff that doesn't help an AI agent select and invoke the tool correctly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 6-parameter tool with no annotations and no output schema, the description provides substantial context about capabilities and usage patterns. However, it lacks critical information about return values, error conditions, and operational constraints. The description compensates somewhat for the lack of structured metadata but leaves important gaps for a tool of this complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 6 parameters thoroughly. The description adds some context about 'workFolder' ('Mandatory when using file operations') and mentions 'parentTaskId' and 'returnMode' in the task orchestration section, but doesn't provide significant additional semantic meaning beyond what's already in the schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states this is a 'versatile multi-modal assistant for code, file, Git, and terminal operations via Claude CLI' and provides specific examples of what it can do (file operations, code generation/analysis, Git workflows, terminal commands, web search, etc.). It distinguishes itself from sibling tools like 'convert_task_markdown' and 'health' by being a comprehensive execution tool rather than a specialized converter or health checker.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool (for code, file, Git, terminal operations, web search, multi-step workflows, GitHub integration, task orchestration) and includes specific prompt tips. However, it doesn't explicitly state when NOT to use it or provide clear alternatives to sibling tools, though the broad scope makes alternatives less relevant.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/twalichiewicz/meshseeks'

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