Skip to main content
Glama
CaptainCrouton89

Claude Parallel Tasks MCP Server

run_parallel_claude_tasks

Execute multiple Claude prompts simultaneously, optionally with file contexts, and save outputs to individual files for efficient processing.

Instructions

Runs multiple Claude prompts in parallel, optionally with file contexts, redirecting output to files.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queriesYesA list of query objects to run with Claude in parallel

Implementation Reference

  • Handler function that maps over queries, executes each Claude task via shell command using claude CLI in parallel with Promise.all, generates output files, and returns a summary report.
    async ({ queries }) => { const taskPromises = queries.map(async (query, i) => { const { queryText, contextFilePaths } = query; // Escape double quotes in the query to prevent command injection issues const escapedQueryText = queryText.replace(/"/g, '\\"'); const outputFileName = `claude_task_${i}_${Date.now()}.md`; let fileContextString = ""; if (contextFilePaths && contextFilePaths.length > 0) { // Ensure file paths are properly escaped if they contain spaces or special characters // For simplicity, assuming paths don't need complex escaping beyond being quoted if necessary. // However, for robust handling, each path might need individual shell argument escaping. fileContextString = contextFilePaths.map((fp) => `"${fp}"`).join(" ") + " "; // Add a space after the files } // Use environment variable for API key const apiKey = process.env.ANTHROPIC_API_KEY; if (!apiKey) { throw new Error("ANTHROPIC_API_KEY environment variable is not set"); } const command = `export ANTHROPIC_API_KEY=${apiKey} && claude -p --dangerously-skip-permissions ${fileContextString}"${escapedQueryText}" > ${outputFileName} 2>&1`; try { const { stdout, stderr } = await execAsync(command); return { query: queryText, command: command, outputFile: outputFileName, status: "completed", stdout: stdout, stderr: stderr, }; } catch (error) { const err = error as Error; return { query: queryText, command: command, outputFile: outputFileName, status: "failed", error: err.message, }; } }); // Wait for all tasks to complete const taskExecutionResults = await Promise.all(taskPromises); const reportLines = taskExecutionResults.map( (r) => `Task for query (first 30 chars): "${r.query.substring( 0, 30 )}..." - Status: ${r.status}. Output file: ${r.outputFile}${ r.error ? ` (Error: ${r.error})` : "" }` ); return { content: [ { type: "text", text: `Completed ${ queries.length } Claude tasks in parallel.\\nDetails:\\n${reportLines.join("\\n")}`, }, ], }; }
  • Zod schema defining the input parameter 'queries' as an array of objects with queryText (string) and optional contextFilePaths (array of strings).
    queries: z .array( z.object({ queryText: z.string().describe("The text prompt to send to Claude"), contextFilePaths: z .array(z.string()) .optional() .describe( "Optional list of file paths to provide as context to Claude" ), }) ) .describe("A list of query objects to run with Claude in parallel"), },
  • src/index.ts:18-107 (registration)
    MCP server tool registration call including name, description, input schema, and inline handler function.
    server.tool( "run_parallel_claude_tasks", "Runs multiple Claude prompts in parallel, optionally with file contexts, redirecting output to files.", { queries: z .array( z.object({ queryText: z.string().describe("The text prompt to send to Claude"), contextFilePaths: z .array(z.string()) .optional() .describe( "Optional list of file paths to provide as context to Claude" ), }) ) .describe("A list of query objects to run with Claude in parallel"), }, async ({ queries }) => { const taskPromises = queries.map(async (query, i) => { const { queryText, contextFilePaths } = query; // Escape double quotes in the query to prevent command injection issues const escapedQueryText = queryText.replace(/"/g, '\\"'); const outputFileName = `claude_task_${i}_${Date.now()}.md`; let fileContextString = ""; if (contextFilePaths && contextFilePaths.length > 0) { // Ensure file paths are properly escaped if they contain spaces or special characters // For simplicity, assuming paths don't need complex escaping beyond being quoted if necessary. // However, for robust handling, each path might need individual shell argument escaping. fileContextString = contextFilePaths.map((fp) => `"${fp}"`).join(" ") + " "; // Add a space after the files } // Use environment variable for API key const apiKey = process.env.ANTHROPIC_API_KEY; if (!apiKey) { throw new Error("ANTHROPIC_API_KEY environment variable is not set"); } const command = `export ANTHROPIC_API_KEY=${apiKey} && claude -p --dangerously-skip-permissions ${fileContextString}"${escapedQueryText}" > ${outputFileName} 2>&1`; try { const { stdout, stderr } = await execAsync(command); return { query: queryText, command: command, outputFile: outputFileName, status: "completed", stdout: stdout, stderr: stderr, }; } catch (error) { const err = error as Error; return { query: queryText, command: command, outputFile: outputFileName, status: "failed", error: err.message, }; } }); // Wait for all tasks to complete const taskExecutionResults = await Promise.all(taskPromises); const reportLines = taskExecutionResults.map( (r) => `Task for query (first 30 chars): "${r.query.substring( 0, 30 )}..." - Status: ${r.status}. Output file: ${r.outputFile}${ r.error ? ` (Error: ${r.error})` : "" }` ); return { content: [ { type: "text", text: `Completed ${ queries.length } Claude tasks in parallel.\\nDetails:\\n${reportLines.join("\\n")}`, }, ], }; } );

Other Tools

Related 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/CaptainCrouton89/claude-code-mcp'

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