VoidRun is a Go API server for managing sandboxes with file operations, command execution, PTY sessions, and organization/API key management. It exposes a REST API (with WebSocket streams for PTY and file watching) and persists state in MongoDB.
- Sandbox lifecycle management (create, list, delete)
- Command execution (sync + streaming) and background processes
- File system operations (upload, download, list, compress, watch)
- PTY sessions (ephemeral and persistent)
- Org + API key management
- OpenAPI spec included
- Linux host with KVM support
cloud-hypervisorinstalled on the host at/usr/local/bin/cloud-hypervisor- MongoDB (Docker Compose provided)
iptablesand bridge networking tools available on the host
cd /root/workspace/vr-work/voidrun
docker compose up --buildThe API is exposed on http://localhost:8080/api when using Docker Compose.
The server expects a Linux bridge for sandbox networking. The setup-net tool configures the bridge and NAT.
go run ./cmd/setup-netdocker run -d --name voidrun-mongo -p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=root \
-e MONGO_INITDB_ROOT_PASSWORD=Qaz123wsx123 \
-e MONGO_INITDB_DATABASE=vr-db \
mongo:7.0-alpinego run ./cmd/serverBy default the server listens on :33944. Set SERVER_PORT to change it.
- Register a user and get a default org + API key.
- Authenticate with either:
X-API-Key(org is derived from the key and cannot be overridden), orAuthorization: Bearer <jwt>plusX-Org-IDfor org context.
- All resource access is tenant-scoped by validated
orgId.
curl -X POST http://localhost:8080/api/register \
-H 'Content-Type: application/json' \
-d '{"name":"Admin","email":"admin@example.com"}'curl http://localhost:8080/api/sandboxes \
-H 'X-API-Key: hf_your_key_here'curl http://localhost:8080/api/sandboxes \
-H 'Authorization: Bearer <jwt_token>' \
-H 'X-Org-ID: <org_object_id>'- Docker Compose:
http://localhost:8080/api - Local default:
http://localhost:33944/api
The full OpenAPI spec is in openapi.yml.
The API exposes a Streamable HTTP MCP endpoint at POST /api/mcp (same auth as the REST API: X-API-Key or Bearer JWT + X-Org-ID). Tool handlers manage sandboxes, exec, and files in 14:54:voidrun/mcp/server.go.
-
Start the API (Docker Compose on 8080, or local
go runand setSERVER_PORTif not using 8080). -
Export a valid API key in the environment Cursor inherits (desktop launchers often do not load shell rc files):
export VOIDRUN_API_KEY="hf_your_key_here"
-
Project config lives at
.cursor/mcp.jsonin this repo. Edit theurlif your server is not athttp://127.0.0.1:8080/api/mcp(for examplehttp://127.0.0.1:33944/api/mcpfor the default local port). -
Reload MCP in Cursor (Settings → MCP) and confirm voidrun connects. Check Output → MCP if initialization fails.
Secrets should stay in ${env:VOIDRUN_API_KEY}; do not commit real keys. For Clerk JWT instead of an API key, Cursor’s static headers map is awkward for short-lived tokens; prefer an API key for this integration.
-
MCP Inspector (recommended) — Official UI and CLI for Streamable HTTP. Requires Node ^22.7.5 per modelcontextprotocol/inspector.
-
UI:
npx @modelcontextprotocol/inspector→ open http://localhost:6274, choose transport streamable-http, set server URL to your/api/mcpendpoint (query shortcut:?transport=streamable-http&serverUrl=http://127.0.0.1:8080/api/mcp). Configure auth soX-API-Keyis sent (use the sidebar auth / header options; Inspector documents Bearer for SSE, but CLI below supports arbitrary headers). -
CLI (scriptable / CI-friendly):
npx @modelcontextprotocol/inspector --cli http://127.0.0.1:8080/api/mcp \ --transport http \ --header "X-API-Key: hf_your_key_here" \ --method tools/listUse
--method tools/callwith--tool-name/--tool-argto exercise a specific tool.
-
-
Raw HTTP — Any client that can send
Content-Type: application/jsonJSON-RPC toPOST /api/mcp, plusX-API-Key, then reuseMcp-Session-Idfrom theinitializeresponse on later POSTs (see mark3labs/mcp-gostreamable_http_test.gofor request shapes). -
API platforms — Bruno, Insomnia, or Postman: run
initialize, captureMcp-Session-Id, thentools/list/tools/callin separate requests with the same header. -
Automated tests in-repo — There is no dedicated
voidrun/mcp/*_test.goyet; you can add an integration test that builds the Gin router (or useshttptest) and posts the same JSON-RPC sequence, or call the Inspector CLI from a shell script in CI.
All previously internal/* and pkg/* packages are now top-level public packages for extension use-cases (for example from voidrun-ee):
voidrun/configvoidrun/servervoidrun/servicevoidrun/repositoryvoidrun/middlewarevoidrun/modelvoidrun/machinevoidrun/storagevoidrun/util
The server reads configuration from environment variables. Common options:
SERVER_PORT=33944
SERVER_HOST=
MONGO_URI=mongodb://root:Qaz123wsx123@localhost:27017/vr-db?authSource=admin
MONGO_DB=vr-db
BASE_IMAGES_DIR=/var/lib/voidrun/base-images
INSTANCES_DIR=/var/lib/voidrun/instances
KERNEL_PATH=/var/lib/voidrun/base-images/vmlinux
BRIDGE_NAME=vmbr0
GATEWAY_IP=192.168.100.1/22
NETWORK_CIDR=192.168.100.0/22
SUBNET_PREFIX=192.168.100.
SYSTEM_USER_NAME=System
SYSTEM_USER_EMAIL=system@local
SANDBOX_DEFAULT_VCPUS=1
SANDBOX_DEFAULT_MEMORY_MB=1024
SANDBOX_DEFAULT_DISK_MB=5120
SANDBOX_DEFAULT_IMAGE=debian
HEALTH_ENABLED=true
HEALTH_INTERVAL_SEC=60
HEALTH_CONCURRENCY=16
API_KEY_CACHE_TTL_SECONDS=3600
JWT_SECRET=change-me-in-production
POST /api/register- create user, org, and API keyGET /api/sandboxes- list sandboxesPOST /api/sandboxes- create sandboxGET /api/sandboxes/{id}- get sandboxDELETE /api/sandboxes/{id}- delete sandboxPOST /api/sandboxes/{id}/exec- execute commandPOST /api/sandboxes/{id}/exec-stream- stream exec outputPOST /api/sandboxes/{id}/pty/sessions- create PTY sessionGET /api/sandboxes/{id}/files- list filesPOST /api/sandboxes/{id}/files/upload- upload fileGET /api/sandboxes/{id}/files/watch/{sessionId}/stream- watch file events (WS)
See openapi.yml for full details.
- If the server fails to start, verify MongoDB connectivity and KVM support.
- PTY and file watch use WebSockets; ensure your proxy allows WS upgrades.
- Sandbox networking issues usually indicate missing bridge or iptables rules.
Proprietary