MCP execution utilities for sandboxed code execution with OS-level isolation
npm install @justanothermldude/mcp-execMCP execution utilities for sandboxed TypeScript/JavaScript code execution with OS-level isolation.
``bash`
npm install @meta-mcp/exec
This package provides secure code execution capabilities with:
- Sandbox Isolation: OS-level sandboxing via @anthropic-ai/sandbox-runtime (sandbox-exec on macOS, bubblewrap on Linux)
- MCP Bridge: HTTP bridge allowing sandboxed code to call MCP tools
- Wrapper Generation: Auto-generate type-safe TypeScript wrappers for MCP tools
`typescript
import { executeCode } from '@meta-mcp/exec';
const result = await executeCode({
code: 'console.log("Hello from sandbox!")',
timeout_ms: 5000,
});
console.log(result.output); // ['Hello from sandbox!']
console.log(result.durationMs); // execution time in ms
`
`bashStart the mcp-exec server
npx @meta-mcp/exec
API Reference
$3
Execute code in a sandboxed environment.
`typescript
import { executeCode } from '@meta-mcp/exec';const result = await executeCode({
code: string; // TypeScript/JavaScript code to execute
timeout_ms?: number; // Max execution time (default: 30000)
});
// Result type
interface ExecutionResult {
output: string[]; // stdout lines
error?: string; // stderr content
durationMs: number; // execution time
}
`$3
Create a custom executor with specific configuration:
`typescript
import { SandboxExecutor, createExecutor } from '@meta-mcp/exec';// Using factory function
const executor = createExecutor({
mcpBridgePort: 4000,
additionalWritePaths: ['/tmp/my-app'],
enableLogMonitor: true,
});
// Using class directly
const executor = new SandboxExecutor({
mcpBridgePort: 4000,
additionalWritePaths: ['/tmp/my-app'],
});
// Execute code
const result = await executor.execute('console.log(1 + 1)', 5000);
// Check status
executor.checkDependencies(); // true if sandbox-runtime available
executor.isSandboxingEnabled(); // true if OS sandboxing active
// Update config
executor.updateConfig({ mcpBridgePort: 5000 });
// Clean up
await executor.reset();
`$3
HTTP bridge for MCP tool access from sandboxed code:
`typescript
import { MCPBridge } from '@meta-mcp/exec';
import { ServerPool, createConnection, getServerConfig } from '@meta-mcp/core';// Create server pool
const connectionFactory = async (serverId: string) => {
const config = getServerConfig(serverId);
if (!config) throw new Error(
Server not found: ${serverId});
return createConnection(config);
};
const pool = new ServerPool(connectionFactory);// Create and start bridge
const bridge = new MCPBridge(pool, {
port: 3000,
host: '127.0.0.1',
});
await bridge.start();
// Bridge endpoints:
// GET /health - Health check
// POST /call - Execute MCP tool call
// Check status
bridge.isRunning(); // true
bridge.getPort(); // 3000
bridge.getHost(); // '127.0.0.1'
// Stop bridge
await bridge.stop();
`$3
Generate type-safe TypeScript wrappers for MCP tools:
`typescript
import { generateToolWrapper, generateServerModule } from '@meta-mcp/exec';
import type { ToolDefinition } from '@meta-mcp/core';// Generate wrapper for single tool
const tool: ToolDefinition = {
name: 'read_file',
description: 'Read contents of a file',
inputSchema: {
type: 'object',
properties: {
path: { type: 'string', description: 'File path to read' },
},
required: ['path'],
},
};
const wrapper = generateToolWrapper(tool, 'filesystem');
// Generates TypeScript function that calls bridge endpoint
// Generate module for all server tools
const tools: ToolDefinition[] = [/ ... /];
const module = generateServerModule(tools, 'filesystem');
// Generates complete TypeScript module with all tool wrappers
`Generated wrapper example:
`typescript
export interface ReadFileInput {
/* File path to read /
path: string;
}/**
* Read contents of a file
* @param input.path - File path to read
* @returns Promise resolving to tool result
*/
export async function read_file(input: ReadFileInput): Promise {
const response = await fetch('http://localhost:3000/call', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
server_name: 'filesystem',
tool_name: 'read_file',
arguments: input,
}),
});
if (!response.ok) {
throw new Error(
Tool call failed: ${response.statusText});
} return response.json();
}
`$3
Create the mcp-exec MCP server programmatically:
`typescript
import { createMcpExecServer } from '@meta-mcp/exec';
import { ServerPool, createConnection, getServerConfig } from '@meta-mcp/core';// Create pool
const connectionFactory = async (serverId: string) => {
const config = getServerConfig(serverId);
if (!config) throw new Error(
Server not found: ${serverId});
return createConnection(config);
};
const pool = new ServerPool(connectionFactory);// Create server
const { server, listToolsHandler, callToolHandler, shutdown } = createMcpExecServer(pool);
// List available tools
const tools = await listToolsHandler();
// => { tools: [{ name: 'execute_code_with_wrappers', ... }, ...] }
// Call execute_code_with_wrappers tool
const result = await callToolHandler({
name: 'execute_code_with_wrappers',
arguments: {
code: 'console.log("Hello!")',
wrappers: [], // optional: MCP server names to generate typed wrappers for
},
});
// Graceful shutdown
await shutdown();
`Types
`typescript
import type {
ExecuteCodeInput,
ExecutionResult,
SandboxExecutorConfig,
MCPBridgeConfig,
CallRequest,
CallResponse,
} from '@meta-mcp/exec';interface ExecuteCodeInput {
code: string;
timeout_ms?: number;
}
interface ExecutionResult {
output: string[];
error?: string;
durationMs: number;
}
interface SandboxExecutorConfig {
mcpBridgePort?: number;
additionalWritePaths?: string[];
enableLogMonitor?: boolean;
}
interface MCPBridgeConfig {
port?: number;
host?: string;
}
interface CallRequest {
server: string;
tool: string;
args?: Record;
}
interface CallResponse {
success: boolean;
content?: unknown[];
isError?: boolean;
error?: string;
}
`CLI Usage
`bash
Start the MCP server
mcp-execShow version
mcp-exec --versionShow help
mcp-exec --help
`Using Wrappers in Sandboxed Code
When code runs in the sandbox, it can call MCP tools via the HTTP bridge:
`typescript
// Code running inside sandbox
const result = await fetch('http://localhost:3000/call', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
server: 'filesystem',
tool: 'read_file',
args: { path: '/tmp/test.txt' },
}),
});const data = await result.json();
console.log(data.content[0].text);
`Or use generated wrappers:
`typescript
// Import generated wrappers
import { read_file, write_file } from './filesystem-wrappers';// Type-safe tool calls
const content = await read_file({ path: '/tmp/test.txt' });
await write_file({ path: '/tmp/output.txt', content: 'Hello!' });
`Case-Agnostic Access
Server and tool names support flexible, case-agnostic access via Proxy-based fuzzy resolution. This means you don't need to remember exact naming conventions—camelCase, snake_case, and kebab-case all work interchangeably.
$3
All of these access patterns resolve to the same server:
`typescript
// Original server name: "corp-jira"
mcp['corp-jira'] // Bracket notation with original name
mcp.corpJira // camelCase
mcp.corp_jira // snake_case
mcp.corpjira // Lowercase without separators
`$3
Similarly, tool names within a server support fuzzy matching:
`typescript
// Original tool name: "search_jira_issues"
const server = mcp['corp-jira'];server.search_jira_issues // Original snake_case
server.searchJiraIssues // camelCase
server.searchjiraissues // Lowercase
server['search-jira-issues'] // kebab-case via bracket notation
`$3
The resolution uses a two-step approach:
1. Fast-path: If the exact property name exists, it's returned immediately
2. Fuzzy match: The requested name is normalized (lowercased, hyphens/underscores removed) and compared against normalized versions of all available names
$3
When a property doesn't match any available option, a
TypeError is thrown with helpful suggestions:`typescript
const server = mcp['corp-jira'];
server.nonExistentTool;
// TypeError: Property "nonExistentTool" not found on corp-jira.
// Available: search_jira_issues, create_issue, get_issue, ...
``typescript
mcp.unknownServer;
// TypeError: Property "unknownServer" not found on mcp.
// Available: corp-jira, github, filesystem, ...
`This makes it easy to discover available tools and servers when debugging or exploring the API.
Security
- Network Isolation: Sandbox only allows connections to the local bridge (e.g.,
localhost:3000)
- Filesystem Isolation: Write access restricted to configured paths
- Timeout Enforcement: Code execution automatically terminated after timeout
- OS-Level Sandboxing: Uses sandbox-exec (macOS) or bubblewrap (Linux)Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
|
SERVERS_CONFIG | ~/.meta-mcp/servers.json | Path to servers configuration |
| MCP_DEFAULT_TIMEOUT` | none | Global timeout for MCP tool calls (ms) |MIT