hyperbox-mcp 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hyperbox_mcp-0.2.1/LICENSE +21 -0
- hyperbox_mcp-0.2.1/PKG-INFO +227 -0
- hyperbox_mcp-0.2.1/PYPI.md +196 -0
- hyperbox_mcp-0.2.1/README.md +158 -0
- hyperbox_mcp-0.2.1/pyproject.toml +57 -0
- hyperbox_mcp-0.2.1/setup.cfg +4 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/__init__.py +0 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/builder.py +90 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/cli.py +164 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/clientconfig.py +203 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/doctor.py +427 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/engine.py +727 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/filelock.py +114 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/llm_sandbox_runtime.py +750 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/policy.py +171 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/registry.py +328 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/runtime.py +136 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/server.py +701 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp/validate.py +224 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp.egg-info/PKG-INFO +227 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp.egg-info/SOURCES.txt +23 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp.egg-info/dependency_links.txt +1 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp.egg-info/entry_points.txt +2 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp.egg-info/requires.txt +2 -0
- hyperbox_mcp-0.2.1/src/hyperbox_mcp.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sanjay
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hyperbox-mcp
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: MCP server that runs LLM-generated code in a disposable Docker/Podman container before it touches your real project.
|
|
5
|
+
Author: Sanjay Jat
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Sanjay7089/hyperbox-mcp
|
|
8
|
+
Project-URL: Repository, https://github.com/Sanjay7089/hyperbox-mcp
|
|
9
|
+
Project-URL: Documentation, https://github.com/Sanjay7089/hyperbox-mcp/tree/main/docs
|
|
10
|
+
Project-URL: Issues, https://github.com/Sanjay7089/hyperbox-mcp/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/Sanjay7089/hyperbox-mcp/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: mcp,model-context-protocol,sandbox,docker,podman,llm,agent,code-execution,container
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Software Development :: Testing
|
|
23
|
+
Classifier: Topic :: Security
|
|
24
|
+
Classifier: Topic :: System :: Emulators
|
|
25
|
+
Requires-Python: >=3.11
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: fastmcp<5,>=4.0.2
|
|
29
|
+
Requires-Dist: llm-sandbox[docker,podman]<0.4,>=0.3.44
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# HyperBox
|
|
33
|
+
|
|
34
|
+
**An MCP server that runs LLM-generated code in a disposable container,
|
|
35
|
+
so your agent can test its own work before it touches your project.**
|
|
36
|
+
|
|
37
|
+
Your agent writes code and wants to run it. By default that happens on
|
|
38
|
+
your machine, against your files, with your credentials. Usually fine.
|
|
39
|
+
Occasionally it is `rm -rf`, a global install that breaks another
|
|
40
|
+
project, or a script that quietly talks to production.
|
|
41
|
+
|
|
42
|
+
HyperBox gives the agent somewhere else to run it:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
create_sandbox() → run(code) → run(fixed code) → destroy_sandbox()
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The agent gets real stdout, stderr and exit codes, so it can fix its code
|
|
49
|
+
and try again somewhere that cannot hurt you — and only then touch your
|
|
50
|
+
project.
|
|
51
|
+
|
|
52
|
+
## What your agent gets
|
|
53
|
+
|
|
54
|
+
Three tools, and nothing else:
|
|
55
|
+
|
|
56
|
+
| Tool | What it does |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `create_sandbox(language, backend, environment)` | A persistent, disposable container. Returns a `sandbox_id`. |
|
|
59
|
+
| `run(sandbox_id, code, libraries, timeout)` | Executes code. Returns `{stdout, stderr, exit_code, success, timed_out}`. |
|
|
60
|
+
| `destroy_sandbox(sandbox_id)` | Tears it down. Idempotent, and confirmed against the engine before claiming success. |
|
|
61
|
+
|
|
62
|
+
Plus a `hyperbox://capabilities` resource publishing the exact limits, so
|
|
63
|
+
an agent can read them instead of discovering them by failing.
|
|
64
|
+
|
|
65
|
+
Within one sandbox the filesystem and installed packages persist between
|
|
66
|
+
runs; variables do not, because each run is a fresh process. Write what
|
|
67
|
+
you need to keep to `/work`.
|
|
68
|
+
|
|
69
|
+
## What is enforced
|
|
70
|
+
|
|
71
|
+
Set by the server, not negotiable by the model, and **read back off the
|
|
72
|
+
real container** after creation — so a sandbox is never described as
|
|
73
|
+
limited when it is not:
|
|
74
|
+
|
|
75
|
+
| | |
|
|
76
|
+
|---|---|
|
|
77
|
+
| Memory | 1 GB, OOM-killed with a legible reason |
|
|
78
|
+
| CPU | 1 core |
|
|
79
|
+
| Processes | 128 PIDs |
|
|
80
|
+
| Timeout | 60 s ceiling |
|
|
81
|
+
| Network | detached before any submitted code runs |
|
|
82
|
+
| Host filesystem | never mounted |
|
|
83
|
+
| Container engine socket | never mounted |
|
|
84
|
+
| Scratch space | `/work`, 64 MB tmpfs, discarded with the sandbox |
|
|
85
|
+
|
|
86
|
+
Declared dependencies are the one network exception: they install in a
|
|
87
|
+
separate step that reattaches the network, runs a no-op program with the
|
|
88
|
+
package list, and detaches again before your code runs.
|
|
89
|
+
|
|
90
|
+
## Built on
|
|
91
|
+
|
|
92
|
+
- **[FastMCP](https://pypi.org/project/fastmcp/)** — the MCP server layer
|
|
93
|
+
(stdio, JSON-RPC).
|
|
94
|
+
- **[llm-sandbox](https://pypi.org/project/llm-sandbox/)** — container
|
|
95
|
+
session management, behind a `Runtime` protocol so the execution
|
|
96
|
+
backend stays replaceable.
|
|
97
|
+
- **Docker or Podman** — whichever you have running. Both are supported
|
|
98
|
+
and both pass the full acceptance suite.
|
|
99
|
+
|
|
100
|
+
Two runtime dependencies, no compiled extensions, one `py3-none-any`
|
|
101
|
+
wheel for every platform.
|
|
102
|
+
|
|
103
|
+
## Install
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
pip install hyperbox-mcp
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or, to get an isolated interpreter and a stable executable path — which
|
|
110
|
+
is what an MCP client needs:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
uv tool install hyperbox-mcp # or: pipx install hyperbox-mcp
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Requires **Python 3.11+** and **Docker or Podman** running.
|
|
117
|
+
|
|
118
|
+
Check the machine and fetch the sandbox image once, so a multi-gigabyte
|
|
119
|
+
download never happens inside a client request:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
hyperbox doctor --pull
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Use it: Cursor
|
|
126
|
+
|
|
127
|
+
Generate the config rather than typing it — the failure mode of getting a
|
|
128
|
+
path wrong is silent, with no tools appearing and no error anywhere:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
hyperbox config --format cursor > .vscode/mcp.json
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
That writes:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"servers": {
|
|
139
|
+
"hyperbox": {
|
|
140
|
+
"command": "/Users/you/.local/bin/hyperbox",
|
|
141
|
+
"args": [],
|
|
142
|
+
"env": { "PATH": "/Users/you/.local/bin:/usr/local/bin:/usr/bin:/bin" }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Restart Cursor — MCP configs are read at launch. Then ask it to run
|
|
149
|
+
something:
|
|
150
|
+
|
|
151
|
+
> Use hyperbox to check whether this regex handles the empty string.
|
|
152
|
+
|
|
153
|
+
A typical exchange looks like:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
create_sandbox(language="python")
|
|
157
|
+
→ {"sandbox_id": "6f5eaaefb938", ...}
|
|
158
|
+
|
|
159
|
+
run(sandbox_id="6f5eaaefb938", code="import re; print(re.match(r'^\\d+$', ''))")
|
|
160
|
+
→ {"stdout": "None\n", "exit_code": 0, "success": true}
|
|
161
|
+
|
|
162
|
+
destroy_sandbox(sandbox_id="6f5eaaefb938")
|
|
163
|
+
→ {"status": "destroyed"}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Other clients
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
hyperbox config --format json # Claude Desktop, and most clients
|
|
170
|
+
hyperbox config --format antigravity # Antigravity
|
|
171
|
+
hyperbox config --format yaml # Continue-based clients
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`PATH` in the generated config includes your container CLI's directory,
|
|
175
|
+
because clients launch servers with a trimmed environment and Docker is
|
|
176
|
+
frequently invisible otherwise.
|
|
177
|
+
|
|
178
|
+
## Custom environments
|
|
179
|
+
|
|
180
|
+
Start sandboxes from a heavier image so you do not pay a package install
|
|
181
|
+
every time:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
hyperbox build data-science --custom ./Dockerfile
|
|
185
|
+
hyperbox envs
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Your agent then asks for it by name:
|
|
189
|
+
`create_sandbox(environment="data-science")`. A running server picks up a
|
|
190
|
+
new environment without a restart.
|
|
191
|
+
|
|
192
|
+
Building is a CLI action on purpose. A build runs whatever the Dockerfile
|
|
193
|
+
says — arbitrary commands, as root, with network, under none of a
|
|
194
|
+
sandbox's limits — so an agent can *use* an environment but cannot create
|
|
195
|
+
one.
|
|
196
|
+
|
|
197
|
+
## Where the boundary sits
|
|
198
|
+
|
|
199
|
+
HyperBox is developer containment, not an isolation guarantee:
|
|
200
|
+
|
|
201
|
+
- **Local containers share your host's kernel.** No gVisor, no
|
|
202
|
+
Firecracker, no VM boundary of its own.
|
|
203
|
+
- **Not a multi-tenant boundary.** Do not run untrusted third-party code
|
|
204
|
+
as a service with it.
|
|
205
|
+
- **Code runs as root inside the container.** A non-root user breaks the
|
|
206
|
+
execution backend; that root is confined by the container boundary,
|
|
207
|
+
`no-new-privileges`, and the limits above.
|
|
208
|
+
- **Dependencies come from the public index** and are not vetted.
|
|
209
|
+
|
|
210
|
+
If you need a hard boundary for genuinely adversarial code, you want a VM
|
|
211
|
+
or microVM sandbox, not a local container.
|
|
212
|
+
|
|
213
|
+
## Commands
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
hyperbox Start the MCP server on stdio (default)
|
|
217
|
+
hyperbox doctor Check this machine can run sandboxes
|
|
218
|
+
hyperbox config Print a ready-to-paste MCP client config
|
|
219
|
+
hyperbox envs List environments create_sandbox can use
|
|
220
|
+
hyperbox build <name> Build an environment from a Dockerfile
|
|
221
|
+
hyperbox logs Show the server log
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
MIT licensed. Source, full documentation and issue tracker:
|
|
227
|
+
**[github.com/Sanjay7089/hyperbox-mcp](https://github.com/Sanjay7089/hyperbox-mcp)**
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# HyperBox
|
|
2
|
+
|
|
3
|
+
**An MCP server that runs LLM-generated code in a disposable container,
|
|
4
|
+
so your agent can test its own work before it touches your project.**
|
|
5
|
+
|
|
6
|
+
Your agent writes code and wants to run it. By default that happens on
|
|
7
|
+
your machine, against your files, with your credentials. Usually fine.
|
|
8
|
+
Occasionally it is `rm -rf`, a global install that breaks another
|
|
9
|
+
project, or a script that quietly talks to production.
|
|
10
|
+
|
|
11
|
+
HyperBox gives the agent somewhere else to run it:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
create_sandbox() → run(code) → run(fixed code) → destroy_sandbox()
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The agent gets real stdout, stderr and exit codes, so it can fix its code
|
|
18
|
+
and try again somewhere that cannot hurt you — and only then touch your
|
|
19
|
+
project.
|
|
20
|
+
|
|
21
|
+
## What your agent gets
|
|
22
|
+
|
|
23
|
+
Three tools, and nothing else:
|
|
24
|
+
|
|
25
|
+
| Tool | What it does |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `create_sandbox(language, backend, environment)` | A persistent, disposable container. Returns a `sandbox_id`. |
|
|
28
|
+
| `run(sandbox_id, code, libraries, timeout)` | Executes code. Returns `{stdout, stderr, exit_code, success, timed_out}`. |
|
|
29
|
+
| `destroy_sandbox(sandbox_id)` | Tears it down. Idempotent, and confirmed against the engine before claiming success. |
|
|
30
|
+
|
|
31
|
+
Plus a `hyperbox://capabilities` resource publishing the exact limits, so
|
|
32
|
+
an agent can read them instead of discovering them by failing.
|
|
33
|
+
|
|
34
|
+
Within one sandbox the filesystem and installed packages persist between
|
|
35
|
+
runs; variables do not, because each run is a fresh process. Write what
|
|
36
|
+
you need to keep to `/work`.
|
|
37
|
+
|
|
38
|
+
## What is enforced
|
|
39
|
+
|
|
40
|
+
Set by the server, not negotiable by the model, and **read back off the
|
|
41
|
+
real container** after creation — so a sandbox is never described as
|
|
42
|
+
limited when it is not:
|
|
43
|
+
|
|
44
|
+
| | |
|
|
45
|
+
|---|---|
|
|
46
|
+
| Memory | 1 GB, OOM-killed with a legible reason |
|
|
47
|
+
| CPU | 1 core |
|
|
48
|
+
| Processes | 128 PIDs |
|
|
49
|
+
| Timeout | 60 s ceiling |
|
|
50
|
+
| Network | detached before any submitted code runs |
|
|
51
|
+
| Host filesystem | never mounted |
|
|
52
|
+
| Container engine socket | never mounted |
|
|
53
|
+
| Scratch space | `/work`, 64 MB tmpfs, discarded with the sandbox |
|
|
54
|
+
|
|
55
|
+
Declared dependencies are the one network exception: they install in a
|
|
56
|
+
separate step that reattaches the network, runs a no-op program with the
|
|
57
|
+
package list, and detaches again before your code runs.
|
|
58
|
+
|
|
59
|
+
## Built on
|
|
60
|
+
|
|
61
|
+
- **[FastMCP](https://pypi.org/project/fastmcp/)** — the MCP server layer
|
|
62
|
+
(stdio, JSON-RPC).
|
|
63
|
+
- **[llm-sandbox](https://pypi.org/project/llm-sandbox/)** — container
|
|
64
|
+
session management, behind a `Runtime` protocol so the execution
|
|
65
|
+
backend stays replaceable.
|
|
66
|
+
- **Docker or Podman** — whichever you have running. Both are supported
|
|
67
|
+
and both pass the full acceptance suite.
|
|
68
|
+
|
|
69
|
+
Two runtime dependencies, no compiled extensions, one `py3-none-any`
|
|
70
|
+
wheel for every platform.
|
|
71
|
+
|
|
72
|
+
## Install
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install hyperbox-mcp
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Or, to get an isolated interpreter and a stable executable path — which
|
|
79
|
+
is what an MCP client needs:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
uv tool install hyperbox-mcp # or: pipx install hyperbox-mcp
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Requires **Python 3.11+** and **Docker or Podman** running.
|
|
86
|
+
|
|
87
|
+
Check the machine and fetch the sandbox image once, so a multi-gigabyte
|
|
88
|
+
download never happens inside a client request:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
hyperbox doctor --pull
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Use it: Cursor
|
|
95
|
+
|
|
96
|
+
Generate the config rather than typing it — the failure mode of getting a
|
|
97
|
+
path wrong is silent, with no tools appearing and no error anywhere:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
hyperbox config --format cursor > .vscode/mcp.json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
That writes:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"servers": {
|
|
108
|
+
"hyperbox": {
|
|
109
|
+
"command": "/Users/you/.local/bin/hyperbox",
|
|
110
|
+
"args": [],
|
|
111
|
+
"env": { "PATH": "/Users/you/.local/bin:/usr/local/bin:/usr/bin:/bin" }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Restart Cursor — MCP configs are read at launch. Then ask it to run
|
|
118
|
+
something:
|
|
119
|
+
|
|
120
|
+
> Use hyperbox to check whether this regex handles the empty string.
|
|
121
|
+
|
|
122
|
+
A typical exchange looks like:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
create_sandbox(language="python")
|
|
126
|
+
→ {"sandbox_id": "6f5eaaefb938", ...}
|
|
127
|
+
|
|
128
|
+
run(sandbox_id="6f5eaaefb938", code="import re; print(re.match(r'^\\d+$', ''))")
|
|
129
|
+
→ {"stdout": "None\n", "exit_code": 0, "success": true}
|
|
130
|
+
|
|
131
|
+
destroy_sandbox(sandbox_id="6f5eaaefb938")
|
|
132
|
+
→ {"status": "destroyed"}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Other clients
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
hyperbox config --format json # Claude Desktop, and most clients
|
|
139
|
+
hyperbox config --format antigravity # Antigravity
|
|
140
|
+
hyperbox config --format yaml # Continue-based clients
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`PATH` in the generated config includes your container CLI's directory,
|
|
144
|
+
because clients launch servers with a trimmed environment and Docker is
|
|
145
|
+
frequently invisible otherwise.
|
|
146
|
+
|
|
147
|
+
## Custom environments
|
|
148
|
+
|
|
149
|
+
Start sandboxes from a heavier image so you do not pay a package install
|
|
150
|
+
every time:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
hyperbox build data-science --custom ./Dockerfile
|
|
154
|
+
hyperbox envs
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Your agent then asks for it by name:
|
|
158
|
+
`create_sandbox(environment="data-science")`. A running server picks up a
|
|
159
|
+
new environment without a restart.
|
|
160
|
+
|
|
161
|
+
Building is a CLI action on purpose. A build runs whatever the Dockerfile
|
|
162
|
+
says — arbitrary commands, as root, with network, under none of a
|
|
163
|
+
sandbox's limits — so an agent can *use* an environment but cannot create
|
|
164
|
+
one.
|
|
165
|
+
|
|
166
|
+
## Where the boundary sits
|
|
167
|
+
|
|
168
|
+
HyperBox is developer containment, not an isolation guarantee:
|
|
169
|
+
|
|
170
|
+
- **Local containers share your host's kernel.** No gVisor, no
|
|
171
|
+
Firecracker, no VM boundary of its own.
|
|
172
|
+
- **Not a multi-tenant boundary.** Do not run untrusted third-party code
|
|
173
|
+
as a service with it.
|
|
174
|
+
- **Code runs as root inside the container.** A non-root user breaks the
|
|
175
|
+
execution backend; that root is confined by the container boundary,
|
|
176
|
+
`no-new-privileges`, and the limits above.
|
|
177
|
+
- **Dependencies come from the public index** and are not vetted.
|
|
178
|
+
|
|
179
|
+
If you need a hard boundary for genuinely adversarial code, you want a VM
|
|
180
|
+
or microVM sandbox, not a local container.
|
|
181
|
+
|
|
182
|
+
## Commands
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
hyperbox Start the MCP server on stdio (default)
|
|
186
|
+
hyperbox doctor Check this machine can run sandboxes
|
|
187
|
+
hyperbox config Print a ready-to-paste MCP client config
|
|
188
|
+
hyperbox envs List environments create_sandbox can use
|
|
189
|
+
hyperbox build <name> Build an environment from a Dockerfile
|
|
190
|
+
hyperbox logs Show the server log
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
MIT licensed. Source, full documentation and issue tracker:
|
|
196
|
+
**[github.com/Sanjay7089/hyperbox-mcp](https://github.com/Sanjay7089/hyperbox-mcp)**
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# HyperBox
|
|
2
|
+
|
|
3
|
+
**An MCP server that runs LLM-generated code in a disposable container,
|
|
4
|
+
so your agent can test its own work before it touches your project.**
|
|
5
|
+
|
|
6
|
+
[](https://pypi.org/project/hyperbox-mcp/)
|
|
7
|
+
[](https://pypi.org/project/hyperbox-mcp/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Your agent writes code and wants to run it. By default that happens on
|
|
13
|
+
your machine, against your files, with your credentials. Usually fine.
|
|
14
|
+
Occasionally it is `rm -rf`, a global install that breaks another
|
|
15
|
+
project, or a script that quietly talks to production.
|
|
16
|
+
|
|
17
|
+
HyperBox gives the agent somewhere else to run it.
|
|
18
|
+
|
|
19
|
+
```mermaid
|
|
20
|
+
flowchart LR
|
|
21
|
+
w["agent writes code"] --> c["create_sandbox()"]
|
|
22
|
+
c --> r["run(code)"]
|
|
23
|
+
r -->|"stderr says what broke"| f["run(fixed code)"]
|
|
24
|
+
f --> r
|
|
25
|
+
r -->|"it works"| d["destroy_sandbox()"]
|
|
26
|
+
f -.->|"only now, and only if<br/>you have seen it pass"| host["apply to the real project"]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The loop matters more than any single call: the agent gets real stdout,
|
|
30
|
+
stderr and exit codes, so it can fix its code and try again somewhere
|
|
31
|
+
that cannot hurt you — and only then touch your project.
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install hyperbox-mcp # or: uv tool install hyperbox-mcp
|
|
37
|
+
hyperbox doctor --pull # check the machine, fetch the sandbox image
|
|
38
|
+
hyperbox config --format json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Merge that config into your MCP client and restart it. Full instructions,
|
|
42
|
+
including Cursor, Antigravity and Continue-based clients, are in
|
|
43
|
+
**[docs/setup.md](docs/setup.md)**.
|
|
44
|
+
|
|
45
|
+
Requires Python 3.11+ and either Docker or Podman.
|
|
46
|
+
|
|
47
|
+
## What your agent gets
|
|
48
|
+
|
|
49
|
+
| Tool | What it does |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `create_sandbox(language, backend, environment)` | A persistent, disposable container. Returns a `sandbox_id`. |
|
|
52
|
+
| `run(sandbox_id, code, libraries, timeout)` | Executes code. Returns `{stdout, stderr, exit_code, success, timed_out}` — never a bare "it failed". |
|
|
53
|
+
| `destroy_sandbox(sandbox_id)` | Tears it down. Idempotent, and confirmed against the engine before it claims success. |
|
|
54
|
+
|
|
55
|
+
Plus a `hyperbox://capabilities` resource publishing the exact limits, so
|
|
56
|
+
an agent can read them instead of discovering them by failing.
|
|
57
|
+
|
|
58
|
+
Within one sandbox, the filesystem and installed packages persist between
|
|
59
|
+
runs; variables do not, because each run is a fresh process. Write what
|
|
60
|
+
you need to keep to `/work`.
|
|
61
|
+
|
|
62
|
+
## Why use it
|
|
63
|
+
|
|
64
|
+
- **Generated code runs outside your client's process.** No access to
|
|
65
|
+
your filesystem, your project, or the container engine.
|
|
66
|
+
- **Limits are server policy, not negotiable by the model** — 1 GB
|
|
67
|
+
memory, 1 CPU, 128 processes, a 60-second ceiling, capped output. They
|
|
68
|
+
are read back off the real container, so a sandbox is never *described*
|
|
69
|
+
as limited when it is not.
|
|
70
|
+
- **The network is sealed** before any submitted code runs. Declared
|
|
71
|
+
dependencies install in a separate step that closes again afterwards.
|
|
72
|
+
- **Cleanup survives restarts.** Ownership lives in a registry outside
|
|
73
|
+
your repo, so a restarted server — or a second one your client launched
|
|
74
|
+
— can still find and destroy a sandbox it did not create.
|
|
75
|
+
- **Failure is reported honestly.** An unreachable engine is an error,
|
|
76
|
+
not a cheerful "already cleaned up".
|
|
77
|
+
|
|
78
|
+
## It contains hostile code — the proof, not the promise
|
|
79
|
+
|
|
80
|
+
`tests/verify_containment.py` runs genuinely dangerous code in a real
|
|
81
|
+
container. Actual output:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
PASS host filesystem is unreachable from inside
|
|
85
|
+
stdout: 'DENIED: FileNotFoundError'
|
|
86
|
+
PASS network is unreachable from inside
|
|
87
|
+
stdout: 'DENIED: OSError'
|
|
88
|
+
PASS container engine socket is not mounted
|
|
89
|
+
stdout: 'engine sockets present: []'
|
|
90
|
+
PASS memory exhaustion is capped, with a legible reason
|
|
91
|
+
exit_code: 137 | stderr: Killed (SIGKILL): the sandbox exceeded its memory limit of 1g.
|
|
92
|
+
PASS process explosion is capped by the PID limit
|
|
93
|
+
stdout: 'DENIED after 126 processes: BlockingIOError'
|
|
94
|
+
PASS sandbox is destroyed cleanly afterwards
|
|
95
|
+
|
|
96
|
+
6/6 contained
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The fork bomb stopped at 126 processes against a ceiling of 128. Run it
|
|
100
|
+
yourself — that is why it ships as a test.
|
|
101
|
+
|
|
102
|
+
## Custom environments
|
|
103
|
+
|
|
104
|
+
Start sandboxes from a heavier image so you do not pay a package install
|
|
105
|
+
every time:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
hyperbox build data-science --custom ./Dockerfile
|
|
109
|
+
hyperbox envs
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Your agent then asks for it by name:
|
|
113
|
+
`create_sandbox(environment="data-science")`. A running server picks up a
|
|
114
|
+
new environment without a restart.
|
|
115
|
+
|
|
116
|
+
Building is a CLI action on purpose — an agent can use an environment,
|
|
117
|
+
but cannot create one. See [docs/security.md](docs/security.md).
|
|
118
|
+
|
|
119
|
+
## What it does not do
|
|
120
|
+
|
|
121
|
+
Be clear-eyed about the boundary:
|
|
122
|
+
|
|
123
|
+
- **Local containers share your host's kernel.** This is developer
|
|
124
|
+
containment, not absolute isolation. There is no gVisor, no
|
|
125
|
+
Firecracker, no VM boundary that HyperBox itself provides.
|
|
126
|
+
- **It is not a multi-tenant boundary.** Do not use it to run untrusted
|
|
127
|
+
third-party code as a service.
|
|
128
|
+
- **Code runs as root inside the container.** A non-root user was tried
|
|
129
|
+
and breaks the execution backend; the reasoning is in
|
|
130
|
+
[docs/security.md](docs/security.md).
|
|
131
|
+
- **Dependencies come from the public index** and are not vetted.
|
|
132
|
+
|
|
133
|
+
If you need a hard boundary for genuinely adversarial code, you want a VM
|
|
134
|
+
or microVM sandbox, not a local container.
|
|
135
|
+
|
|
136
|
+
## Documentation
|
|
137
|
+
|
|
138
|
+
- **[Setup](docs/setup.md)** — install, client configuration, environments, CLI reference
|
|
139
|
+
- **[Security model](docs/security.md)** — what is enforced, how it is proven, what it does not cover
|
|
140
|
+
- **[Troubleshooting](docs/troubleshooting.md)** — when something does not work
|
|
141
|
+
- **[Changelog](CHANGELOG.md)**
|
|
142
|
+
- **[Contributing](CONTRIBUTING.md)**
|
|
143
|
+
|
|
144
|
+
## Testing
|
|
145
|
+
|
|
146
|
+
There are no mocks on the sandbox path, on purpose — mocking Docker would
|
|
147
|
+
prove only that the mock works. Every acceptance suite runs against a real
|
|
148
|
+
container:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
python tests/run_all.py docker # and: podman
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Takes 5–15 minutes. It also asserts that no containers were left behind.
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "hyperbox-mcp"
|
|
3
|
+
version = "0.2.1"
|
|
4
|
+
description = "MCP server that runs LLM-generated code in a disposable Docker/Podman container before it touches your real project."
|
|
5
|
+
# PyPI gets its own page: self-contained, no mermaid (PyPI renders it
|
|
6
|
+
# as a raw code block) and no relative links into the repo tree.
|
|
7
|
+
readme = "PYPI.md"
|
|
8
|
+
requires-python = ">=3.11"
|
|
9
|
+
license = "MIT"
|
|
10
|
+
license-files = ["LICENSE"]
|
|
11
|
+
authors = [{ name = "Sanjay Jat" }]
|
|
12
|
+
keywords = [
|
|
13
|
+
"mcp",
|
|
14
|
+
"model-context-protocol",
|
|
15
|
+
"sandbox",
|
|
16
|
+
"docker",
|
|
17
|
+
"podman",
|
|
18
|
+
"llm",
|
|
19
|
+
"agent",
|
|
20
|
+
"code-execution",
|
|
21
|
+
"container",
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 4 - Beta",
|
|
25
|
+
"Intended Audience :: Developers",
|
|
26
|
+
"Operating System :: MacOS",
|
|
27
|
+
"Operating System :: Microsoft :: Windows",
|
|
28
|
+
"Operating System :: POSIX :: Linux",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.11",
|
|
31
|
+
"Programming Language :: Python :: 3.12",
|
|
32
|
+
"Programming Language :: Python :: 3.13",
|
|
33
|
+
"Topic :: Software Development :: Testing",
|
|
34
|
+
"Topic :: Security",
|
|
35
|
+
"Topic :: System :: Emulators",
|
|
36
|
+
]
|
|
37
|
+
dependencies = [
|
|
38
|
+
"fastmcp>=4.0.2,<5",
|
|
39
|
+
"llm-sandbox[docker,podman]>=0.3.44,<0.4",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Homepage = "https://github.com/Sanjay7089/hyperbox-mcp"
|
|
44
|
+
Repository = "https://github.com/Sanjay7089/hyperbox-mcp"
|
|
45
|
+
Documentation = "https://github.com/Sanjay7089/hyperbox-mcp/tree/main/docs"
|
|
46
|
+
Issues = "https://github.com/Sanjay7089/hyperbox-mcp/issues"
|
|
47
|
+
Changelog = "https://github.com/Sanjay7089/hyperbox-mcp/blob/main/CHANGELOG.md"
|
|
48
|
+
|
|
49
|
+
[project.scripts]
|
|
50
|
+
hyperbox = "hyperbox_mcp.server:main"
|
|
51
|
+
|
|
52
|
+
[build-system]
|
|
53
|
+
requires = ["setuptools>=77"]
|
|
54
|
+
build-backend = "setuptools.build_meta"
|
|
55
|
+
|
|
56
|
+
[tool.setuptools.packages.find]
|
|
57
|
+
where = ["src"]
|
|
File without changes
|