execute_code
Execute Python, Bash, or Node.js code in a secure sandboxed environment to process data and achieve significant token savings by offloading computation from LLM context.
Instructions
Execute code in sandboxed environment. Supports Python, Bash, Node.js. Now with heredoc support for bash scripts (<<EOF, <<'EOF', <<EOT). Achieves 98%+ token savings by processing in execution environment.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Code to execute. Supports heredocs for bash/sh: <<EOF, <<'EOF'. | |
| language | No | Programming language | bash |
| timeout | No | Execution timeout in seconds | |
| response_format | No | summary |
Implementation Reference
- src/index.ts:473-607 (handler)The main handler for execute_code tool. Creates a temp directory, writes code to a file, executes it with the appropriate interpreter (python3, bash, sh, or node), handles heredoc parsing for bash/sh scripts, manages timeouts, and returns results with token metrics. Cleans up temp files on completion.
private async executeCode(args: { code: string; language?: string; timeout?: number; response_format?: string; }): Promise<{ content: any[] }> { const startTime = Date.now(); const language = args.language || 'bash'; const timeout = args.timeout || 30; const responseFormat = args.response_format || 'summary'; // Language configuration const languageConfig: Record<string, { cmd: string; ext: string }> = { python: { cmd: 'python3', ext: '.py' }, bash: { cmd: 'bash', ext: '.sh' }, sh: { cmd: 'sh', ext: '.sh' }, node: { cmd: 'node', ext: '.js' }, javascript: { cmd: 'node', ext: '.js' }, }; if (!languageConfig[language]) { return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `Unsupported language: ${language}. Supported: ${Object.keys(languageConfig).join(', ')}` }, null, 2) }] }; } let tmpDir: string | null = null; try { const config = languageConfig[language]; // Use /var/tmp for srt sandbox compatibility tmpDir = await fs.mkdtemp(path.join('/var/tmp', 'mcp-exec-')); const tmpFile = path.join(tmpDir, `code${config.ext}`); // Check for heredocs and extract them let codeToWrite = args.code; let heredocFiles: string[] = []; if (language === 'bash' || language === 'sh') { const heredocs = this.parseHeredocs(args.code); if (heredocs.length > 0) { // Write each heredoc content to a temp file for (const heredoc of heredocs) { const heredocFileName = path.join(tmpDir, `heredoc_${heredoc.delimiter}_${heredocs.indexOf(heredoc)}.txt`); await fs.writeFile(heredocFileName, heredoc.content + '\n', 'utf-8'); heredocFiles.push(heredocFileName); } // Replace heredocs with file redirections using actual tmpDir paths codeToWrite = this.replaceHeredocs(args.code, heredocs, tmpDir); } } // Write code to temp file await fs.writeFile(tmpFile, codeToWrite, 'utf-8'); // Execute with timeout, setting TMPDIR so tsx/node can create IPC pipes in our temp dir const { stdout, stderr } = await execAsync(`${config.cmd} ${tmpFile}`, { timeout: timeout * 1000, maxBuffer: 10 * 1024 * 1024, // 10MB env: { ...process.env, TMPDIR: tmpDir, // Direct tsx IPC to our writable temp dir TMP: tmpDir, TEMP: tmpDir, NODE_TMPDIR: tmpDir } }); const result: any = { success: true, language, output: stdout.trim(), exit_code: 0 }; // Track heredoc usage if (heredocFiles.length > 0) { result.heredocs_processed = heredocFiles.length; result.heredoc_support = 'enabled'; } const processingTime = Date.now() - startTime; if (responseFormat === 'summary') { // Truncate long output if (result.output.length > 500) { result.output = result.output.substring(0, 500) + `\n... (${result.output.length - 500} more chars)`; result.truncated = true; } } // Wrap with metrics return { content: [{ type: 'text', text: JSON.stringify( this.wrapWithMetrics(result, args.code.length, processingTime), null, 2 ) }] }; } catch (error: any) { const errorResult: any = { success: false, language, error: error.message || 'Execution failed' }; if (error.stdout) errorResult.stdout = error.stdout.substring(0, 200); if (error.stderr) errorResult.stderr = error.stderr.substring(0, 200); if (error.code === 'ETIMEDOUT') { errorResult.error = `Execution timed out after ${timeout}s`; } return { content: [{ type: 'text', text: JSON.stringify(errorResult, null, 2) }] }; } finally { // Clean up temp directory if (tmpDir) { await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {}); } } } - src/index.ts:609-626 (registration)Tool registration defining the execute_code tool with its name, title, description, and JSON Schema input schema. Supports code execution in Python, Bash, Sh, Node.js, and JavaScript with configurable timeout and response format.
private getToolDefinitions(): Tool[] { return [ { name: 'execute_code', title: 'Execute Code in Sandbox', description: 'Execute code in sandboxed environment. Supports Python, Bash, Node.js. Now with heredoc support for bash scripts (<<EOF, <<\'EOF\', <<EOT). Achieves 98%+ token savings by processing in execution environment.', inputSchema: { type: 'object', properties: { code: { type: 'string', description: 'Code to execute. Supports heredocs for bash/sh: <<EOF, <<\'EOF\'.', minLength: 1, maxLength: 50000 }, language: { type: 'string', enum: ['python', 'bash', 'sh', 'node', 'javascript'], default: 'bash', description: 'Programming language' }, timeout: { type: 'number', default: 30, description: 'Execution timeout in seconds', minimum: 1, maximum: 300 }, response_format: { type: 'string', enum: ['summary', 'json', 'markdown'], default: 'summary' }, }, required: ['code'], $schema: 'https://json-schema.org/draft/2020-12/schema', }, }, - src/index.ts:87-94 (handler)Request handler setup that dispatches incoming tool calls. The switch statement routes 'execute_code' requests to the executeCode method.
this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'execute_code': return await this.executeCode(args as any); case 'process_csv': - src/index.ts:39-45 (schema)Type definition for heredoc parsing results, used by the execute_code handler to process heredoc syntax in bash/sh scripts.
interface HeredocMatch { delimiter: string; content: string; startIndex: number; endIndex: number; quoted: boolean; // true for <<'EOF', false for <<EOF } - src/index.ts:391-470 (helper)Helper methods for heredoc processing: parseHeredocs extracts heredoc blocks from bash/sh code, and replaceHeredocs transforms them into file redirections for safe execution in the sandbox.
private parseHeredocs(code: string): HeredocMatch[] { const heredocs: HeredocMatch[] = []; // Heredoc patterns: // 1. <<'DELIM' (quoted, no variable expansion) // 2. <<"DELIM" (double quoted, variable expansion) // 3. <<DELIM (unquoted, variable expansion) const heredocRegex = /<<(\s*)('?|"?)([A-Za-z_][A-Za-z0-9_]*)\2/g; let match: RegExpExecArray | null; const matches: Array<{ fullMatch: string; quote: string; delimiter: string; index: number }> = []; // Find all heredoc start markers while ((match = heredocRegex.exec(code)) !== null) { matches.push({ fullMatch: match[0], quote: match[2], // '', ", or empty delimiter: match[3], index: match.index }); } // Extract each heredoc content for (const m of matches) { const startIndex = m.index + m.fullMatch.length; const delimiterPattern = new RegExp(`^${m.delimiter}\\s*$`, 'm'); // Find the closing delimiter const afterStart = code.slice(startIndex); const endMatch = delimiterPattern.exec(afterStart); if (endMatch) { const endIndex = startIndex + endMatch.index; const content = afterStart.slice(0, endMatch.index); heredocs.push({ delimiter: m.delimiter, content: content, startIndex: m.index, endIndex: endIndex + m.delimiter.length, quoted: m.quote === "'" // <<'EOF' means quoted }); } } return heredocs; } /** * Replace heredocs in code with file redirections */ private replaceHeredocs(code: string, heredocs: HeredocMatch[], tmpDir: string): string { let transformedCode = code; const replacements: Array<{ original: string; replacement: string; index: number }> = []; for (const heredoc of heredocs) { // startIndex points to where <<'DELIM' begins, endIndex points to content end (before closing delimiter) // We need to include the closing delimiter and its newline const fullHeredocEnd = heredoc.endIndex + heredoc.delimiter.length + 1; const originalHeredoc = code.slice(heredoc.startIndex, fullHeredocEnd); const tempFileName = path.join(tmpDir, `heredoc_${heredoc.delimiter}_${heredocs.indexOf(heredoc)}.txt`); // Replace entire heredoc (from <<'DELIM' to closing DELIM) with file redirection replacements.push({ original: originalHeredoc, replacement: `< "${tempFileName}"`, index: heredoc.startIndex }); } // Apply replacements (reverse order to maintain positions) let offset = 0; for (const rep of [...replacements].reverse()) { const before = transformedCode.slice(0, rep.index + offset); const after = transformedCode.slice(rep.index + offset + rep.original.length); transformedCode = before + rep.replacement + after; offset += rep.replacement.length - rep.original.length; } return transformedCode;