đŸ§± The MCP Cell — an AI That Can Only Talk to Pipe's Own MCP Server 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. ← All posts← Alle BeitrĂ€ge ../blog.html đŸ§± The MCP Cell — an AI That Can Only Talk to Pipe's Own MCP Server 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. Everyone asks the same question about sandboxes: "But if the agent has tools, aren't the tools the attack surface?" Fair. 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. The 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 agent and a real MCP server on stdio serve that external clients like Claude Desktop or Cursor can plug into. Both modes give the exact same five tools. The Cell đŸ—ïž The profile is the wall: sandbox profile "mcp-cell" { fs: "temp-only", every write lands in ./.pipe sandbox network: true, network whitelist: provider host , the ONLY network target is the AI provider exec: false, no shell, period ai: true, budget: 0.5, max tool calls: 25, audit log: true, timeout: 30 } Inside that wall the agent can call exactly five tools, defined with ordinary Pipe functions and registered with ai tool : | Tool | What it does | |---|---| sb write | Writes a file — redirected into .pipe sandbox | sb read | Reads a file from the sandbox | sb list | Lists the sandbox directory | sb note | Stores an in-memory note a plain Pipe map | sb ping | Liveness check | fn sb note key value set cell notes key value "Notiz gesetzt: " ++ key ++ " = " ++ value ai tool "sb note" "Legt eine In-Memory-Notiz an" {key: "Schluessel", value: "Wert"} sb note Then the sandbox is locked in with set sandbox "mcp-cell" , and the server is started. Because mcp server bridges whatever ai tool registered, the client-facing tool list is the same five functions — and every single tools/call executes under the active profile. What the Agent Actually Did đŸ€– In agent mode the task was simple: create three notes, write a summary file, list the sandbox. DeepSeek did it in six tool calls: tool call | sb note tool call | sb note tool call | sb note tool call | sb write tool call | sb list That's the whole audit log. No exec , no foreign http get , 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. The Real Proof: Trying to Break Out đŸ’„ A demo that only shows success proves nothing. So I tried to escape, using the same builtins an attacker would reach for inside the cell: | Attempt | Result | |---|---| exec "id" | E SANDBOX: exec blocked by profile 'mcp-cell' | http get "https://www.google.com" | E SANDBOX: network target not in whitelist | write file "/tmp/escape.txt" | silently redirected to .pipe sandbox/escape.txt | The 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 — the file actually lands inside the cell. The attacker gets a consistent illusion, and the host stays clean. One Real Bug Found Along the Way 🐛 Building this demo surfaced an actual bug in Pipe. With fs: "temp-only" and the default workingDir: "." , listing the sandbox directory broke: list dir: open /tmp/.pipe sandbox/tmp: no such file or directory The filepath.Rel call in the redirect logic can't relate an absolute path to a relative base — so list dir "." resolved 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 : func currentDir string { d, err := os.Getwd if err = nil || d == "" { return "." } return d } Now every profile starts with an absolute working directory, and temp-only redirects behave correctly — including list dir "." . Try It Yourself 🚀 DeepSeek DEEPSEEK API KEY=sk-... pipe examples/mcp sandbox agent.pipe agent local, no key needed pipe examples/mcp sandbox agent.pipe serve ollama Then point Claude Desktop or Cursor at the stdio server: { "mcpServers": { "pipe-cell": { "command": "pipe", "args": "examples/mcp sandbox agent.pipe", "serve" } } } The same mcp-cell profile wraps both the in-process agent and every external client call. One sandbox, two entry points, same guarantee. đŸ§± Die MCP-Zelle — eine KI, die nur mit Pipes eigenem MCP-Server sprechen kann 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. Jeder fragt bei Sandboxen dasselbe: "Aber wenn der Agent Werkzeuge hat, ist der Werkzeugsatz nicht die AngriffsflĂ€che?" Fair. 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. Das 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 agent und einen echten MCP-Server auf stdio serve , in den sich externe Clients wie Claude Desktop oder Cursor einklinken. Beide Modi geben exakt dieselben fĂŒnf Tools. Die Zelle đŸ—ïž Das Profil ist die Wand: sandbox profile "mcp-cell" { fs: "temp-only", every write lands in ./.pipe sandbox network: true, network whitelist: provider host , the ONLY network target is the AI provider exec: false, no shell, period ai: true, budget: 0.5, max tool calls: 25, audit log: true, timeout: 30 } Innerhalb dieser Wand kann der Agent genau fĂŒnf Tools aufrufen, definiert als ganz normale Pipe-Funktionen und registriert mit ai tool : | Tool | Was es tut | |---|---| sb write | Schreibt eine Datei — umgeleitet nach .pipe sandbox | sb read | Liest eine Datei aus der Sandbox | sb list | Listet das Sandbox-Verzeichnis | sb note | Legt eine In-Memory-Notiz an eine Pipe-Map | sb ping | Lebenszeichen-Check | fn sb note key value set cell notes key value "Notiz gesetzt: " ++ key ++ " = " ++ value ai tool "sb note" "Legt eine In-Memory-Notiz an" {key: "Schluessel", value: "Wert"} sb note Danach wird die Sandbox mit set sandbox "mcp-cell" festgeschaltet und der Server gestartet. Da mcp server alles bridged, was ai tool registriert hat, ist die client-seitige Toolliste dieselben fĂŒnf Funktionen — und jeder tools/call lĂ€uft unter dem aktiven Profil. Was der Agent wirklich tat đŸ€– Im agent -Modus war die Aufgabe simpel: drei Notizen anlegen, eine Zusammenfassung schreiben, die Sandbox auflisten. DeepSeek erledigte das in sechs Tool-Calls: tool call | sb note tool call | sb note tool call | sb note tool call | sb write tool call | sb list Das ist das gesamte Audit-Log. Kein exec , kein fremder http get , 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. Der echte Beweis: Der Ausbruchsversuch đŸ’„ Eine 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: | Versuch | Ergebnis | |---|---| exec "id" | E SANDBOX: exec blocked by profile 'mcp-cell' | http get "https://www.google.com" | E SANDBOX: network target not in whitelist | write file "/tmp/escape.txt" | stillschweigend umgeleitet nach .pipe sandbox/escape.txt | Der 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 geschrieben — die Datei landet tatsĂ€chlich in der Zelle. Der Angreifer bekommt eine konsistente Illusion, und der Host bleibt sauber. Ein echter Bug, der dabei auffiel 🐛 Beim Bauen dieser Demo fiel ein echter Bug in Pipe auf. Mit fs: "temp-only" und dem Standard- workingDir: "." brach das Auflisten des Sandbox-Verzeichnisses: list dir: open /tmp/.pipe sandbox/tmp: no such file or directory Der filepath.Rel -Aufruf in der Redirect-Logik kann einen absoluten Pfad nicht auf eine relative Basis beziehen — deshalb landete list dir "." an 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 : func currentDir string { d, err := os.Getwd if err = nil || d == "" { return "." } return d } Jetzt startet jedes Profil mit absolutem Arbeitsverzeichnis, und temp-only- Redirects verhalten sich korrekt — inklusive list dir "." . Probier es selbst 🚀 DeepSeek DEEPSEEK API KEY=sk-... pipe examples/mcp sandbox agent.pipe agent local, no key needed pipe examples/mcp sandbox agent.pipe serve ollama Danach Claude Desktop oder Cursor auf den stdio-Server zeigen lassen: { "mcpServers": { "pipe-cell": { "command": "pipe", "args": "examples/mcp sandbox agent.pipe", "serve" } } } Dasselbe mcp-cell -Profil umschließt sowohl den In-Process-Agenten als auch jeden externen Client-Aufruf. Eine Sandbox, zwei Einstiegspunkte, dieselbe Garantie.