Runtime

How to give an AI research agent a sandbox to fetch pages and run code

Give the agent one sandbox per research question, with fetch and search tools inside it, a shell for analysis and files for its notes.

On Runtime a research agent's machine costs $0.03125 an hour while the model reads and writes, for 2 vCPUs and 4 GiB, and a new one ran its first Python command 351 ms after the request at the median on 24 September 2026 (speed). Web tools start inside the sandbox with one call, so whatever a fetched page tries to make the agent do happens on a disposable machine, not on your server.

What a research agent does that a chatbot does not

A research agent answers a question by working: it searches, opens sources, downloads a dataset, computes something from it, checks a claim, and writes up what it found with citations. That means three things run on its behalf:

  • Fetching arbitrary URLs, chosen by a model, from pages written by anyone.
  • Running code to parse, count and chart what it downloaded.
  • Keeping state across dozens of steps: downloaded files, notes, a draft.

Each is a risk on your own infrastructure. A fetch from your API server can reach internal addresses. Code the agent writes after reading a hostile page can do what that page told it. A sandbox holds all three in a Firecracker microVM with its own kernel, where private and internal addresses are refused by the host and the machine can be thrown away at the end.

The core loop

Create the sandbox, start the fetch server in it, and hand the agent two kinds of tool: the MCP server's URL for reading the web, and shell and file tools for everything else.

TypeScriptimport { Sandbox } from "withruntime";import { sandboxTools } from "withruntime/tools";await using sbx = await Sandbox.create({  timeoutSeconds: 3600,  idlePauseSeconds: 600,  labels: { agent: "research", question: "q-311" },});// An MCP server for the web, running inside the sandbox.await sbx.mcp.start([{ id: "fetch" }]);const gateway = await sbx.mcp.ready();const fetchServer = gateway.servers[0]; // give its url and gateway.headers to your MCP client// Shell and files for analysis and notes.const tools = sandboxTools(sbx); // runtime_exec, runtime_read_file, runtime_write_file, runtime_list_filesconsole.log(  fetchServer?.url,  tools.map((t) => t.name),);// ... the model's tool-calling loop runs here ...const report = await sbx.files.readText("/workspace/report.md");console.log(report);
Pythonfrom withruntime import Sandboxfrom withruntime.tools import sandbox_toolswith Sandbox.create(    timeout_seconds=3600,    idle_pause_seconds=600,    labels={"agent": "research", "question": "q-311"},) as sbx:    sbx.mcp.start([{"id": "fetch"}])    gateway = sbx.mcp.ready()    fetch_server = gateway["servers"][0]  # its url and gateway["headers"] go to your MCP client    run, read, write, ls = sandbox_tools(sbx)    print(fetch_server["url"])    # ... the model's tool-calling loop runs here ...    print(sbx.files.read_text("/workspace/report.md"))

Tell the model in its system prompt to save every source it uses under /workspace/sources/ and to write its answer to /workspace/report.md. Your code then reads the report and can check that every cited file exists before it shows anything to a user.

Which web tools can run inside

runtime.mcp.catalog() lists the servers Runtime can start in a sandbox, each with its licence, pinned version and the hosts it calls. For research the relevant ones are fetch, Brave Search, Exa, Firecrawl, a Playwright browser, Context7 and memory (MCP servers in a sandbox).

Server (id) What the agent gets
fetch A web page by URL, returned as Markdown
brave-search Web, news, image and local search via Brave's API
exa Exa's search and page contents
firecrawl Scraping, crawling and structured extraction
playwright A headless Chromium the agent drives
memory A knowledge graph kept in a file in the sandbox

A search provider's API key is stored once as a Runtime secret and named when the server starts, as in { id: "brave-search", secrets: { BRAVE_API_KEY: "BRAVE_API_KEY" } }. The server in the sandbox sees only a placeholder, and the host's proxy adds the real value to requests bound for that provider's own hosts, so a page that talks the model into printing its environment gets nothing it can use (secrets sandboxes never see).

Research that takes hours or days

Long questions do not fit one lease. Two settings make that cheap:

  • idlePauseSeconds pauses the sandbox after that many seconds with no request, keeping files, memory and processes. The next tool call wakes it, usually in about half a second, and a paused sandbox pays no compute.
  • A name. Sandbox.getOrCreate("q-311") returns the same sandbox from any process tomorrow, woken if it was paused, so a queue worker can pick the question up where another left it.
TypeScriptimport { Sandbox } from "withruntime";const sbx = await Sandbox.getOrCreate("research-q-311", { idlePauseSeconds: 900 });const notes = await sbx.exec("ls sources | wc -l", { cwd: "/workspace" });console.log(sbx.info.reused, notes.stdout.trim(), "sources so far");

A paused sandbox is billed as storage at $0.08 per decimal GB per 30-day month (pricing).

Narrowing what it can reach

By default a paid sandbox reaches any public host. For a research agent that should read only certain sites, such as a company's own docs, a standards body or a statistics office, pass an allow list at create, or change it mid-task with sbx.network.set({ internet: true, allow: [...] }). A rule applies at once, to open connections too, and root in the guest cannot lift it (the sandbox environment).

What the agent's sandbox covers

Need How Runtime covers it
Fetching URLs a model picked Private and internal addresses refused on the host, for every sandbox
Analysis of what it downloaded Python 3.12 with pandas, NumPy and matplotlib; Node.js 24; sudo apt
Web tools without your servers Catalog MCP servers started inside the sandbox, behind a bearer token
Search keys that cannot leak Secrets injected by the host's proxy, never present in the guest
Pauses for human review Pause keeps memory and processes, 1 to 365 days
Many questions at once 100 sandboxes at once on a paid account to start
Knowing what it did Lifecycle events and per-minute CPU and memory readings

What it costs

Take 500 research tasks a month. Each keeps a 2 vCPU, 4 GiB sandbox running for 20 minutes, and its fetches, parsing and charts use 90 CPU-seconds in all:

TextCPU:    500 × 90 s / 3,600 × $0.025               = $0.31Memory: 500 × 1,200 s / 3,600 × 4 GiB × $0.0075   = $5.00Total:                                              $5.31

About a cent each, at Runtime's rates of $0.025 per vCPU-hour of measured CPU and $0.0075 per GiB-hour (pricing). Model tokens are paid to your model provider, not to Runtime. A new account gets 50 free sandbox hours, about 150 such tasks, with no card.

Start

Terminalclaude mcp add --scope user runtime -- npx -y withruntime mcp

That gives Claude Code, or any MCP client, Runtime's own tools; approve the link it shows once in your browser. For your own agent, install the JavaScript or Python SDK and start from the loop above.

Related: browser automation agent, what MCP is, egress control, pause and resume a sandbox, AI data pipelines.

Facts on this page were checked on 25 September 2026.