Skip to main content
Glama

execute_code

Run Python, Go, or JavaScript code securely in isolated containers with the Isolator MCP Server. Execute custom code snippets or predefined templates in a controlled environment.

Instructions

Executes code (Python, Go, JavaScript) in a secure, isolated container environment.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
additional_filesNoOptional array of additional files needed for execution
entrypoint_codeNoThe main code content to execute. Required unless using snippet_name.
entrypoint_filenameNoOptional filename for the main code (defaults based on language).
languageNoThe programming language (python, go, javascript). Required unless using snippet_name.
snippet_nameNoName of a pre-defined code snippet to execute (e.g., 'hello_world'). Mutually exclusive with entrypoint_code/language.

Implementation Reference

  • The primary handler for the 'execute_code' tool within the CallToolRequestSchema handler. It validates input with Zod, handles snippet loading or direct code, creates temporary files, executes code via the isolator CLI using child_process.spawn, parses JSON output, formats the result as MCP CallToolResult, and cleans up temporary directories.
    server.setRequestHandler(CallToolRequestSchema, async (request): Promise<CallToolResult> => {
      if (request.params.name !== "execute_code") {
        throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
      }
    
      // Validate input using Zod schema
      const parseResult = executeCodeInputSchema.safeParse(request.params.arguments);
      if (!parseResult.success) {
        console.error("Invalid input:", parseResult.error.errors);
        throw new McpError(ErrorCode.InvalidParams, `Invalid arguments: ${parseResult.error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(', ')}`);
      }
    
      let languageInput: string;
      let codeInput: string;
      let languageDetectedFromSnippet = false;
      const { entrypoint_filename, additional_files, snippet_name } = parseResult.data;
      let finalEntrypointFilename: string;
    
      // --- Determine code input and language: Snippet or Direct ---
      if (snippet_name) {
        const __filename = fileURLToPath(import.meta.url);
        const __dirname = path.dirname(__filename);
        const snippetsDir = path.resolve(__dirname, '..', serverConfig.promptsDir); // Use config value
        const snippetExt = path.extname(snippet_name);
        const baseSnippetName = snippetExt ? path.basename(snippet_name, snippetExt) : snippet_name;
    
        let foundSnippetPath: string | undefined;
        let detectedLang: string | undefined;
        let snippetFilename: string | undefined;
    
        const possibleExtensions: { [key: string]: string } = {
            ".py": "python",
            ".go": "go",
            ".js": "javascript",
            ".mjs": "javascript",
            ".cjs": "javascript",
        };
    
        if (snippetExt && possibleExtensions[snippetExt]) {
            detectedLang = possibleExtensions[snippetExt];
            foundSnippetPath = path.join(snippetsDir, `${baseSnippetName}${snippetExt}`);
            snippetFilename = `${baseSnippetName}${snippetExt}`;
        } else {
            for (const [ext, lang] of Object.entries(possibleExtensions)) {
                 const testPath = path.join(snippetsDir, `${baseSnippetName}${ext}`);
                 try {
                     await fs.access(testPath);
                     foundSnippetPath = testPath;
                     detectedLang = lang;
                     snippetFilename = `${baseSnippetName}${ext}`;
                     break;
                 } catch { /* continue */ }
            }
        }
    
        if (!foundSnippetPath || !detectedLang) {
            throw new McpError(ErrorCode.InvalidParams, `Snippet '${snippet_name}' not found in '${snippetsDir}' or language could not be determined.`);
        }
    
        try {
            codeInput = await fs.readFile(foundSnippetPath, 'utf-8');
            languageInput = detectedLang;
            languageDetectedFromSnippet = true;
            console.error(`Loaded code from snippet: ${foundSnippetPath}`);
        } catch (readError) {
            throw new McpError(ErrorCode.InternalError, `Failed to read snippet file '${foundSnippetPath}': ${readError instanceof Error ? readError.message : String(readError)}`);
        }
    
        if (!snippetFilename) {
            throw new McpError(ErrorCode.InternalError, `Could not determine snippet filename for ${snippet_name}`);
        }
        finalEntrypointFilename = snippetFilename;
    
      } else {
        languageInput = parseResult.data.language!;
        codeInput = parseResult.data.entrypoint_code!;
    
        finalEntrypointFilename = entrypoint_filename || "";
        if (!finalEntrypointFilename) {
            switch(languageInput.toLowerCase()) {
                case "python": finalEntrypointFilename = "main.py"; break;
                case "go": finalEntrypointFilename = "main.go"; break;
                case "javascript": finalEntrypointFilename = "index.js"; break;
                default:
                    throw new McpError(ErrorCode.InternalError, `Cannot determine default entrypoint filename for ${languageInput}`);
            }
        }
      }
    
      const langLower = languageInput.toLowerCase();
    
      if (!serverConfig.languageSettings[langLower]) {
          const errorMsg = languageDetectedFromSnippet
            ? `Language '${languageInput}' (detected from snippet '${snippet_name}') is not configured.`
            : `Unsupported language provided directly: ${languageInput}`;
          throw new McpError(ErrorCode.InvalidParams, errorMsg);
      }
    
      // --- Temporary Directory and File Creation ---
      let tempDir: string | undefined;
      try {
        tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "isolator-mcp-"));
        // Set directory permissions to be accessible (rwxr-xr-x)
        await fs.chmod(tempDir, 0o755);
        console.error(`Created temp dir: ${tempDir} with mode 755`);
    
        // Write entrypoint file
        const entrypointPath = path.join(tempDir, finalEntrypointFilename);
        await fs.writeFile(entrypointPath, codeInput);
        // Set file permissions to be readable (rw-r--r--)
        // Use 0o755 if script needs to be executable itself by the container user (less common)
        await fs.chmod(entrypointPath, 0o644);
        console.error(`Wrote entrypoint file: ${entrypointPath} with mode 644`);
    
    
        // Write additional files
        if (additional_files) {
          for (const file of additional_files) {
            const safeFilename = path.basename(file.filename);
            if (safeFilename !== file.filename || safeFilename === "." || safeFilename === "..") {
                 throw new McpError(ErrorCode.InvalidParams, `Invalid additional filename: ${file.filename}`);
            }
            const additionalFilePath = path.join(tempDir, safeFilename);
            await fs.writeFile(additionalFilePath, file.content);
            // Set file permissions to be readable (rw-r--r--)
            await fs.chmod(additionalFilePath, 0o644);
            console.error(`Wrote additional file: ${additionalFilePath} with mode 644`);
          }
        }
    
        // --- Construct Go CLI Command ---
        const args: string[] = [
            "run",
            "--language", langLower,
            "--dir", tempDir,
            "--timeout", `${serverConfig.defaultTimeoutSeconds}s`,
            "--memory", String(serverConfig.defaultMemoryMB),
            "--cpus", String(serverConfig.defaultCpus),
            "--pids-limit", String(serverConfig.defaultPidsLimit),
            "--network", serverConfig.defaultNetworkMode,
            "--read-only", String(serverConfig.defaultReadOnlyRootfs),
            "--container-workdir", serverConfig.defaultContainerWorkdir,
            "--entrypoint", finalEntrypointFilename,
            ...serverConfig.defaultCapDrop.map(cap => ["--cap-drop", cap]).flat(),
        ];
    
        // Add GOCACHE env var specifically for Go
        if (langLower === "go") {
            args.push("--env", "GOCACHE=/tmp");
        }
    
    
        console.error(`Executing: ${serverConfig.isolatorPath} ${args.join(" ")}`);
    
        // --- Execute Go CLI ---
        const executionPromise = new Promise<ExecutionResult>((resolve, reject) => {
            // Use default spawn options, relying on the --env flag now
            const spawnOptions: Parameters<typeof spawn>[2] = { stdio: ["ignore", "pipe", "pipe"], env: process.env };
    
            const child = spawn(serverConfig.isolatorPath, args, spawnOptions);
    
            let stdoutData = "";
            let stderrData = "";
    
            if (child.stdout) {
                child.stdout.on("data", (data) => { stdoutData += data.toString(); });
            } else {
                console.error("Warning: child.stdout is null");
            }
    
            if (child.stderr) {
                child.stderr.on("data", (data) => {
                    stderrData += data.toString();
                    console.error("isolator CLI stderr:", data.toString());
                });
            } else {
                 console.error("Warning: child.stderr is null");
            }
    
            child.on("error", (err) => {
                console.error("Failed to start isolator CLI:", err);
                reject(new Error(`Failed to start isolator process: ${err.message}`));
            });
    
            child.on("close", (code) => {
                console.error(`isolator CLI exited with code ${code}`);
                try {
                    const result: ExecutionResult = JSON.parse(stdoutData);
                    resolve(result);
                } catch (parseError) {
                     console.error("Failed to parse isolator JSON output:", parseError);
                     console.error("isolator stdout:", stdoutData);
                     resolve({
                         status: "error",
                         exitCode: code ?? -1,
                         stdout: stdoutData,
                         stderr: stderrData,
                         durationMs: 0,
                         error: `Failed to parse execution result from isolator CLI. Exit code: ${code}. ${parseError instanceof Error ? parseError.message : String(parseError)}`
                     });
                }
            });
        });
    
        const result = await executionPromise;
    
        // --- Format MCP Result ---
        const outputText = `--- stdout ---\n${result.stdout}\n--- stderr ---\n${result.stderr}`;
        const content: TextContent = { type: "text", text: outputText };
        const callResult: CallToolResult = { content: [content] };
    
        if (result.status !== "success") {
            callResult.isError = true;
            content.text = `Execution Failed (${result.status}): ${result.error || 'Unknown error'}\n\n` + content.text;
        }
    
        return callResult;
    
      } catch (error) {
        console.error("Error during execute_code handling:", error);
        throw new McpError(ErrorCode.InternalError, `Failed to execute code: ${error instanceof Error ? error.message : String(error)}`);
      } finally {
        // --- Cleanup Temporary Directory ---
        if (tempDir) {
          try {
            await fs.rm(tempDir, { recursive: true, force: true });
            console.error(`Cleaned up temp directory: ${tempDir}`);
          } catch (cleanupError) {
            console.error(`Error cleaning up temp directory ${tempDir}:`, cleanupError);
          }
        }
      }
    });
  • Zod schemas for validating the input parameters of the 'execute_code' tool: additionalFileSchema and the main executeCodeInputSchema with refinement for mutual exclusivity between snippet_name and direct code inputs.
    const additionalFileSchema = z.object({
        filename: z.string().describe("Name of the file (including extension)"),
        content: z.string().describe("Content of the file"),
    });
    
    // Input schema allowing either direct code OR a snippet name
    const executeCodeInputSchema = z.object({
      language: z.string().optional().describe("The programming language (python, go, javascript). Required unless using snippet_name."),
      entrypoint_code: z.string().optional().describe("The main code content to execute. Required unless using snippet_name."),
      entrypoint_filename: z.string().optional().describe("Optional filename for the main code (defaults based on language)"),
      additional_files: z.array(additionalFileSchema).optional().describe("Optional array of additional files needed for execution"),
      snippet_name: z.string().optional().describe("Name of a pre-defined code snippet to execute (e.g., 'hello_world'). Mutually exclusive with entrypoint_code/language.")
    }).refine(data => (data.snippet_name && !data.entrypoint_code && !data.language) || (!data.snippet_name && data.entrypoint_code && data.language), {
      message: "Either 'snippet_name' or BOTH 'entrypoint_code' and 'language' must be provided, but not both sets.",
    });
  • src/index.ts:106-155 (registration)
    Registration of the 'execute_code' tool in the ListToolsRequestHandler, providing name, description, and inputSchema for MCP tool discovery.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: "execute_code",
            description: "Executes code (Python, Go, JavaScript) in a secure, isolated container environment.",
            inputSchema: {
              type: "object",
              properties: {
                language: {
                  type: "string",
                  description: "The programming language (python, go, javascript). Required unless using snippet_name."
                },
                entrypoint_code: {
                  type: "string",
                  description: "The main code content to execute. Required unless using snippet_name."
                },
                entrypoint_filename: {
                  type: "string",
                  description: "Optional filename for the main code (defaults based on language)."
                },
                additional_files: {
                  type: "array",
                  description: "Optional array of additional files needed for execution",
                  items: {
                    type: "object",
                    properties: {
                      filename: {
                        type: "string",
                        description: "Name of the file (including extension)"
                      },
                      content: {
                        type: "string",
                        description: "Content of the file"
                      },
                    },
                    required: ["filename", "content"],
                  },
                },
                snippet_name: {
                  type: "string",
                  description: "Name of a pre-defined code snippet to execute (e.g., 'hello_world'). Mutually exclusive with entrypoint_code/language.",
                },
              },
              // Rely on Zod validation in the handler for mutual exclusivity.
            },
          },
        ],
      };
    });
Install Server

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/Ompragash/isolator-mcp'

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