{
  "markdown": "# mcp-exec\n\n**English** | [Русский](README.ru.md)\n\n[![Version](https://img.shields.io/github/v/tag/inhuman/mcp-exec?sort=semver&style=flat-square&label=version)](https://github.com/inhuman/mcp-exec/tags)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-io.github.inhuman%2Fmcp--exec-blue?style=flat-square)](https://registry.modelcontextprotocol.io)\n[![Docker Pulls](https://img.shields.io/docker/pulls/idconstruct/mcp-exec?style=flat-square&logo=docker)](https://hub.docker.com/r/idconstruct/mcp-exec)\n[![Docker Image Version](https://img.shields.io/docker/v/idconstruct/mcp-exec?sort=semver&style=flat-square&logo=docker&label=image)](https://hub.docker.com/r/idconstruct/mcp-exec/tags)\n[![Build](https://img.shields.io/github/actions/workflow/status/inhuman/mcp-exec/docker-publish.yml?style=flat-square&logo=github)](https://github.com/inhuman/mcp-exec/actions/workflows/docker-publish.yml)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/inhuman/mcp-exec?style=flat-square&logo=go)](https://go.dev/)\n[![Go Report Card](https://goreportcard.com/badge/github.com/inhuman/mcp-exec?style=flat-square)](https://goreportcard.com/report/github.com/inhuman/mcp-exec)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)](LICENSE)\n[![Issues](https://img.shields.io/github/issues/inhuman/mcp-exec?style=flat-square)](https://github.com/inhuman/mcp-exec/issues)\n[![Last Commit](https://img.shields.io/github/last-commit/inhuman/mcp-exec?style=flat-square)](https://github.com/inhuman/mcp-exec/commits/main)\n\nPublic OSS MCP server (Go, MIT) exposing a single powerful tool — **`exec`** — that runs\ncaller-supplied **Python** code in a **network-isolated, locked-down sandbox** and returns\n`stdout` / `stderr` / `exit_code`. It is the \"code-execution mode\" building block: instead of\nflooding an agent's context with hundreds of tool schemas, the agent writes code that orchestrates\nthe work.\n\nWorks over three transports — **stdio / HTTP / SSE** — with an identical tool set everywhere\n(official [`modelcontextprotocol/go-sdk`](https://github.com/modelcontextprotocol/go-sdk)).\n\n## The `exec` tool\n\n**Input**: `{ code: string (required), timeout_s?: int, stdin?: string }`\n**Output**: `{ stdout, stderr, exit_code, duration_ms, truncated, timed_out }`\n\n- A non-zero `exit_code` or `timed_out=true` is a **normal result**, not a tool error. Only invalid\n  input (empty `code`, oversized `stdin`) is a tool-call error.\n- Sandbox v1: Python 3 with stdlib + **PyYAML**, **Jinja2**, **Pillow**, **numpy**, **pandas**, **matplotlib**.\n\n## Security model (invariants)\n\nPer execution: **no network**, non-root, `cap-drop=ALL`, `no-new-privileges`, read-only rootfs,\n**no CAP_SYS_ADMIN**, ephemeral tmpdir (cleaned up), wall-clock timeout (kills the whole\nprocess-group), memory/PID/CPU limits, capped output (1 MiB → `truncated`). Runs are **serialized**\nwithin an instance; scale out with replicas. Caller data (`code`/`stdin`/output) is never persisted\nand never logged in full — only metadata.\n\n> `exec` is the most powerful surface there is. When embedding it in an agent, gate it behind that\n> agent's tool-policy (trusted roles only).\n\n**Network note:** `--network none` only applies to **stdio**. In **HTTP/SSE** the container needs\nnetworking to serve its port, so sandboxed code would inherit egress — deny it at the orchestrator.\nIn k8s, a `NetworkPolicy` that allows ingress to the port and denies all egress:\n\n```yaml\napiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\nmetadata: { name: mcp-exec-lockdown }\nspec:\n  podSelector: { matchLabels: { app: mcp-exec } }\n  policyTypes: [Ingress, Egress]\n  ingress: [{ ports: [{ port: 8080 }] }]\n  egress: []   # deny all egress → sandbox has no network\n```\n\n## Run\n\n```bash\ngo build -o mcp-exec ./cmd/mcp-exec\nMCP_EXEC_TRANSPORT=stdio ./mcp-exec\n```\n\nDocker (recommended production posture):\n\n```bash\ndocker run --rm -i --network none --read-only --cap-drop ALL \\\n  --security-opt no-new-privileges --user 65532:65532 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=64m \\\n  --memory 256m --pids-limit 128 --cpus 1 \\\n  idconstruct/mcp-exec\n```\n\n`--tmpfs /tmp` is required: the rootfs is read-only, and each run needs a writable\nephemeral workspace (cleaned up after).\n\n### Optional auth (HTTP/SSE)\n\nSet `MCP_EXEC_AUTH_TOKEN` to require every HTTP/SSE request to carry a matching `X-MCP-AUTH` header\n(constant-time compare; `401` otherwise). Empty token disables it. Not applicable to stdio.\n\n## Configuration\n\n| Env var | Purpose | Default |\n|---|---|---|\n| `MCP_EXEC_TRANSPORT` | `stdio` \\| `http` \\| `sse` | `stdio` |\n| `MCP_EXEC_ADDR` | listen address for http/sse | `:8080` |\n| `MCP_EXEC_DEFAULT_TIMEOUT_S` | default wall-clock timeout | `30` |\n| `MCP_EXEC_MAX_TIMEOUT_S` | timeout ceiling | `300` |\n| `MCP_EXEC_MAX_OUTPUT_BYTES` | combined stdout+stderr cap | `1048576` |\n| `MCP_EXEC_MAX_STDIN_BYTES` | stdin size cap | `1048576` |\n| `MCP_EXEC_PYTHON` | interpreter path | `python3` |\n| `MCP_EXEC_AUTH_TOKEN` | if set, http/sse require `X-MCP-AUTH` header (constant-time); empty = off | `` |\n\n## Not in v1\n\nbash / multi-language, network from the sandbox, proxying other MCP servers into the sandbox.\n\n## License\n\nMIT.\n",
  "bytes": 5211,
  "sha": "ae483d1f2d8ffefe2e7360db80023e55cf1b85e1ac77c86ad807f24a517ce7b8",
  "repo_slug": "inhuman/mcp-exec",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_inhuman_mcp_exec_b185dcfd/readme"
}