Skip to main content

Overview

SuperBox uses AWS Lambda to execute MCP servers in completely isolated sandbox environments, ensuring security, scalability, and reliability.

Complete Isolation

Each execution runs in its own container

Resource Limits

CPU, memory, and time constraints

Network Control

Restricted network access

Auto-Scaling

Handles 1000+ concurrent executions

Sandbox Architecture

Lambda Execution Flow

1

Request Reception

API server receives tool execution request:
POST /execute/weather-mcp-123
{
  "tool": "get_weather",
  "parameters": {
    "city": "San Francisco",
    "units": "metric"
  }
}
2

Lambda Invocation

API server invokes Lambda function:
executionReq := &ExecutionRequest{
    ServerID:   "weather-mcp-123",
    ToolName:   "get_weather",
    Parameters: map[string]interface{}{
        "city":  "San Francisco",
        "units": "metric",
    },
    Timeout: 30,
}

payload, _ := json.Marshal(executionReq)

result, err := lambdaClient.Invoke(ctx, &lambda.InvokeInput{
    FunctionName: aws.String("superbox-executor"),
    Payload:      payload,
    LogType:      types.LogTypeTail,
})
3

Sandbox Bootstrap

Lambda container initializes: 1. Download MCP server code from S3 2. Extract to /tmp directory 3. Install Python/Node.js dependencies 4. Load MCP server configuration 5. Initialize server instance
4

Tool Execution

Execute requested tool in sandbox:
# Inside Lambda handler
async def execute_tool(server_id, tool_name, parameters):
    # Load server
    server = await load_mcp_server(server_id)
    
    # Call tool
    result = await server.call_tool(
        name=tool_name,
        arguments=parameters
    )
    
    return result
5

Response Return

Return execution result:
{
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Weather in San Francisco: 18°C, clear skies"
      }
    ]
  },
  "duration_ms": 245,
  "logs": [
    "INFO: Server initialized",
    "INFO: Executing tool get_weather",
    "INFO: API call successful"
  ]
}

Security Isolation

Container Isolation

Each Lambda function runs in an isolated container:
  • Separate file system
  • Independent process tree
  • Isolated network namespace
  • No cross-container access
Containers are destroyed after execution, leaving no traces

Lambda Handler Implementation

Python Handler

import json
import os
import sys
import tempfile
import traceback
from pathlib import Path
import boto3
import zipfile
import subprocess

s3_client = boto3.client('s3')
S3_BUCKET = os.environ['S3_BUCKET']

def handler(event, context):
  """
  Main Lambda handler for MCP server execution
  """
  try:
      # Parse request
      server_id = event['server_id']
      tool_name = event['tool_name']
      parameters = event.get('parameters', {})
      timeout = event.get('timeout', 30)

      # Setup execution environment
      server_path = setup_server(server_id)

      # Execute tool
      start_time = time.time()
      result = execute_mcp_tool(server_path, tool_name, parameters, timeout)
      duration_ms = int((time.time() - start_time) * 1000)

      return {
          'statusCode': 200,
          'body': json.dumps({
              'result': result,
              'duration_ms': duration_ms,
              'server_id': server_id,
              'tool_name': tool_name
          })
      }

  except TimeoutError as e:
      return {
          'statusCode': 408,
          'body': json.dumps({
              'error': 'Execution timeout',
              'message': str(e)
          })
      }

  except Exception as e:
      return {
          'statusCode': 500,
          'body': json.dumps({
              'error': type(e).__name__,
              'message': str(e),
              'traceback': traceback.format_exc()
          })
      }

def setup_server(server_id):
  """
  Download and setup MCP server from S3
  """
  # Download from S3
  local_zip = f'/tmp/{server_id}.zip'
  server_dir = f'/tmp/{server_id}'

  s3_key = f'servers/{server_id}/latest.zip'
  s3_client.download_file(S3_BUCKET, s3_key, local_zip)

  # Extract
  with zipfile.ZipFile(local_zip, 'r') as zip_ref:
      zip_ref.extractall(server_dir)

  # Install dependencies
  requirements_file = Path(server_dir) / 'requirements.txt'
  if requirements_file.exists():
      subprocess.run([
          sys.executable, '-m', 'pip', 'install',
          '-r', str(requirements_file),
          '-t', server_dir,
          '--quiet'
      ], check=True)

  return server_dir

def execute_mcp_tool(server_path, tool_name, parameters, timeout):
  """
  Execute MCP tool in subprocess with timeout
  """
  # Add server path to sys.path
  sys.path.insert(0, server_path)

  # Import and run server
  import asyncio
  from mcp_server import server

  async def run_tool():
      # Call tool
      result = await server.call_tool(
          name=tool_name,
          arguments=parameters
      )
      return result

  # Run with timeout
  loop = asyncio.get_event_loop()
  task = loop.create_task(run_tool())

  try:
      result = loop.run_until_complete(
          asyncio.wait_for(task, timeout=timeout)
      )
      return result
  except asyncio.TimeoutError:
      task.cancel()
      raise TimeoutError(f'Execution exceeded {timeout}s timeout')

Runtime Environment

Pre-installed packages:
boto3==1.34.0
botocore==1.34.0
urllib3==2.0.7
requests==2.31.0
certifi==2023.11.17
Custom packages installed per-execution from requirements.txt
Pre-installed packages:
{
  "dependencies": {
    "aws-sdk": "^2.1500.0",
    "@aws-sdk/client-s3": "^3.450.0"
  }
}
Custom packages from package.json installed during cold start
Available to MCP servers:
AWS_REGION=ap-south-1
AWS_EXECUTION_ENV=AWS_Lambda_python3.11 
LAMBDA_TASK_ROOT=/var/task
LAMBDA_RUNTIME_DIR=/var/runtime 
# Custom variables 
SERVER_ID=weather-mcp-123
SUPERBOX_ENV=production 
LOG_LEVEL=info
Shared dependencies via Lambda Layers:
  • MCP SDK Layer - Model Context Protocol SDK
  • Common Libraries Layer - httpx, aiohttp, etc.
  • ML Libraries Layer - numpy, pandas (optional)
/opt/python/lib/python3.11/site-packages/
├── mcp/
├── httpx/
├── aiohttp/
└── ...

Cold Start Optimization

Cold starts occur when Lambda creates a new container:
  • Container initialization: ~500ms
  • Runtime bootstrap: ~200ms
  • Dependency installation: ~2-5s
  • Total: 3-6 seconds
Cold starts impact user experience for first requests

Monitoring & Observability

CloudWatch Logs

All execution logs captured:
  • Server initialization
  • Tool invocations
  • Error stack traces
  • Performance metrics

CloudWatch Metrics

Lambda metrics: - Invocations - Duration - Errors - Throttles - Concurrent executions

X-Ray Tracing

Distributed tracing: - End-to-end latency - Service dependencies - Bottleneck identification

Custom Metrics

Business metrics:
  • Tool execution counts
  • Success/error rates
  • Average duration per tool

Example CloudWatch Dashboard

{
  "widgets": [
    {
      "type": "metric",
      "properties": {
        "metrics": [
          ["AWS/Lambda", "Invocations", { "stat": "Sum" }],
          [".", "Errors", { "stat": "Sum" }],
          [".", "Throttles", { "stat": "Sum" }]
        ],
        "period": 300,
        "stat": "Sum",
        "region": "us-east-1",
        "title": "Lambda Executions"
      }
    },
    {
      "type": "metric",
      "properties": {
        "metrics": [
          ["AWS/Lambda", "Duration", { "stat": "Average" }],
          ["...", { "stat": "p99" }]
        ],
        "period": 300,
        "region": "us-east-1",
        "title": "Execution Duration"
      }
    }
  ]
}

Cost Optimization

AWS Lambda pricing:
  • Requests: $0.20 per 1M requests
  • Duration: $0.0000166667 per GB-second
  • Free tier: 1M requests, 400,000 GB-seconds/month
Example cost calculation:
Monthly executions: 10,000,000
Average duration: 250ms
Memory: 1024 MB

Request cost: (10M - 1M) × $0.20 / 1M = $1.80
Duration cost: 10M × 0.25s × 1GB × $0.0000166667 = $41.67

Total: $43.47/month

Error Handling

Handle execution timeouts gracefully:
try:
    result = await asyncio.wait_for(
        execute_tool(tool_name, params),
        timeout=30
    )
except asyncio.TimeoutError:
    return {
        'statusCode': 408,
        'body': {
            'error': 'Execution timeout',
            'message': 'Tool execution exceeded 30s limit'
        }
    }
Monitor memory usage:
import psutil

def check_memory():
    process = psutil.Process()
    memory_mb = process.memory_info().rss / 1024 / 1024
    
    if memory_mb > 900:  # 1024 MB limit
        raise MemoryError(f'Memory usage: {memory_mb:.0f}MB')
Handle missing dependencies:
try:
    import required_package
except ImportError as e:
    return {
        'statusCode': 500,
        'body': {
            'error': 'Missing dependency',
            'message': str(e),
            'hint': 'Add package to requirements.txt'
        }
    }

Next Steps