{"slug": "the-mcp-cell-an-ai-that-can-only-talk-to-pipe-s-own-mcp-server", "title": "🧱 The MCP Cell — an AI That Can Only Talk to Pipe's Own MCP Server", "summary": "Pipe, a programming language and runtime, released a demo of a sandboxed AI agent that can only interact with its own MCP server, exposing five whitelisted tools and blocking all other operations. The demo, available in examples/mcp_sandbox_agent.pipe, includes an in-process agent mode and a real MCP server on stdio for external clients like Claude Desktop or Cursor. Attempts to break out of the sandbox were blocked, with exec and network calls returning errors and file writes redirected to a temporary directory, and the demo surfaced a bug in Pipe's temp-only filesystem handling.", "body_md": "[← All posts← Alle Beiträge](../blog.html)\n\n# 🧱 The MCP Cell — an AI That Can Only Talk to Pipe's Own MCP Server\n\n**The smallest demo of the strongest idea: a sandboxed AI agent whose entire universe is Pipe's own MCP server. No free network, no free filesystem, no shell — just five tools behind a whitelist.**\n\nEveryone asks the same question about sandboxes: *\"But if the agent has tools, aren't the tools the attack surface?\"*\n\nFair. So this time I flipped it. Instead of giving the agent a toolbox and hoping the sandbox holds, I built a profile where the **only** things the agent can do are the MCP tools that *I* chose to expose — and nothing else. The AI's entire world is one MCP server, and that server lives inside the sandbox too.\n\nThe example lives in [ examples/mcp_sandbox_agent.pipe](https://github.com/MachuraHarry/pipe/blob/master/examples/mcp_sandbox_agent.pipe). It has two modes: an in-process agent mode (\n\n`agent`\n\n) and a real MCP server on stdio (`serve`\n\n) that external clients like Claude Desktop or Cursor can plug into. Both modes give the exact same five tools.## The Cell 🏗️\n\nThe profile is the wall:\n\n```\nsandbox_profile \"mcp-cell\" {\n    fs:                \"temp-only\",       # every write lands in ./.pipe_sandbox\n    network:           true,\n    network_whitelist: [provider_host],   # the ONLY network target is the AI provider\n    exec:              false,             # no shell, period\n    ai:                true,\n    budget:            0.5,\n    max_tool_calls:    25,\n    audit_log:         true,\n    timeout:           30\n}\n```\n\nInside that wall the agent can call exactly five tools, defined with ordinary Pipe functions and registered with `ai_tool`\n\n:\n\n| Tool | What it does |\n|---|---|\n`sb_write` | Writes a file — redirected into `.pipe_sandbox` |\n`sb_read` | Reads a file from the sandbox |\n`sb_list` | Lists the sandbox directory |\n`sb_note` | Stores an in-memory note (a plain Pipe map) |\n`sb_ping` | Liveness check |\n\n```\nfn sb_note key value\n    set __cell_notes key value\n    \"Notiz gesetzt: \" ++ key ++ \" = \" ++ value\n\nai_tool \"sb_note\" \"Legt eine In-Memory-Notiz an\" {key: \"Schluessel\", value: \"Wert\"} sb_note\n```\n\nThen the sandbox is locked in with `set_sandbox \"mcp-cell\"`\n\n, and the server is started. Because `mcp_server`\n\nbridges whatever `ai_tool`\n\nregistered, the client-facing tool list is *the same five functions* — and every single `tools/call`\n\nexecutes under the active profile.\n\n## What the Agent Actually Did 🤖\n\nIn `agent`\n\nmode the task was simple: create three notes, write a summary file, list the sandbox. DeepSeek did it in six tool calls:\n\n```\ntool_call | sb_note\ntool_call | sb_note\ntool_call | sb_note\ntool_call | sb_write\ntool_call | sb_list\n```\n\nThat's the whole audit log. No `exec`\n\n, no foreign `http_get`\n\n, no writes outside the cell. The agent *couldn't* have done more even if it had tried — the profile blocks it at the builtin level, not at the prompt level.\n\n## The Real Proof: Trying to Break Out 💥\n\nA demo that only shows success proves nothing. So I tried to escape, using the same builtins an attacker would reach for inside the cell:\n\n| Attempt | Result |\n|---|---|\n`exec \"id\"` | `E_SANDBOX: exec blocked by profile 'mcp-cell'` |\n`http_get \"https://www.google.com\"` | `E_SANDBOX: network target not in whitelist` |\n`write_file \"/tmp/escape.txt\"` | silently redirected to `.pipe_sandbox/escape.txt` |\n\nThe third one is the interesting case: temp-only **doesn't fail**, it *redirects*. The agent writes wherever it wants and believes it wrote to `/tmp/escape.txt`\n\n— the file actually lands inside the cell. The attacker gets a consistent illusion, and the host stays clean.\n\n## One Real Bug Found Along the Way 🐛\n\nBuilding this demo surfaced an actual bug in Pipe. With `fs: \"temp-only\"`\n\nand the default `workingDir: \".\"`\n\n, listing the sandbox directory broke:\n\n```\nlist_dir: open /tmp/.pipe_sandbox/tmp: no such file or directory\n```\n\nThe `filepath.Rel`\n\ncall in the redirect logic can't relate an absolute path to a *relative* base — so `list_dir \".\"`\n\nresolved to the wrong place. The fix was to make the profile's working directory absolute everywhere ([ sandbox.go](https://github.com/MachuraHarry/pipe/blob/master/pkg/object/sandbox.go)):\n\n```\nfunc currentDir() string {\n    d, err := os.Getwd()\n    if err != nil || d == \"\" {\n        return \".\"\n    }\n    return d\n}\n```\n\nNow every profile starts with an absolute working directory, and temp-only redirects behave correctly — including `list_dir \".\"`\n\n.\n\n## Try It Yourself 🚀\n\n```\n# DeepSeek\nDEEPSEEK_API_KEY=sk-... pipe examples/mcp_sandbox_agent.pipe agent\n\n# local, no key needed\npipe examples/mcp_sandbox_agent.pipe serve ollama\n```\n\nThen point Claude Desktop or Cursor at the stdio server:\n\n```\n{\n  \"mcpServers\": {\n    \"pipe-cell\": {\n      \"command\": \"pipe\",\n      \"args\": [\"examples/mcp_sandbox_agent.pipe\", \"serve\"]\n    }\n  }\n}\n```\n\nThe same `mcp-cell`\n\nprofile wraps both the in-process agent and every external client call. One sandbox, two entry points, same guarantee.\n\n# 🧱 Die MCP-Zelle — eine KI, die nur mit Pipes eigenem MCP-Server sprechen kann\n\n**Die kleinste Demo der stärksten Idee: eine KI in der Sandbox, deren ganzes Universum Pipes eigener MCP-Server ist. Kein freies Netz, kein freies Dateisystem, keine Shell — nur fünf Tools hinter einer Whitelist.**\n\nJeder fragt bei Sandboxen dasselbe: *\"Aber wenn der Agent Werkzeuge hat, ist der Werkzeugsatz nicht die Angriffsfläche?\"*\n\nFair. Also habe ich es diesmal umgedreht. Statt dem Agenten einen Werkzeugkasten zu geben und zu hoffen, dass die Sandbox hält, habe ich ein Profil gebaut, in dem der Agent **ausschließlich** die MCP-Tools nutzen kann, die *ich* freigebe — und sonst nichts. Die ganze Welt der KI ist ein einziger MCP-Server, und dieser Server lebt ebenfalls in der Sandbox.\n\nDas Beispiel liegt in [ examples/mcp_sandbox_agent.pipe](https://github.com/MachuraHarry/pipe/blob/master/examples/mcp_sandbox_agent.pipe). Es hat zwei Modi: einen In-Process-Agenten (\n\n`agent`\n\n) und einen echten MCP-Server auf stdio (`serve`\n\n), in den sich externe Clients wie Claude Desktop oder Cursor einklinken. Beide Modi geben exakt dieselben fünf Tools.## Die Zelle 🏗️\n\nDas Profil ist die Wand:\n\n```\nsandbox_profile \"mcp-cell\" {\n    fs:                \"temp-only\",       # every write lands in ./.pipe_sandbox\n    network:           true,\n    network_whitelist: [provider_host],   # the ONLY network target is the AI provider\n    exec:              false,             # no shell, period\n    ai:                true,\n    budget:            0.5,\n    max_tool_calls:    25,\n    audit_log:         true,\n    timeout:           30\n}\n```\n\nInnerhalb dieser Wand kann der Agent genau fünf Tools aufrufen, definiert als ganz normale Pipe-Funktionen und registriert mit `ai_tool`\n\n:\n\n| Tool | Was es tut |\n|---|---|\n`sb_write` | Schreibt eine Datei — umgeleitet nach `.pipe_sandbox` |\n`sb_read` | Liest eine Datei aus der Sandbox |\n`sb_list` | Listet das Sandbox-Verzeichnis |\n`sb_note` | Legt eine In-Memory-Notiz an (eine Pipe-Map) |\n`sb_ping` | Lebenszeichen-Check |\n\n```\nfn sb_note key value\n    set __cell_notes key value\n    \"Notiz gesetzt: \" ++ key ++ \" = \" ++ value\n\nai_tool \"sb_note\" \"Legt eine In-Memory-Notiz an\" {key: \"Schluessel\", value: \"Wert\"} sb_note\n```\n\nDanach wird die Sandbox mit `set_sandbox \"mcp-cell\"`\n\nfestgeschaltet und der Server gestartet. Da `mcp_server`\n\nalles bridged, was `ai_tool`\n\nregistriert hat, ist die client-seitige Toolliste *dieselben fünf Funktionen* — und jeder `tools/call`\n\nläuft unter dem aktiven Profil.\n\n## Was der Agent wirklich tat 🤖\n\nIm `agent`\n\n-Modus war die Aufgabe simpel: drei Notizen anlegen, eine Zusammenfassung schreiben, die Sandbox auflisten. DeepSeek erledigte das in sechs Tool-Calls:\n\n```\ntool_call | sb_note\ntool_call | sb_note\ntool_call | sb_note\ntool_call | sb_write\ntool_call | sb_list\n```\n\nDas ist das gesamte Audit-Log. Kein `exec`\n\n, kein fremder `http_get`\n\n, keine Schreibzugriffe außerhalb der Zelle. Der Agent *hätte* nicht mehr tun können, selbst wenn er es versucht hätte — das Profil blockt auf Builtin-Ebene, nicht auf Prompt-Ebene.\n\n## Der echte Beweis: Der Ausbruchsversuch 💥\n\nEine Demo, die nur Erfolg zeigt, beweist nichts. Also habe ich versucht auszubrechen — mit genau den Builtins, nach denen ein Angreifer in der Zelle greifen würde:\n\n| Versuch | Ergebnis |\n|---|---|\n`exec \"id\"` | `E_SANDBOX: exec blocked by profile 'mcp-cell'` |\n`http_get \"https://www.google.com\"` | `E_SANDBOX: network target not in whitelist` |\n`write_file \"/tmp/escape.txt\"` | stillschweigend umgeleitet nach `.pipe_sandbox/escape.txt` |\n\nDer dritte Fall ist der interessante: temp-only **scheitert nicht**, es *leitet um*. Der Agent schreibt, wohin er will, und glaubt, er habe nach `/tmp/escape.txt`\n\ngeschrieben — die Datei landet tatsächlich in der Zelle. Der Angreifer bekommt eine konsistente Illusion, und der Host bleibt sauber.\n\n## Ein echter Bug, der dabei auffiel 🐛\n\nBeim Bauen dieser Demo fiel ein echter Bug in Pipe auf. Mit `fs: \"temp-only\"`\n\nund dem Standard-`workingDir: \".\"`\n\nbrach das Auflisten des Sandbox-Verzeichnisses:\n\n```\nlist_dir: open /tmp/.pipe_sandbox/tmp: no such file or directory\n```\n\nDer `filepath.Rel`\n\n-Aufruf in der Redirect-Logik kann einen absoluten Pfad nicht auf eine *relative* Basis beziehen — deshalb landete `list_dir \".\"`\n\nan der falschen Stelle. Der Fix: Das Arbeitsverzeichnis des Profils wird überall absolut gemacht ([ sandbox.go](https://github.com/MachuraHarry/pipe/blob/master/pkg/object/sandbox.go)):\n\n```\nfunc currentDir() string {\n    d, err := os.Getwd()\n    if err != nil || d == \"\" {\n        return \".\"\n    }\n    return d\n}\n```\n\nJetzt startet jedes Profil mit absolutem Arbeitsverzeichnis, und temp-only- Redirects verhalten sich korrekt — inklusive `list_dir \".\"`\n\n.\n\n## Probier es selbst 🚀\n\n```\n# DeepSeek\nDEEPSEEK_API_KEY=sk-... pipe examples/mcp_sandbox_agent.pipe agent\n\n# local, no key needed\npipe examples/mcp_sandbox_agent.pipe serve ollama\n```\n\nDanach Claude Desktop oder Cursor auf den stdio-Server zeigen lassen:\n\n```\n{\n  \"mcpServers\": {\n    \"pipe-cell\": {\n      \"command\": \"pipe\",\n      \"args\": [\"examples/mcp_sandbox_agent.pipe\", \"serve\"]\n    }\n  }\n}\n```\n\nDasselbe `mcp-cell`\n\n-Profil umschließt sowohl den In-Process-Agenten als auch jeden externen Client-Aufruf. Eine Sandbox, zwei Einstiegspunkte, dieselbe Garantie.", "url": "https://wpnews.pro/news/the-mcp-cell-an-ai-that-can-only-talk-to-pipe-s-own-mcp-server", "canonical_source": "https://pipe-lang.com/blog/mcp-cell.html", "published_at": "2026-08-14 00:00:00+00:00", "updated_at": "2026-08-14 06:13:34.799876+00:00", "lang": "en", "topics": ["ai-agents", "ai-safety", "ai-tools", "developer-tools"], "entities": ["Pipe", "DeepSeek", "Claude Desktop", "Cursor", "MCP"], "alternates": {"html": "https://wpnews.pro/news/the-mcp-cell-an-ai-that-can-only-talk-to-pipe-s-own-mcp-server", "markdown": "https://wpnews.pro/news/the-mcp-cell-an-ai-that-can-only-talk-to-pipe-s-own-mcp-server.md", "text": "https://wpnews.pro/news/the-mcp-cell-an-ai-that-can-only-talk-to-pipe-s-own-mcp-server.txt", "jsonld": "https://wpnews.pro/news/the-mcp-cell-an-ai-that-can-only-talk-to-pipe-s-own-mcp-server.jsonld"}}