mcp-box
# mcp-box
Private MCP server that turns the [ascii Box API](https://docs.ascii.dev/box/api/v1) into tools an external agent can drive. ChatGPT, Claude, Cursor, or Grok is the agent. The Box is the Linux machine.
`POST /prompt` is **never** used. Agents run shell and file tools only.
## Install
```bash
npm install
cp .env.example .env # set BOX_API_KEY
npm run typecheck
npm test
```
## Run
**stdio** (Claude Desktop, Cursor, Grok local):
```bash
npm run start:stdio
# or
npx tsx src/stdio.ts
```
**Streamable HTTP** (local Inspector, or behind tunnel-client):
```bash
npm run start:http
# listens on http://127.0.0.1:8787/mcp when PORT=8787 in .env
```
**ChatGPT:** use **OpenAI Secure MCP Tunnel**, not a public Cloudflare URL. See [docs/chatgpt.md](./docs/chatgpt.md).
```bash
# after tunnel-client is installed and CONTROL_PLANE_API_KEY is set
export CONTROL_PLANE_TUNNEL_ID=tunnel_6a7290ef51b88191af7b32deba8e0640
tunnel-client run \
--control-plane.tunnel-id "$CONTROL_PLANE_TUNNEL_ID" \
--mcp.server-url http://127.0.0.1:8787/mcp
```
Then in ChatGPT: Criar app → Conexão **Túnel** → select `mcp-box` → Sem autenticação.
## Environment
| Variable | Default | Purpose |
| --- | --- | --- |
| `BOX_API_KEY` | (required for live) | Box dashboard API key; never sent to the MCP client |
| `BOX_BASE_URL` | `https://ascii.dev/api/box/v1` | API base |
| `MCP_BOX_MODE` | `isolated` | `isolated` or `trusted` |
| `ALLOW_WRITES` | `true` | When `false`, deny non-read tools |
| `HOST` | `127.0.0.1` | HTTP bind address |
| `PORT` | `3333` | HTTP port |
| `MCP_BOX_AUDIT_PATH` | stderr (trusted) | Optional audit JSONL path |
See [.env.example](./.env.example).
## Trust modes
| Mode | `noEnv` on create/fork | Account secrets | Audit log | Force stop |
| --- | --- | --- | --- | --- |
| **isolated** (default) | always `true` | blocked | off | denied |
| **trusted** | may be `false` | allowed via `env` / account | JSON lines | allowed with `confirm: true` |
Isolated boxes cannot act on your account secrets. Use them for untrusted agent work.
Trusted mode records every tool call (timestamp, tool, boxId, outcome). Desktop URLs and tokens are redacted in logs.
## Tools
| Tool | Read-only | Notes |
| --- | --- | --- |
| `box_create` | no | Default size **small**; TTL 3600s; waits until ready |
| `box_list` | yes | Optional state filter |
| `box_get` | yes | Desktop URL redacted in summary |
| `box_exec` | no | `timeoutSeconds` capped at **60** |
| `box_exec_background` | no | Convention under `.mcp-box-jobs/` |
| `box_job_status` | yes | Poll pid/exit/log tails |
| `box_read_file` | yes | Relative paths only |
| `box_write_file` | no | utf8 or base64 |
| `box_download_artifact` | yes | Base64, max ~2MB |
| `box_desktop` | yes | Secret URL; do not log full value |
| `box_stop_and_wait` | no | Requires `confirm: true` |
| `box_resume` | no | Wait until ready |
| `box_fork` | no | Isolated forks are noEnv |
| `box_interrupt` | no | Best-effort; prompt-oriented |
There is **no** `box_prompt` tool.
## Background jobs
Box has no native shell job API. Background work is:
1. Write a launcher under `.mcp-box-jobs/<jobId>/`
2. `nohup` the command; store pid and logs
3. Poll with `box_job_status`
## Clients
- Local JSON snippets: [docs/clients.md](./docs/clients.md)
- ChatGPT Developer Mode + tunnel: [docs/chatgpt.md](./docs/chatgpt.md)
- Grok Build on a template box (OAuth sub): [docs/grok-template.md](./docs/grok-template.md)
- Box selected repos (go-zoen): [docs/box-repos.md](./docs/box-repos.md)
### Grok template
```bash
npm run grok:template # small box: grok CLI + OAuth + EnzoTironi/skills + zoen-skills/pstack
npm run grok:diagnose -- bx_… # resume + smoke; REARCHIVE=1 to stop again
```
Current template: **`go-zoen`** / **`bx_sb5sbxzz`** (see [docs/grok-template.md](./docs/grok-template.md)). Fork for ChatGPT work with Grok + skills + go-zoen.
### ChatGPT write caveat
Full write MCP tools in ChatGPT generally need **Business / Enterprise / Edu**. Pro is often read-only for connectors. Confirm your plan before relying on ChatGPT as the primary write agent.
## Security
- Keep `BOX_API_KEY` on the host only.
- Prefer isolated mode unless you intentionally need account secrets.
- Redact desktop URLs (`_token`) from logs and tickets.
- Bind HTTP to localhost unless you add auth (v1 has no OAuth).
## Non-goals (v1)
- Multi-tenant OAuth
- Wrapping `POST /prompt`
- Native job queue
- Cloudflare Workers deploy
## Development
```bash
npm test
npm run typecheck
npm run smoke # fake client tools/list
LIVE_BOX=1 npm run smoke # live create → exec → write/read → stop
```
## License
Private / unlicensed unless you add one.
TDQS
Scored across 14 tools
Each tool targets a distinct operation: lifecycle (create/list/get/resume/stop/fork), execution (exec/exec_background/job_status/interrupt), file access (read/write/download), and desktop. The overlap between exec and exec_background is clear from their descriptions—one is synchronous with a timeout, the other is asynchronous via nohup.
All tools share the 'box_' prefix and use lowercase verbs or verb_noun patterns (e.g., box_create, box_read_file, box_stop_and_wait). The naming is uniformly descriptive and follows a recognizable convention throughout.
14 tools is well-scoped for a cloud computer management server, covering lifecycle, command execution, job handling, file operations, and desktop access without being excessive. Each tool serves a distinct purpose and earns its place.
The surface covers the major workflows: box lifecycle (create, get, list, resume, stop, fork), command execution (foreground, background, interrupt, job status), and file operations (read, write, download). Minor gaps exist, such as no explicit delete/destroy tool and no direct retrieval of background job stdout/stderr, but agents can work around these with existing tools.