npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@prodisco/sandbox-server

v0.1.6

Published

gRPC sandbox server for code execution with Kubernetes context

Readme

@prodisco/sandbox-server

A gRPC-based sandbox server for secure TypeScript/JavaScript code execution with Kubernetes and Prometheus context. Designed to decouple code execution from MCP servers, enabling flexible deployment options and improved isolation.

Table of Contents

Features

  • Secure Sandboxed Execution - Run untrusted code in Node.js VM with restricted module access
  • TypeScript Support - Execute TypeScript directly with esbuild transformation
  • Multiple Execution Modes - Synchronous, streaming, async, and test execution
  • Unit Testing - Built-in test runner with structured results using uvu assertions
  • Kubernetes Integration - Pre-configured access to @kubernetes/client-node
  • Prometheus/Loki Support - Query metrics and logs from within scripts
  • Script Caching - Automatic caching with content-based deduplication
  • Flexible Transport - Unix socket (default) or TCP with optional TLS/mTLS
  • Container Ready - Dockerfile and Kubernetes manifests included

Installation

npm install @prodisco/sandbox-server

Quick Start

Starting the Server

# Using the CLI
npx sandbox-server

# Or programmatically
import { startServer } from '@prodisco/sandbox-server/server';

const server = await startServer({
  socketPath: '/tmp/prodisco-sandbox.sock',
  cacheDir: '/tmp/prodisco-scripts',
});

Using the Client

import { SandboxClient } from '@prodisco/sandbox-server/client';

const client = new SandboxClient();

// Simple execution
const result = await client.execute({
  code: `
    const k8s = require('@kubernetes/client-node');
    console.log('Kubernetes client loaded:', typeof k8s.CoreV1Api);
  `,
  timeoutMs: 30000,
});

console.log(result.success);  // true
console.log(result.output);   // "Kubernetes client loaded: function"

Execution Modes

| Mode | Method | Use Case | |------|--------|----------| | Synchronous | execute() | Simple scripts, short execution time | | Streaming | executeStream() | Real-time output, long-running scripts | | Async | executeAsync() | Background execution with polling | | Test | executeTest() | Unit testing with structured results |

Synchronous Execution

const result = await client.execute({
  code: 'console.log("Hello, World!");',
  timeoutMs: 30000,
});

// Result:
// {
//   success: true,
//   output: "Hello, World!",
//   executionTimeMs: 45
// }

Streaming Execution

for await (const chunk of client.executeStream({ code: longRunningScript })) {
  if (chunk.type === 'output') {
    process.stdout.write(chunk.data);
  } else if (chunk.type === 'error') {
    process.stderr.write(chunk.data);
  } else if (chunk.type === 'result') {
    console.log('Finished:', chunk.data.success);
  }
}

Async Execution with Polling

// Start execution
const { executionId } = await client.executeAsync({
  code: `
    for (let i = 0; i < 10; i++) {
      console.log("Processing:", i);
      await new Promise(r => setTimeout(r, 100));
    }
  `,
});

// Poll for status
const status = await client.getExecution(executionId, { wait: true });
console.log(status.state);  // 'completed'
console.log(status.output); // Processing output

// Or cancel if needed
await client.cancelExecution(executionId);

Test Execution

Run unit tests with structured results using the built-in uvu test framework:

const result = await client.executeTest({
  code: `
    function fibonacci(n: number): number[] {
      if (n <= 0) return [];
      if (n === 1) return [0];
      const seq = [0, 1];
      for (let i = 2; i < n; i++) {
        seq.push(seq[i-1] + seq[i-2]);
      }
      return seq;
    }
  `,
  tests: `
    test("fibonacci(0) returns empty array", () => {
      assert.equal(fibonacci(0), []);
    });

    test("fibonacci(5) returns correct sequence", () => {
      assert.equal(fibonacci(5), [0, 1, 1, 2, 3]);
    });

    test("each number is sum of previous two", () => {
      const seq = fibonacci(10);
      for (let i = 2; i < seq.length; i++) {
        assert.is(seq[i], seq[i-1] + seq[i-2]);
      }
    });
  `,
});

// Result:
// {
//   success: true,
//   summary: { total: 3, passed: 3, failed: 0, skipped: 0 },
//   tests: [
//     { name: 'fibonacci(0) returns empty array', passed: true, durationMs: 0 },
//     { name: 'fibonacci(5) returns correct sequence', passed: true, durationMs: 0 },
//     { name: 'each number is sum of previous two', passed: true, durationMs: 1 }
//   ],
//   executionTimeMs: 45
// }

Important: In test mode, test() and assert are pre-injected globals. Do NOT import them.

Available Assertions:

| Assertion | Description | |-----------|-------------| | assert.is(a, b) | Strict equality (===) | | assert.equal(a, b) | Deep equality for objects/arrays | | assert.ok(val) | Truthy check | | assert.not(val) | Falsy check | | assert.throws(fn) | Expects function to throw |

Sandbox Environment

Allowed Modules

By default, the sandbox allows these modules:

  • @kubernetes/client-node - Kubernetes API client
  • @prodisco/prometheus-client - Prometheus metrics queries
  • @prodisco/loki-client - Loki log queries
  • simple-statistics - Statistical analysis functions
  • uvu - Test framework (always available for test mode)

Available Globals

// Console methods
console.log(), console.error(), console.warn(), console.info()

// Timers
setTimeout, setInterval, clearTimeout, clearInterval

// Built-ins
Promise, JSON, Buffer, Date, Math, Array, Object, String, Number, Boolean, Error

// Environment
process.env  // Read-only access to environment variables

Custom Module Configuration

Configure allowed modules via environment variable or config file:

# Environment variable (JSON array or comma-separated)
export SANDBOX_ALLOWED_MODULES='["@kubernetes/client-node","lodash"]'

# Or via config file
export PRODISCO_CONFIG_PATH=/path/to/config.yaml

Config file format:

libraries:
  - name: "@kubernetes/client-node"
    description: "Kubernetes API client"
  - name: "lodash"
    description: "Utility library"

Configuration

Environment Variables

| Variable | Default | Description | |----------|---------|-------------| | SANDBOX_SOCKET_PATH | /tmp/prodisco-sandbox.sock | Unix socket path | | SANDBOX_USE_TCP | false | Use TCP instead of Unix socket | | SANDBOX_TCP_HOST | 0.0.0.0 / localhost | TCP host (server/client) | | SANDBOX_TCP_PORT | 50051 | TCP port | | SCRIPTS_CACHE_DIR | /tmp/prodisco-scripts | Cache directory | | SANDBOX_ALLOWED_MODULES | (see above) | Allowed require() modules | | SANDBOX_MODULES_BASE_PATH | process.cwd() | node_modules resolution base |

Transport Security

| Variable | Description | |----------|-------------| | SANDBOX_TRANSPORT_MODE | insecure, tls, or mtls | | SANDBOX_TLS_CERT_PATH | Server certificate path | | SANDBOX_TLS_KEY_PATH | Server private key path | | SANDBOX_TLS_CA_PATH | CA certificate path | | SANDBOX_TLS_CLIENT_CERT_PATH | Client cert (mTLS) | | SANDBOX_TLS_CLIENT_KEY_PATH | Client key (mTLS) |

API Reference

SandboxClient

class SandboxClient {
  constructor(options?: SandboxClientOptions);

  // Synchronous execution
  execute(options: ExecuteOptions): Promise<ExecuteResult>;

  // Streaming execution
  executeStream(options: ExecuteOptions): AsyncGenerator<StreamChunk>;
  executeStreamWithAbort(options: ExecuteOptions, signal?: AbortSignal): AsyncGenerator<StreamChunk>;

  // Async execution
  executeAsync(options: ExecuteOptions): Promise<{ executionId: string; state: ExecutionState }>;
  getExecution(id: string, options?: GetExecutionOptions): Promise<ExecutionStatus>;
  waitForExecution(id: string): Promise<ExecutionStatus>;
  cancelExecution(id: string): Promise<CancelResult>;
  listExecutions(options?: ListOptions): Promise<ExecutionSummary[]>;

  // Test execution
  executeTest(options: ExecuteTestOptions): Promise<TestExecutionResult>;

  // Cache management
  listCache(filter?: string): Promise<CacheEntry[]>;
  clearCache(): Promise<number>;

  // Health check
  healthCheck(): Promise<{ healthy: boolean; kubernetesContext: string }>;
  waitForHealthy(timeoutMs: number): Promise<boolean>;

  close(): void;
}

Singleton Pattern

import { getSandboxClient, closeSandboxClient } from '@prodisco/sandbox-server/client';

// Get or create shared client instance
const client = getSandboxClient({ socketPath: '/tmp/sandbox.sock' });

// Close when done
closeSandboxClient();

Docker & Kubernetes Deployment

Building the Container

docker build -f packages/sandbox-server/Dockerfile -t prodisco/sandbox-server:latest .

Kubernetes Deployment

# Deploy to cluster
kubectl apply -f packages/sandbox-server/k8s/deployment.yaml

# Port forward for local access
kubectl -n prodisco port-forward service/sandbox-server 50051:50051

Connecting to Containerized Server

// Via port-forward
const client = new SandboxClient({
  useTcp: true,
  tcpHost: 'localhost',
  tcpPort: 50051,
});

// Via in-cluster DNS
const client = new SandboxClient({
  useTcp: true,
  tcpHost: 'sandbox-server.prodisco.svc.cluster.local',
  tcpPort: 50051,
});

Development

Building

npm run build

Running Tests

# All tests
npm test

# Watch mode
npm run test:watch

# Security tests
npm run test:security

# E2E tests (requires kind cluster)
npm run test:e2e:setup
npm run test:e2e
npm run test:e2e:teardown

Regenerating Protobuf Types

npm run proto:generate

Development Server

npm run dev

Protocol

The gRPC service is defined in proto/sandbox.proto. Key RPCs:

service SandboxService {
  rpc Execute(ExecuteRequest) returns (ExecuteResponse);
  rpc ExecuteStream(ExecuteRequest) returns (stream ExecuteChunk);
  rpc ExecuteAsync(ExecuteRequest) returns (ExecuteAsyncResponse);
  rpc GetExecution(GetExecutionRequest) returns (GetExecutionResponse);
  rpc CancelExecution(CancelExecutionRequest) returns (CancelExecutionResponse);
  rpc ListExecutions(ListExecutionsRequest) returns (ListExecutionsResponse);
  rpc ExecuteTest(ExecuteTestRequest) returns (ExecuteTestResponse);
  rpc HealthCheck(HealthCheckRequest) returns (HealthCheckResponse);
  rpc ListCache(ListCacheRequest) returns (ListCacheResponse);
  rpc ClearCache(ClearCacheRequest) returns (ClearCacheResponse);
}

Architecture

See docs/grpc-sandbox-architecture.md for detailed architecture documentation.

+---------------------------------------------------------------------+
|                         MCP Server                                   |
|  +-------------------+    +--------------------------------------+   |
|  | searchTools       |    | runSandbox Tool                      |   |
|  | (API discovery)   |    | (thin gRPC client wrapper)           |   |
|  +-------------------+    +------------------+-------------------+   |
|                                              |                       |
+----------------------------------------------+-----------------------+
                                               | gRPC over Unix Socket
                                               v
+---------------------------------------------------------------------+
|                     Sandbox gRPC Server                              |
|  +---------------------------------------------------------------+   |
|  | SandboxService                                                 |   |
|  | (Execute, ExecuteStream, ExecuteAsync, ExecuteTest, ...)      |   |
|  +---------------------------------------------------------------+   |
|                              |                                       |
|  +----------------+  +-------+--------+  +----------------------+    |
|  | Executor       |  | Execution      |  | CacheManager         |    |
|  | (VM + esbuild) |  | Registry       |  | (dedup, persist)     |    |
|  +----------------+  +----------------+  +----------------------+    |
+---------------------------------------------------------------------+

License

MIT