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:
idlePauseSecondspauses 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 mcpThat 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.