Skip to main content
Glama

Sandbox MCP Server

by Tsuchijo
from mcp.server.fastmcp import FastMCP import docker import tempfile import os from pathlib import Path from typing import Dict, List, Optional class SandboxServer: def __init__(self): self.mcp = FastMCP("sandbox-server") self.docker_client = docker.from_env() # Map of container IDs to their info self.containers: Dict[str, dict] = {} # Register all tools self._register_tools() def _register_tools(self): @self.mcp.tool() async def create_container_environment(image: str, persist: bool) -> str: """Create a new container with the specified base image. Args: image: Docker image to use (e.g., python:3.9-slim, ubuntu:latest) Returns: Container ID of the new container """ try: # Create a temporary directory for file mounting temp_dir = tempfile.mkdtemp() # Create container with the temp directory mounted container = self.docker_client.containers.run( image=image, command="tail -f /dev/null", # Keep container running volumes={ temp_dir: { 'bind': '/workspace', 'mode': 'rw' } }, working_dir='/workspace', detach=True, remove=not persist ) # Store container info self.containers[container.id] = { 'temp_dir': temp_dir, 'files': {} } return f"""Container created with ID: {container.id} Working directory is /workspace Container is ready for commands""" except docker.errors.ImageNotFound: return f"Error: Image {image} not found. Please verify the image name." except Exception as e: return f"Error creating container: {str(e)}" @self.mcp.tool() async def create_file_in_container(container_id: str, filename: str, content: str) -> str: """Create a file in the specified container. Args: container_id: ID of the container filename: Name of the file to create content: Content of the file Returns: Status message """ if container_id not in self.containers: return f"Container {container_id} not found" try: container_info = self.containers[container_id] temp_dir = container_info['temp_dir'] # Create file in the mounted directory file_path = Path(temp_dir) / filename with open(file_path, 'w') as f: f.write(content) # Update container info container_info['files'][filename] = content return f"File {filename} has been created in /workspace" except Exception as e: return f"Error creating file: {str(e)}" @self.mcp.tool() async def execute_command_in_container(container_id: str, command: str) -> str: """Execute a command in the specified container. Args: container_id: ID of the container command: Command to execute Returns: Command output """ try: container = self.docker_client.containers.get(container_id) result = container.exec_run( command, workdir='/workspace', environment={ "DEBIAN_FRONTEND": "noninteractive" # For apt-get } ) return result.output.decode('utf-8') except docker.errors.NotFound: return f"Container {container_id} not found" except Exception as e: return f"Error executing command: {str(e)}" @self.mcp.tool() async def save_container_state(container_id: str, name: str) -> str: """Save the current state of a container as a new image. Args: container_id: ID of the container to save name: Name for the saved image (e.g., 'my-python-env:v1') Returns: Instructions for using the saved image """ try: container = self.docker_client.containers.get(container_id) repository, tag = name.split(':') if ':' in name else (name, 'latest') container.commit(repository=repository, tag=tag) return f"""Environment saved as image: {name} To use this environment later: 1. Create new container: docker run -it {name} 2. Or use with this MCP server: create_container("{name}") The image contains all installed packages and configurations.""" except docker.errors.NotFound: return f"Container {container_id} not found" except Exception as e: return f"Error saving container: {str(e)}" @self.mcp.tool() async def export_dockerfile(container_id: str) -> str: """Generate a Dockerfile that recreates the current container state. Args: container_id: ID of the container to export Returns: Dockerfile content and instructions """ try: container = self.docker_client.containers.get(container_id) # Get container info info = container_info = self.containers.get(container_id, {}) image = container.attrs['Config']['Image'] # Get history of commands (if available) history = [] if 'files' in info: history.extend([f"COPY {file} /workspace/{file}" for file in info['files'].keys()]) # Create Dockerfile content dockerfile = [ f"FROM {image}", "WORKDIR /workspace", *history, '\n# Add any additional steps needed:', '# RUN pip install <packages>', '# COPY <src> <dest>', '# etc.' ] return f"""Here's a Dockerfile to recreate this environment: {chr(10).join(dockerfile)} To use this Dockerfile: 1. Save it to a file named 'Dockerfile' 2. Build: docker build -t your-image-name . 3. Run: docker run -it your-image-name""" except docker.errors.NotFound: return f"Container {container_id} not found" except Exception as e: return f"Error generating Dockerfile: {str(e)}" @self.mcp.tool() async def exit_container(container_id: str, force: bool = False) -> str: """Stop and remove a running container. Args: container_id: ID of the container to stop and remove force: Force remove the container even if it's running Returns: Status message about container cleanup """ try: container = self.docker_client.containers.get(container_id) container_info = self.containers.get(container_id, {}) # Try to stop container gracefully first if not force: try: container.stop(timeout=10) except Exception as e: return f"Failed to stop container gracefully: {str(e)}. Try using force=True if needed." # Remove container and cleanup container.remove(force=force) # Clean up temp directory if it exists if 'temp_dir' in container_info: try: import shutil shutil.rmtree(container_info['temp_dir']) except Exception as e: print(f"Warning: Failed to remove temp directory: {str(e)}") # Remove from our tracking if container_id in self.containers: del self.containers[container_id] return f"Container {container_id} has been stopped and removed." except docker.errors.NotFound: return f"Container {container_id} not found" except Exception as e: return f"Error cleaning up container: {str(e)}" def run(self): """Start the MCP server.""" self.mcp.run() def main(): server = SandboxServer() server.run() if __name__ == "__main__": main()

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Tsuchijo/sandbox-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server