Update AGENT_SANDBOX_VERSION to v1.0.8 and the docs that quote the control-plane pin (example prerequisites, architecture, versioning table, minimal-single-tenant template comment, platform skill). The v1.0.8 release adds only one CRD field, spec.failedPodPolicy (Sandbox and SandboxTemplate, enum Retain|Recreate, default Retain), so the existing manifests keep their behavior: Retain is the default and neither the API version (v1beta1) nor any field we set changed. All five custom resources still validate against the v1.0.8 CRD schemas. Behavior changes in the controller itself (bounded MCP output, router kustomization, creation-latency metric timing) do not affect the platform because it uses neither the sandbox-router nor the MCP server. Co-authored-by: SREDevOpsAgents <agents@sredevops.org>
6.2 KiB
agent-sandbox MCP server reference
Upstream: clients/integrations/mcp-server.
It is a Python/FastAPI + FastMCP service (streamable HTTP on :8000, MCP
endpoint /mcp) that provisions sandboxes from a warm pool and runs commands or
file operations through a sandbox runtime. It ships with no authentication.
Build the server from the same tag as the cluster: read AGENT_SANDBOX_VERSION
in versions.env, and check the installed controller image. Do not build from
main against an older cluster; tool schemas and connection types differ.
Tool surface
| Tool | Arguments (defaults) | Returns / notes |
|---|---|---|
create_sandbox |
warmpool, namespace, sandbox_ready_timeout=180, labels, shutdown_after_seconds=300 (null disables), pod_labels, pod_annotations |
sandbox_claim_name; adds the MCP session label |
delete_sandbox |
sandbox_claim_name, namespace |
Deletes the session-owned claim; PVC cascades |
execute_command |
sandbox_claim_name, namespace, command, timeout=60 (max 600), max_output_chars only on v1.0.8+ (128-300,000, default 30,000) |
exit_code, stdout, stderr; v1.0.8 adds *_total_chars and *_truncated |
upload_file |
sandbox_claim_name, namespace, path, content, binary=false, timeout=60 |
Bytes written; base64 when binary=true |
download_file |
sandbox_claim_name, namespace, path, binary=false, timeout=60 |
Content + bytes read |
list_files |
sandbox_claim_name, namespace, path, timeout=60, max_entries=1000 (max 10,000) |
Entries (name, size, type, mod_time), total_entries, truncated |
file_exists |
sandbox_claim_name, namespace, path, timeout=60 |
exists; a missing path is not an error |
get_sandbox_status |
sandbox_claim_name, namespace |
SandboxReady / SandboxNotReady / SandboxNotFound, ready, message |
Resource: sandboxes://{namespace} lists sandboxes for the current MCP session.
Session scoping is the most important behavior
Every tool, including get_sandbox_status, calls get_sandbox() ->
ensure_session_owns(), which lists sandboxes with the label selector
<K8S_SANDBOX_SESSION_ID_LABEL_KEY>=<MCP session id>. The resource uses the same
selector. Consequences:
- The server can only see/exec/delete claims it created in the same MCP
session. It cannot inspect or manage DSH platform claims created by the
gateway or
kubectl, or claims from another session. - On a DSH MCP reconnect, the MCP session changes; earlier claims become
invisible to the tools. They keep running until
shutdown_after_secondsexpires, or until you remove them by label with a confirmedkubectl delete. - A "Sandbox claim '' is not found in namespace ''" error usually means wrong namespace or the claim belongs to a different session.
- Use
kubectlfor global inventory; use the MCP only for sandboxes it created in this task.
Session identity requires a session-providing transport. With stdio,
ctx.session_id is None and creation fails. Connect DSH over
streamable-http.
Runtime prerequisite
The server talks to a sandbox runtime, not to arbitrary pods:
gateway,direct,in-cluster: runtime HTTP onSERVER_PORT=8888(sandbox-router API or direct pod runtime).sandboxd-in-cluster(v1.0.8+): sandboxd REST8080, gRPC9090.
The shipped DSH template runs only DSH Web on 3080, so no connection type can
exec into it. A sandboxd sidecar executes commands in the sidecar's own
container, not in the DSH container; shared volumes share files, not binaries or
processes. To exec inside DSH, build a combined image (sandboxd injected into the
DSH image) or use kubectl exec with explicit RBAC and confirmation. For
untrusted code, deploy a separate runtime warm pool rather than modifying the
DSH template.
Version differences
| Area | Before v1.0.8 | v1.0.8+ |
|---|---|---|
| Connection types | gateway, direct, in-cluster |
Adds sandboxd-in-cluster |
execute_command output |
Unbounded | Bounded by max_output_chars; four metadata fields |
| Failed pod recovery | Retain only |
spec.failedPodPolicy: Recreate |
| Router install | kubectl apply -f sandbox-router/deploy/ |
kubectl apply -k sandbox-router/deploy/; projected token |
Never pass max_output_chars to a pre-v1.0.8 server. On older servers, redirect
verbose output to a file and download_file it, or pipe through tail/head.
The repository pins AGENT_SANDBOX_VERSION=v1.0.8, so the right-hand column is
what the documented platform and a same-tag MCP build provide; keep the
before-column for clusters still on v1.0.7.
Safety and cleanup
- No auth: anyone reaching
:8000gets every tool and the service account's access. Keep it ClusterIP, authenticated, and namespace-scoped. - Treat commands as untrusted code: they can read files and environment variables inside the sandbox, including provider keys in a combined image.
delete_sandboxcascades the claim, sandbox, and PVC: confirm the target and namespace. Never delete a namespace or PVC as cleanup.- Clean up in the same session that created the sandbox. If the session is gone, list claims by the session label and delete them explicitly (requires write RBAC); otherwise rely on the shutdown timeout.
Troubleshooting
| Symptom | Cause / fix |
|---|---|
| Tools missing | Row not enabled, wrong URL, connection failed; check logs and /readyz |
| 404 on connect | URL is missing /mcp or points at the wrong port |
ctx.session_id is None |
Connected over stdio; use streamable HTTP |
Sandbox claim ... is not found |
Wrong namespace, or claim created by another MCP session |
| Creation times out at ~60 s | MCP session alive but DSH cancelled the call; raise toolCallTimeoutMs |
execute_command connection error |
No runtime on 8888/8080/9090, or wrong connection type; the DSH template is unsupported |
| Output flood | Pre-v1.0.8 server; bound the command output yourself |
| Empty sandbox list | The resource is session-scoped; use kubectl for global inventory |
Deployment, connection matrix, RBAC, and the DSH row: MCP deployment.