Skip to main content
Glama
README.md
# runloop-mcp

An MCP server for **running and testing code in disposable Runloop sandboxes**.
It remains focused on testing rather than vibe coding: active Devboxes last at
most one hour and local files should be treated as temporary. Snapshots,
blueprints and suspend/resume are available for repeatable test environments;
interactive PTYs, tunnels, account secrets and MCP Hub administration are not.

## Tools

| Tool | Purpose |
| --- | --- |
| `run_code` | Reuse a compatible running sandbox, or create one, then run a command |
| `create_sandbox` | Start a sandbox for a multi-step test, capped at 1 hour |
| `list_sandbox` | List sandboxes while excluding shutdown entries |
| `get_sandbox` | Check sandbox status |
| `suspend_sandbox` / `resume_sandbox` | Preserve and restore sandbox disk state |
| `execute_in_sandbox` | Run a blocking, non-interactive command |
| `upload_test_file` | Upload Base64 test input or source files |
| `download_artifact` | Export a result before the sandbox disappears |
| `get_sandbox_usage` | Inspect CPU, memory, disk, and usage |
| `shutdown_sandbox` | Destroy a sandbox and its remaining data |
| `create_snapshot` / `list_snapshot` | Save and discover reusable disk states |
| `build_blueprint` / `list_blueprint` | Build and discover reusable test images |

Prefer `run_code`. It searches running code-testing sandboxes first and retains
the selected sandbox after a successful run for later reuse. Use
`shutdown_sandbox` when reuse is no longer needed.

## Installation

Requires Python 3.10+ and a Runloop API key.

```bash
pip install -e .
```

## Start

HTTP (default):

```bash
runloop-mcp --host 127.0.0.1 --port 8000
```

stdio:

```bash
RUNLOOP_API_KEY=... runloop-mcp --transport stdio
```

The HTTP MCP endpoint is `/mcp`. Supply the API key when connecting:

```text
http://127.0.0.1:8000/mcp?api_key=YOUR_RUNLOOP_API_KEY
```

Do not log or share URLs containing the key. Query-key behavior remains for
compatibility, but a secret-aware proxy is recommended for public deployment.

## Examples

One-shot Python test:

```python
run_code(
    files={
        "/home/user/test_app.py": "assert 2 + 2 == 4\nprint('passed')\n"
    },
    command="python3 /home/user/test_app.py",
)
```

Multi-step test with an exported report:

```python
sandbox = create_sandbox(files={"/home/user/package.json": "{...}"})
execute_in_sandbox(sandbox_id=sandbox["id"], command="cd /home/user && npm test")
download_artifact(sandbox_id=sandbox["id"], file_path="/home/user/report.xml")
shutdown_sandbox(sandbox_id=sandbox["id"])
```

`download_artifact` returns standard Base64. Decode and save it outside Runloop
before shutdown or expiry. Package large source trees into an archive, upload
it, and extract it with `execute_in_sandbox`.

## Reuse behavior

- `run_code` only reuses running sandboxes tagged with `purpose=code-testing`.
- It prefers a sandbox matching the requested blueprint.
- Files passed to `run_code` overwrite paths in a reused sandbox.
- Environment variables are creation-time settings and cannot be replaced when
    reusing a sandbox; put per-run values in the command when appropriate.
- A newly created sandbox is destroyed if execution raises an error, but is
    retained after success.

## Design constraints

- Sandbox lifetime is restricted to 60–3600 seconds.
- `run_code` attempts forced cleanup of a newly created sandbox on execution failure.
- No background-process, PTY, or tunnel workflow is exposed.
- Sandbox storage must not be treated as a source of truth.
- Avoid passing credentials in ordinary environment variables or command text.

## Deployment

`main.py` exposes MCP at `/mcp` and health checks at `/health`:

```bash
uvicorn main:app --host 0.0.0.0 --port 8000
```

The included `Dockerfile` uses the same ASGI application.

## License

[MIT](LICENSE)

TDQS

A3.9/5.0

Scored across 16 tools

Disambiguation5/5

Each tool maps to a distinct resource and action. The three command execution tools are clearly differentiated by blocking vs async vs interactive PTY, and the PTY tools have separate connect/send/control roles. No two tools appear to do the same thing.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern (e.g., create_devbox, list_devboxes, write_file, pty_connect). The PTY tools use a common pty_ prefix, and the async variant uses a clear _async suffix.

Tool Count5/5

16 tools cover the devbox lifecycle, file operations, snapshots, and PTY interactivity without redundancy. Even though slightly above the typical range, each tool serves a distinct purpose and the set feels well-scoped.

Completeness3/5

Core devbox lifecycle is fully covered (create/get/list/update/suspend/resume/delete). However, there are notable gaps: no way to retrieve results from execute_command_async (no polling/status tool), and no delete operation for snapshots. These are workable but missing.

Maintenance

ActivityMaintained
ResponsivenessSyncing