Skip to content
Runtime

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

Give the agent one sandbox per research question. Put 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. 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 results from it, checks a claim, and writes up what it found with citations. 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 one is a risk on your own infrastructure. A fetch from your API server can reach internal addresses. Code the agent writes after it reads a hostile page can do what that page told it. A sandbox runs all three in a Firecracker microVM with its own kernel. The host refuses private and internal addresses there, and the machine can be discarded at the end.

The core loop

Create the sandbox, start the fetch server in it, and give 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. It 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 that Runtime can start in a sandbox. Each entry shows its license, 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. It is 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. The host's proxy adds the real value to requests bound for that provider's own hosts. So a page that tricks the model into printing its environment gets nothing it can use (secrets sandboxes never see).

Research that takes hours or days

A sandbox has no time limit, so a long question is never cut off. Two settings make the waiting cheap:

  • idlePauseSeconds pauses the sandbox after that many seconds with nothing happening in it. The default is 300 unless you set another value. The pause keeps files, memory and processes. 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 immediately, including to open connections. Root in the guest cannot remove it (the sandbox environment).

What the agent's sandbox covers

Need How Runtime covers it
Fetching URLs a model picked The host refuses private and internal addresses, 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 The host's proxy injects secrets; they are never present in the guest
Pauses for human review Pause keeps memory and processes while you have credit
Many questions at the same time 100 sandboxes at the same time on a paid account
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. Its fetches, parsing and charts use 90 CPU-seconds in all:

CPU
500 × 90 s / 3,600 × $0.025
$0.31
Memory
500 × 1,200 s / 3,600 × 4 GiB × $0.0075
$5.00
Total
$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). You pay for model tokens to your model provider, not to Runtime. A new account gets 100 free hours of a 1 GB machine in its first 30 days, about 75 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 26 October 2026.

Related.

100 free hoursin your first 30 days.

of a 1 GB machine

  • No credit card
  • Four sandboxes at once, 2 vCPU and 4 GiB each
  • Then prepaid credit from $10, no plan fee
Start free, no card
Start free, no card