pull_file_from_sandbox
Copy files from Modal sandbox environments to your local system for analysis, backup, or debugging purposes.
Instructions
Copies a file from a Modal sandbox to the local filesystem.
Parameters:
- sandbox_id: The unique identifier of the sandbox
- sandbox_path: Path to the file in the sandbox
- local_path: Destination path on local filesystem
Returns a PullFileFromSandboxResponse containing:
- success: Boolean indicating if copy was successful
- message: Descriptive message about the copy operation
- sandbox_path: The source path in sandbox
- local_path: The destination path on local filesystem
- file_size: Size of the file in bytes
This tool is useful for:
- Retrieving output files from sandbox executions
- Backing up sandbox data
- Analyzing sandbox-generated content locally
- Debugging sandbox operations
The tool will:
1. Verify sandbox and source file exist
2. Create local destination directory if needed
3. Copy file contents from sandbox to local system
4. Return status of the operation
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sandbox_id | Yes | ||
| sandbox_path | Yes | ||
| local_path | Yes |
Implementation Reference
- The main asynchronous handler function implementing the pull_file_from_sandbox tool. It retrieves the sandbox, checks its status, reads the file content using a thread helper, writes it to the local path, and returns a response.async def pull_file_from_sandbox( self, sandbox_id: str, sandbox_path: str, local_path: str ) -> PullFileFromSandboxResponse: # Get sandbox from Modal using from_id modal_sandbox = await modal.Sandbox.from_id.aio(sandbox_id) # Check if sandbox is running before copying file from sandbox sandbox_status = await modal_sandbox.poll.aio() if sandbox_status is not None: raise ToolError(f"Sandbox {sandbox_id} is not running") # Read from sandbox using thread executor content = await self._read_sandbox_file_in_thread(modal_sandbox, sandbox_path, 'rb') file_size = len(content) # Write to local file asynchronously makedirs(path.dirname(local_path), exist_ok=True) async with aiofiles.open(local_path, 'wb') as file_pointer: await file_pointer.write(content) logger.info(f"Copied file from {sandbox_path} to {local_path} from sandbox {sandbox_id}") return PullFileFromSandboxResponse( success=True, message=f"File copied successfully to {local_path}", file_size=file_size, sandbox_path=sandbox_path, local_path=local_path, )
- src/mcp4modal_sandbox/backend/mcp_server.py:126-129 (registration)Tool registration in the FastMCP app, binding the name, description, and handler function.mcp_app.tool( name="pull_file_from_sandbox", description=ToolDescriptions.PULL_FILE_FROM_SANDBOX, )(self.pull_file_from_sandbox)
- Pydantic BaseModel defining the response structure for the pull_file_from_sandbox tool.class PullFileFromSandboxResponse(BaseModel): success: bool message: str sandbox_path: str local_path: str file_size: int
- Helper method to asynchronously read file contents from the Modal Sandbox using a thread pool executor to avoid blocking the event loop.async def _read_sandbox_file_in_thread(self, modal_sandbox, file_path: str, mode: str = 'rb'): def _sync_read(): with modal_sandbox.open(file_path, mode) as f: return f.read() loop = asyncio.get_event_loop() return await loop.run_in_executor(self.thread_pool_executor, _sync_read)