Back to blog posts

11 min

How to run Anthropic tool use code execution with Blaxel

Run Anthropic tool use code execution safely in isolated microVM sandboxes. Learn how to connect Claude Code to a Next.js codebase via MCP using Blaxel.

Nicolas LecomteNico is a founder of Blaxel, who usually writes about AI, agentics, and the future of AI runtimes.

Claude can call your tools, but the tools need somewhere to run. A common first implementation runs tool-call code on the application server. A Python script Claude generated then shares your application server's filesystem and environment variables, along with its network access. One malicious or buggy execution can read your API keys. It can also reach internal services or corrupt the application server.

Two Blaxel sandboxes provide an isolated environment. One hosts a Next.js codebase, and the other runs Claude Code. Model Context Protocol (MCP) connects them. Tool calls then run without touching your application server.

Anthropic's tool use lets Claude call external functions during a conversation. When those functions run code, they execute model-generated output. You didn't write that output and can't fully predict it. This includes scripts, shell commands, file operations, and package installs. Such code needs an isolated environment with its own filesystem and process space. A bad execution remains isolated from the application server and neighboring tenants. Its network access and credentials still require explicit controls.

Why tool use code execution needs a sandbox

Anthropic's tool use API puts execution responsibility on you. Your application executes requested functions and sends the results back to Claude. Pre-defined tools with controlled behavior can run safely on your application server. Treat every model-generated command as hostile input before it reaches an execution sink. Code Claude generates from user prompts becomes risky when tools execute user-influenced inputs. File operations on uploaded content and shell commands assembled from conversation context carry the same risk. Never pass model output directly into an unsandboxed application server shell, exec, or eval. Apply a zero-trust approach before model output reaches any execution sink. Validate and isolate that output because direct execution can result in remote code execution. Sandboxed processExecute provides the controlled execution path.

A sandbox isolates tool execution in a dedicated environment. That environment has its own filesystem and process space. If a tool call runs hostile code, delete the sandbox and create a fresh one. Your application server keeps running untouched. Network routes and sandbox credentials remain reachable, so apply least-privilege controls to both. For arbitrary model-generated code, a container's shared host kernel provides a thinner boundary. A microVM instead provides hardware-enforced isolation. Blaxel uses Firecracker microVMs, the same microVM approach used by AWS Lambda.

How to set up Blaxel sandboxes for Anthropic tool use

  • Install the Blaxel CLI and SDK
  • Create two sandboxes
  • Connect Claude Code to the hosted codebase over MCP
  • Run a tool call task against it

One sandbox (nextjs-sandbox) hosts the target application and its dev server. The other (claude-sandbox) runs Claude Code, which operates on the codebase. The steps follow Blaxel's Claude Code tutorial. It also includes the full Python variant of every script.

1. Install the Blaxel CLI and SDK

Authenticate the CLI and install the SDK in your chosen language, then export your API key. The CLI handles login and terminal access to sandboxes. The SDK handles sandbox creation and lifecycle from your own code.

Authenticate first:

bl login

That login later lets bl connect open a terminal inside a sandbox.

Install the SDK:

# TypeScript
npm install @blaxel/core

# Python
pip install blaxel

Blaxel supports alternative authentication paths. The SDK can use the CLI login session. It can also read environment variables such as BL_WORKSPACE and BL_API_KEY. The creation script reads a separate value, BLAXEL_API_KEY, directly through process.env. It then forwards that value into the Claude Code sandbox. Export it before you run anything:

export BLAXEL_API_KEY=YOUR-BLAXEL-API-KEY-HERE

Step two passes this value into claude-sandbox through the envs array. Claude Code later uses it to authenticate MCP requests.

The toolchain stops there. You don't need to provision infrastructure. You also don't configure an image registry because both sandboxes use Blaxel's pre-built templates.

2. Create the application and Claude Code sandboxes

The creation script creates the application sandbox and starts its dev server. It then generates a tokenized preview URL and prints the MCP server URL. Finally, it creates the Claude Code sandbox. The TypeScript version follows:

import { SandboxInstance } from "@blaxel/core";

async function main() {
  const blaxelApiKey = process.env.BLAXEL_API_KEY;
  if (!blaxelApiKey) {
    throw new Error("BLAXEL_API_KEY environment variable is not set");
  }

  // Create application sandbox
  const appSandbox = await SandboxInstance.createIfNotExists({
    name: "nextjs-sandbox",
    image: "blaxel/nextjs:latest",
    memory: 4096,
    region: "us-pdx-1",
  });

  // Start dev server
  await appSandbox.process.exec({
    workingDir: "/blaxel/app",
    command: "npm run dev -- --hostname $HOST --port 3000"
  });

  // Create preview URL
  const appPreview = await appSandbox.previews.createIfNotExists({
    metadata: { name: "app-preview" },
    spec: {
      port: 3000,
      public: false,
    }
  });

  // Create preview token
  const expiresAt = new Date(Date.now() + 1440 * 60 * 1000);
  const token = await appPreview.tokens.create(expiresAt);

  console.log(`Preview URL: ${appPreview.spec.url}?bl_preview_token=${token.value}`);
  console.log(`MCP URL: ${appSandbox.metadata.url}/mcp`);

  // Create Claude Code sandbox, passing BLAXEL_API_KEY as an env var
  const claudeSandbox = await SandboxInstance.createIfNotExists({
    name: "claude-sandbox",
    image: "blaxel/claude-code:latest",
    memory: 4096,
    region: "us-pdx-1",
    envs: [
      { name: "BLAXEL_API_KEY", value: blaxelApiKey }
    ]
  });
}

main();

Both calls share four parameters: a name, an image, memory in megabytes, and a region. The memory: 4096 setting requests 4096 MB, or 4 GB, for each sandbox. That allocation supports the development server as well as dependency installation and code analysis. The region: "us-pdx-1" setting places both sandboxes in the same region. On the preview, public: false requires the token created on the next line.

The images differ between the two sandboxes. blaxel/nextjs:latest ships a Next.js environment. blaxel/claude-code:latest ships the Claude Code CLI. The second sandbox's envs array makes the architecture work. Passing BLAXEL_API_KEY into Claude Code authenticates MCP requests to other Blaxel sandboxes. Processes in that sandbox can use those credentials. Scope and rotate them appropriately.

Lifecycle settings belong in the same create call. A ttl value sets a maximum age from creation. Blaxel deletes the sandbox after that age. Without an expiration policy, a sandbox can remain in standby indefinitely. Set a TTL when you require automatic cleanup.

Tag both sandboxes with the same external IDs value at creation. This value is typically your session or user ID. A later getByExternalId call returns that session's sandbox without scanning the workspace. External IDs are capped at 64 characters and allow alphanumerics and dashes. Validate and normalize session IDs before creating the sandboxes.

Run the script with bun index.ts, or use python main.py for the Python version. Copy the preview URL and MCP URL from the console output.

3. Connect Claude Code to the application sandbox via MCP

This step registers the application sandbox's MCP server as a tool source inside Claude Code. Open a terminal session in the Claude Code sandbox:

bl connect sandbox claude-sandbox

Confirm the Claude Code binary is available:

claude --version

Add the application sandbox's MCP server and replace the placeholder with the MCP URL from step two:

claude mcp add --transport http sandbox YOUR-SANDBOX-MCP-URL-HERE \
  --header "Authorization: Bearer $BLAXEL_API_KEY"

Every registration requires an Authorization header with a bearer token; the sandbox MCP endpoint does not support OAuth. The value must also resolve inside the sandbox shell, not on your laptop. $BLAXEL_API_KEY expands in whichever shell runs the command. Here, that shell is inside claude-sandbox.

Step two injected the key for this registration. It avoids requiring you to type the key at the prompt. A manually entered key also lands in the sandbox shell history.

Verify the connection. claude mcp list should show the sandbox server as connected.

Every Blaxel sandbox exposes a built-in MCP server at https://<SANDBOX_BASE_URL>/mcp. A bearer token authenticates that server. It offers structured tool calls in three groups:

  • Filesystem (fsReadFile, fsWriteFile, fsListDirectory): read, write, and list files inside the sandbox.
  • Processes (processExecute, processGetLogs, processKill): start commands, pull their output, and stop them.
  • Code search and editing (codegenCodebaseSearch, codegenGrepSearch, codegenEditFile): search the codebase and apply edits. codegenEditFile requires a Morph or Relace API key.

Claude Code uses these tools to operate the application sandbox remotely.

4. Run a coding task and verify execution

The final step starts Claude Code and gives it a task. That task exercises the MCP connection end to end. Launch the agent from inside the Claude Code sandbox:

claude

Claude Code may require trust verification for a newly added MCP server. Approve the sandbox server if it prompts you. Give it a task targeting the hosted Next.js codebase:

Create a landing page for a new board game with an interactive demo.
Make all changes only in the sandbox.

Claude Code inspects the Next.js codebase through the MCP code-search tools. It writes changes with filesystem tools and restarts processes as needed. MCP tool names can appear in the transcript while the agent works; documented examples follow the mcp__server__tool pattern, including mcp__filesystem__read_file. Other examples are mcp__memory__create_entities and mcp__github__search_repositories.

Failures land inside the sandbox too. A processExecute call may run a command that exits non-zero. It returns the command's output to Claude Code as tool output. Claude Code can read that output and retry with a corrected command. If the retry loop stalls, retrieve the same output with processGetLogs. You can read the process output.

That failure remains confined to the application sandbox, and its output remains available for inspection. The two-sandbox layout separates the Claude Code runtime from the application runtime. The failing command ran in a microVM you can delete and recreate.

The dev server from step two is already running. Results therefore appear at the preview URL while the agent works. Open that URL in a browser to verify the changes landed. Use the preview URL as the verification boundary. If changes do not appear there, inspect sandbox files and process logs rather than your local machine or application servers.

How to debug a broken Claude Code to sandbox connection

claude mcp list may report that the sandbox server needs authentication. The Authorization: Bearer header was probably missing from the registration command. An empty $BLAXEL_API_KEY inside the sandbox shell produces the same result. Echo the variable inside claude-sandbox to confirm it holds the key. Rerun claude mcp add with the header and check the list again.

$BLAXEL_API_KEY may be unset inside claude-sandbox. This happens when the variable was absent from the envs array during creation. Environment variables are fixed when the sandbox is created. Delete the sandbox and recreate it with the envs entry shown in step two.

The preview URL may load nothing. Check whether the dev server bound to $HOST. A server listening only on localhost inside the microVM produces this symptom. Keep --hostname $HOST --port 3000 exactly as written in the exec command. Retrieve process output with processGetLogs to confirm the server is running. An authorization error later may indicate an expired preview token. Create a new token and append the ?bl_preview_token= query parameter to rebuild the URL.

How to trace tool calls between Claude and the sandbox

Trace requests, results, and execution boundaries

For debugging or a security review, trace the request through the following path. Claude returns stop_reason: "tool_use" with a tool name and input object. Claude Code maps that response to the matching MCP tool. It uses fsWriteFile for a file write or processExecute for a command.

Claude Code sends the request over HTTPS to the application sandbox's /mcp endpoint. The bearer token from step three authenticates the request. The MCP server then routes the operation to the sandbox, which runs it inside the isolated environment.

The MCP server returns the operation's output. That output returns to Claude in a tool_result block on the next request. The block carries the answered call's tool_use_id. Claude then issues another tool_use block or returns plain text. The loop ends when a response contains no tool call.

Tracing one call by hand requires following those two identifiers. Find the tool_use_id in the request carrying stop_reason: "tool_use". Find the tool_result block quoting that ID on the following request. For processes, processGetLogs provides the raw stdout and stderr captured by the sandbox. This is the same text Claude saw as tool output. Plain text without another tool_use block indicates normal termination.

Execution and file operations are attributable to the application sandbox's microVM. Claude Code invokes structured tools over MCP without receiving shell access to a host. During a review, verify the MCP endpoint and sandbox identity, then correlate them with the per-process output to confirm that boundary. Explicitly granted network routes and credentials remain available and require least-privilege controls. MicroVM isolation prevents a prompt-injected agent from targeting a shared host kernel. This boundary is substantially stronger than a container, though no boundary is absolute. Per-process output remains retrievable with processGetLogs for later inspection.

Give each trust boundary its own environment rather than using a shared pool. Follow Anthropic's sandbox guidance for production multi-user deployments. Give each user session its own sandbox pair, isolated in separate microVMs. Tag both with the session ID. Set a TTL on both so abandoned pairs delete themselves automatically. Sandbox state survives standby, not deletion. Route anything that must outlive the pair to a volume.

How to secure Anthropic tool use code execution with Blaxel sandboxes

Isolate execution, restrict access, and manage state

Assign model-generated code a dedicated microVM identity and lifecycle rather than your application's privileges. This makes cleanup and process inspection properties of the execution environment. Credential scoping becomes one too. For coding agents and PR review agents, isolation belongs in the architecture from day one.

Use domain filtering to restrict reachable destinations. Use proxy secrets injection so tools can access credentials without receiving their raw values. Dedicated egress gateways can provide static outbound IPs and are currently in private preview. Combine these controls with narrowly scoped credentials and sandbox-specific network access.

Blaxel, the perpetual sandbox platform, provides the execution layer for Anthropic tool use. Blaxel Sandboxes are microVM-isolated environments with a built-in MCP server on every sandbox. Agents operate them through structured tool calls. Sandboxes resume from standby in under 25 milliseconds. The snapshot keeps the filesystem and running processes intact across that transition.

Sandboxes return to standby after 15 seconds of network inactivity. A pair can remain in standby indefinitely when no expiration policy is configured. In standby, you pay for snapshot storage and volumes rather than compute. Use a volume for state that requires guaranteed long-term persistence.

Talk to the team at blaxel.ai/contact about your tool-use architecture. Start building at app.blaxel.ai.

FAQ

How do tool use, sandboxes, and MCP work together?

Tool use defines the requested action, MCP transports it, and the sandbox sets the execution boundary. In this setup, verify each layer independently by inspecting Claude's tool request and confirming MCP bearer authentication. Then check sandbox process logs and files. This separation helps locate failures by distinguishing model behavior from transport and runtime errors. Keep the bearer token scoped to the intended sandbox pair.

How do custom images and concurrent user sessions change this setup?

Use custom images when the default templates do not fit: scaffold with bl new sandbox, include Blaxel's sandbox API binary, push the image, and pass its ID as image. For concurrent users, create a separately named application-and-Claude sandbox pair per session. Tag pairs with external IDs and set TTLs for cleanup. Use volumes when data must survive sandbox deletion.

Can I use a custom execution environment with Claude and Blaxel?

Yes. Use custom Docker images to run Claude's tool calls in a pre-configured environment. Include the build toolchain and language runtimes your workload requires. Add its dependencies to the image. The resulting sandbox still provides microVM isolation and keeps generated code and shell commands away from your application server, sensitive filesystem, environment variables, and other host resources.

Related articles