Skip to main content
Glama
mozicim

Node Code Sandbox MCP

by mozicim

run_js_ephemeral

Execute JavaScript code in a temporary container with optional npm dependencies, then automatically clean up. Use for one-shot executions without maintaining sandboxes or managing cleanup manually.

Instructions

Run a JavaScript snippet in a temporary disposable container with optional npm dependencies, then automatically clean up. The code must be valid ESModules (import/export syntax). Ideal for simple one-shot executions without maintaining a sandbox or managing cleanup manually. When reading and writing from the Node.js processes, you always need to read from and write to the "./files" directory to ensure persistence on the mounted volume. This includes images (e.g., PNG, JPEG) and other files (e.g., text, JSON, binaries).

Example:

import fs from "fs/promises";
await fs.writeFile("./files/hello.txt", "Hello world!");
console.log("Saved ./files/hello.txt");

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
imageNoDocker image to use for ephemeral execution. e.g. - **node:lts-slim**: Node.js LTS version, slim variant. (Lightweight and fast for JavaScript execution tasks.) - **mcr.microsoft.com/playwright:v1.52.0-noble**: Playwright image for browser automation. (Preconfigured for running Playwright scripts.) - **alfonsograziano/node-chartjs-canvas:latest**: Chart.js image for chart generation and mermaid charts generation. ('Preconfigured for generating charts with chartjs-node-canvas and Mermaid. Minimal Mermaid example: import fs from "fs"; import { run } from "@mermaid-js/mermaid-cli"; fs.writeFileSync("./files/diagram.mmd", "graph LR; A-->B;", "utf8"); await run("./files/diagram.mmd", "./files/diagram.svg");)node:lts-slim
dependenciesNoA list of npm dependencies to install before running the code. Each item must have a `name` (package) and `version` (range). If none, returns an empty array.
codeYesJavaScript code to run inside the ephemeral container.

Implementation Reference

  • Main handler function that spins up an ephemeral Docker container, installs dependencies, runs the provided JavaScript code, captures output and file changes, and cleans up.
    export default async function runJsEphemeral({
      image = DEFAULT_NODE_IMAGE,
      code,
      dependencies = [],
    }: {
      image?: string;
      code: string;
      dependencies?: NodeDependenciesArray;
    }): Promise<McpResponse> {
      if (!isDockerRunning()) {
        return { content: [textContent(DOCKER_NOT_RUNNING_ERROR)] };
      }
    
      const telemetry: Record<string, unknown> = {};
      const dependenciesRecord = preprocessDependencies({ dependencies, image });
      const containerId = `js-ephemeral-${randomUUID()}`;
      const tmpDir = tmp.dirSync({ unsafeCleanup: true });
      const { memFlag, cpuFlag } = computeResourceLimits(image);
    
      try {
        // Start an ephemeral container
        execSync(
          `docker run -d --network host ${memFlag} ${cpuFlag} ` +
            `--workdir /workspace -v ${getFilesDir()}:/workspace/files ` +
            `--name ${containerId} ${image} tail -f /dev/null`
        );
    
        // Prepare workspace locally
        const localWorkspace = await prepareWorkspace({ code, dependenciesRecord });
        execSync(`docker cp ${localWorkspace.name}/. ${containerId}:/workspace`);
    
        // Generate snapshot of the workspace
        const snapshotStartTime = Date.now();
        const snapshot = await getSnapshot(getMountPointDir());
    
        // Run install and script inside container
        const installCmd =
          'npm install --omit=dev --prefer-offline --no-audit --loglevel=error';
    
        if (dependencies.length > 0) {
          const installStart = Date.now();
          const installOutput = execSync(
            `docker exec ${containerId} /bin/sh -c ${JSON.stringify(installCmd)}`,
            { encoding: 'utf8' }
          );
          telemetry.installTimeMs = Date.now() - installStart;
          telemetry.installOutput = installOutput;
        } else {
          telemetry.installTimeMs = 0;
          telemetry.installOutput = 'Skipped npm install (no dependencies)';
        }
    
        const { output, error, duration } = safeExecNodeInContainer({
          containerId,
        });
        telemetry.runTimeMs = duration;
        if (error) return getContentFromError(error, telemetry);
    
        // Detect the file changed during the execution of the tool in the mounted workspace
        // and report the changes to the user
        const changes = await detectChanges(
          snapshot,
          getMountPointDir(),
          snapshotStartTime
        );
    
        const extractedContents = await changesToMcpContent(changes);
    
        return {
          content: [
            textContent(`Node.js process output:\n${output}`),
            ...extractedContents,
            textContent(`Telemetry:\n${JSON.stringify(telemetry, null, 2)}`),
          ],
        };
      } finally {
        execSync(`docker rm -f ${containerId}`);
        tmpDir.removeCallback();
      }
    }
  • Zod schema defining input parameters: optional image, array of dependencies (name/version), and code string.
    export const argSchema = {
      image: z
        .string()
        .optional()
        .default(DEFAULT_NODE_IMAGE)
        .describe(
          'Docker image to use for ephemeral execution. e.g. ' +
            generateSuggestedImages()
        ),
      // We use an array of { name, version } items instead of a record
      // because the OpenAI function-calling schema doesn’t reliably support arbitrary
      // object keys. An explicit array ensures each dependency has a clear, uniform
      // structure the model can populate.
      // Schema for a single dependency item
      dependencies: z
        .array(NodeDependency)
        .default([])
        .describe(
          'A list of npm dependencies to install before running the code. ' +
            'Each item must have a `name` (package) and `version` (range). ' +
            'If none, returns an empty array.'
        ),
      code: z
        .string()
        .describe('JavaScript code to run inside the ephemeral container.'),
    };
  • src/server.ts:82-98 (registration)
    Registration of the 'run_js_ephemeral' tool on the MCP server using server.tool, linking name, description, schema, and handler.
    server.tool(
      'run_js_ephemeral',
      `Run a JavaScript snippet in a temporary disposable container with optional npm dependencies, then automatically clean up. 
      The code must be valid ESModules (import/export syntax). Ideal for simple one-shot executions without maintaining a sandbox or managing cleanup manually.
      When reading and writing from the Node.js processes, you always need to read from and write to the "./files" directory to ensure persistence on the mounted volume.
      This includes images (e.g., PNG, JPEG) and other files (e.g., text, JSON, binaries).
    
      Example:
      \`\`\`js
      import fs from "fs/promises";
      await fs.writeFile("./files/hello.txt", "Hello world!");
      console.log("Saved ./files/hello.txt");
      \`\`\`
    `,
      ephemeralSchema,
      runJsEphemeral
    );
  • src/server.ts:16-18 (registration)
    Import of the runJsEphemeral handler and its schema (ephemeralSchema) from the implementation file.
    import runJsEphemeral, {
      argSchema as ephemeralSchema,
    } from './tools/runJsEphemeral.ts';

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/mozicim/node-code-sandbox-mcp'

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