Skip to main content
Glama
schizoidcock

MCX (Modular Code Execution)

by schizoidcock

MCX - Modular Code Execution

███╗ ███╗ ██████╗██╗ ██╗ ████╗ ████║██╔════╝╚██╗██╔╝ ██╔████╔██║██║ ╚███╔╝ ██║╚██╔╝██║██║ ██╔██╗ ██║ ╚═╝ ██║╚██████╗██╔╝ ██╗ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝

MCP server that lets AI agents execute code instead of calling tools directly.

Based on Anthropic's code execution article.

The Problem

Traditional MCP has two inefficiencies:

  1. Tool definition overload - Loading all tool definitions floods context. Thousands of tools = hundreds of thousands of tokens before any work begins.

  2. Intermediate result bloat - Every API response passes through the model. A list of 100 records with nested data can consume 50,000+ tokens.

The Solution

Instead of calling tools directly, the agent writes code that runs in a sandbox:

// Agent writes this code, MCX executes it const invoices = await api.getInvoices({ limit: 100 }); return { count: invoices.length, total: sum(invoices, 'amount'), byStatus: count(invoices, 'status') }; // Returns ~50 tokens instead of 50,000

Result: 98% token reduction by filtering data inside the execution environment.

Key Benefits

Benefit

Description

Progressive Disclosure

Adapters loaded on demand, not upfront. Agent only sees what it needs.

Context Efficiency

Filtering, aggregation, and transformation happen in sandbox. Model sees results, not raw data.

Control Flow

Loops, conditionals, retries run as native code - no back-and-forth with model.

Privacy

Intermediate data stays in sandbox. Model only sees what code explicitly returns.

Skills

Save reusable operations as skills that combine multiple adapter calls.

Installation

bun install bun run build

Fully Bun-native: Uses Bun for package management, building, and runtime. No Node.js required.

Quick Start

1. Setup

# Create environment file cp .env.template .env # Create config file cp mcx.config.template.ts mcx.config.ts

2. Create Adapters

# Option A: Generate from OpenAPI docs (recommended) mcx gen # Option B: Copy from template cp adapters/adapter.template.ts adapters/my-api.ts

3. Run

# Start MCP server (stdio mode for Claude Code) mcx serve # Or just run mcx (serve is the default command) mcx

Templates

File

Description

.env.template

Environment variables (API keys, etc.)

mcx.config.template.ts

MCX configuration (adapters, sandbox settings)

adapters/adapter.template.ts

Adapter template with CRUD examples

skills/skill.template.ts

Skill template with 3 patterns

CLI Commands

mcx serve

Start the MCP server. This is the default command when running mcx without arguments.

mcx serve [options] Options: -t, --transport <type> Transport mode: stdio (default) or http -p, --port <number> HTTP port (default: 3100, only for http) -c, --cwd <path> Working directory for config and adapters

Features:

  • Auto-discovers mcx.config.ts by walking up the directory tree

  • Loads .env files automatically

  • HTTP transport binds to 127.0.0.1 only (localhost)

  • HTTP mode exposes /health endpoint for monitoring

mcx gen

Generate adapters from OpenAPI specs. Run without arguments for interactive TUI mode.

# Interactive TUI (recommended) mcx gen # CLI mode - single file mcx gen ./api-docs/users.md -n users # CLI mode - batch directory mcx gen ./api-docs -n myapi Options: -n, --name <name> Adapter name (auto-detected from source) -o, --output <path> Output file (default: adapters/<name>.ts) -b, --base-url <url> API base URL (auto-detected from OpenAPI) -a, --auth <type> Auth type: basic, bearer, apikey, none --read-only Generate GET methods only

mcx init

Initialize a new MCX project in the current directory.

mcx init

Creates:

  • mcx.config.ts - Configuration file

  • adapters/example.ts - Example adapter

  • skills/hello.ts - Example skill

mcx list

List all available adapters and skills. Alias: mcx ls

mcx list mcx ls

mcx run

Run a skill or script directly.

# Run a skill by name mcx run daily-summary date=2024-01-15 # Run a script file mcx run ./scripts/migrate.ts

MCP Tools

MCX exposes three tools to the AI agent:

Tool

Description

mcx_execute

Execute JavaScript/TypeScript code in sandbox with adapter access

mcx_run_skill

Run a named skill with optional inputs

mcx_list

List available adapters and skills (read-only)

Built-in Helpers

Functions available in the sandbox for efficient data handling:

Helper

Usage

Description

pick(arr, fields)

pick(data, ['id', 'name'])

Extract specific fields (supports dot-notation: 'address.city')

first(arr, n)

first(data, 5)

First N items (default: 5)

sum(arr, field)

sum(data, 'amount')

Sum numeric field

count(arr, field)

count(data, 'status')

Count by field value

table(arr, maxRows)

table(data, 20)

Format as markdown table (default: 10 rows)

Console Methods

All console methods are captured and returned in the response:

console.log('Debug info'); // [LOG] Debug info console.warn('Warning'); // [WARN] Warning console.error('Error'); // [ERROR] Error console.info('Info'); // [INFO] Info

Adapter Access

Adapters are available both via the adapters object and as top-level globals:

// Both work identically await adapters.crm.getLeads({ limit: 10 }); await crm.getLeads({ limit: 10 });

Usage Patterns

Bad: Raw API response floods context

return await api.getRecords({ limit: 100 }); // 100 objects × 500 tokens each = 50,000 tokens

Good: Filter before returning

const data = await api.getRecords({ limit: 100 }); return pick(data, ['id', 'name', 'status']); // 100 objects × 3 fields = ~500 tokens

Good: Return summary only

const data = await api.getRecords({ limit: 100 }); return { count: data.length, total: sum(data, 'amount'), byStatus: count(data, 'status') }; // ~50 tokens

Good: Debug with logs, return minimal

const data = await api.getRecords({ limit: 10 }); console.log(table(pick(data, ['id', 'name', 'amount']))); return { count: data.length }; // Logs show table, return is tiny

Polling Loop (native control flow)

let found = false; while (!found) { const messages = await slack.getChannelHistory({ channel: 'C123' }); found = messages.some(m => m.text.includes('deployment complete')); if (!found) await new Promise(r => setTimeout(r, 5000)); } return { status: 'deployment complete' }; // Runs entirely in sandbox, no model round-trips

Generating Adapters

Auto-generate adapters from OpenAPI specs in markdown files.

Interactive TUI

mcx gen

The TUI wizard guides you through:

  1. Source selection - Single file or batch directory with file browser

  2. Analysis summary - Shows endpoints, categories, detected auth

  3. Adapter name - Auto-suggested from API name

  4. Output path - File browser for destination

  5. Auth/Base URL - Only asked if not auto-detected

  6. Config import - Option to add adapter to mcx.config.ts

Auto-Detection

MCX automatically detects:

  • Base URL from OpenAPI servers field

  • Authentication from OpenAPI securitySchemes:

    • http/basic → Basic Auth

    • http/bearer → Bearer Token

    • apiKey → API Key (header or query)

  • SDK-based APIs from code examples in markdown (TypeScript and Python)

Batch Processing

Process entire directories of API docs:

mcx gen ./alegra-endpoints -n alegra # Scans all .md files, extracts OpenAPI specs, generates single adapter

SDK-Based Adapters

When MCX detects SDK usage in docs, it generates SDK wrappers instead of fetch-based code:

// Generated from SDK-based API docs import { ZepClient } from '@getzep/zep-cloud'; const client = new ZepClient({ apiKey: process.env.ZEP_API_KEY }); export const zep = defineAdapter({ tools: { addMemory: { execute: async (params) => client.memory.add(params.sessionId, params), }, }, });

Creating Adapters

import { defineAdapter } from '@mcx/adapters'; export const myApi = defineAdapter({ name: 'myapi', description: 'My API adapter', tools: { getRecords: { description: 'Fetch records', parameters: { limit: { type: 'number', description: 'Max results' }, }, execute: async (params) => { return fetch(`${BASE_URL}/records?limit=${params.limit}`).then(r => r.json()); }, }, }, });

Built-in Adapters

Fetch Adapter

Generic HTTP client with all standard methods.

import { createFetchAdapter } from '@mcx/adapters'; const api = createFetchAdapter({ baseUrl: 'https://api.example.com', headers: { 'X-API-Key': process.env.API_KEY }, timeout: 30000, });

Tools: get, post, put, patch, delete, head, request

Creating Skills

Skills are reusable operations that combine multiple adapter calls.

Using defineSkill

import { defineSkill } from '@mcx/core'; export const dailySummary = defineSkill({ name: 'daily-summary', description: 'Summarize daily activity across systems', adapters: ['crm', 'analytics'], code: ` const leads = await crm.getLeads({ date: inputs.date }); const visits = await analytics.getPageViews({ date: inputs.date }); return { date: inputs.date, leads: leads.length, visits: sum(visits, 'count'), conversion: (leads.length / sum(visits, 'count') * 100).toFixed(2) + '%' }; `, sandbox: { timeout: 10000, memoryLimit: 128, }, });

Using skillBuilder (Fluent API)

import { skillBuilder } from '@mcx/core'; export const processData = skillBuilder('process-data') .description('Fetch, transform, and store data') .requires('api', 'db') .timeout(15000) .memoryLimit(256) .code(` const raw = await api.fetchRecords({ limit: 1000 }); const filtered = pick(raw, ['id', 'name', 'amount']); const result = await db.bulkInsert(filtered); return { inserted: result.count }; `) .build();

Native Function Skills

For complex logic, use a native TypeScript function instead of code string:

export const complexSkill = defineSkill({ name: 'complex-operation', description: 'Skill with native TypeScript logic', adapters: ['api'], run: async ({ adapters, inputs }) => { const data = await adapters.api.getData(inputs); // Complex processing with full TypeScript support const processed = data .filter(item => item.active) .map(item => ({ ...item, score: calculateScore(item), })) .sort((a, b) => b.score - a.score); return { top10: processed.slice(0, 10) }; }, });

Skill Directory Structure

Skills can be single files or directories:

skills/ ├── daily-summary.ts # Single file skill ├── complex-workflow/ # Directory skill │ ├── index.ts # Entry point (required) │ └── helpers.ts # Supporting modules

Configuration

mcx.config.ts

import { defineConfig } from '@mcx/core'; import { myAdapter } from './adapters/my-adapter'; export default defineConfig({ // Adapters to load adapters: [myAdapter], // Skills to load (optional, auto-discovered from skills/) skills: [], // Sandbox configuration sandbox: { timeout: 5000, // Execution timeout (ms) memoryLimit: 128, // Memory limit (MB) allowAsync: true, // Allow async/await globals: {}, // Custom globals }, // Environment variables to inject (available in adapters) env: { API_KEY: process.env.API_KEY, }, });

Fluent Config Builder

import { configBuilder } from '@mcx/core'; export default configBuilder() .adapter(myAdapter) .adapters(otherAdapter1, otherAdapter2) .sandbox({ timeout: 10000 }) .build();

Programmatic API

Use MCX programmatically in your own applications:

import { createExecutor } from '@mcx/core'; const executor = createExecutor(); await executor.loadConfig('./mcx.config.ts'); // Execute code const result = await executor.execute(` const data = await api.getRecords({ limit: 10 }); return pick(data, ['id', 'name']); `); // Run a skill const skillResult = await executor.runSkill('daily-summary', { inputs: { date: '2024-01-15' }, });

MCXExecutor Methods

Method

Description

loadConfig(path?)

Load configuration from file

registerAdapter(adapter)

Register an adapter

unregisterAdapter(name)

Remove an adapter

getAdapter(name)

Get adapter by name

getAdapterNames()

List all adapter names

registerSkill(skill)

Register a skill

unregisterSkill(name)

Remove a skill

getSkill(name)

Get skill by name

getSkillNames()

List all skill names

execute(code, options?)

Execute code in sandbox

runSkill(name, options?)

Run a skill

configureSandbox(config)

Update sandbox defaults

Claude Code Integration

Add to your project's .mcp.json:

{ "mcpServers": { "mcx": { "command": "bun", "args": ["run", "mcx", "serve"], "cwd": "/path/to/project" } } }

Or with environment variables:

{ "mcpServers": { "mcx": { "command": "bun", "args": ["run", "mcx", "serve"], "cwd": "/path/to/project", "env": { "API_KEY": "your-api-key" } } } }

Server Options

# Default: stdio transport (for Claude Code) mcx serve # HTTP transport (for testing, other MCP clients, custom integrations) mcx serve -t http -p 3100 # Specify working directory mcx serve -c /path/to/project

Option

Description

-t, --transport

stdio (default) or http

-p, --port

HTTP port (default: 3100, only for http transport)

-c, --cwd

Working directory for config and adapters

HTTP Transport

When using HTTP transport:

  • Server binds to 127.0.0.1 only (localhost, for security)

  • MCP endpoint: POST /mcp

  • Health check: GET /health returns { status, server, version }

Result Summarization

Large results are automatically summarized to prevent context overflow:

  • Arrays truncated to 5 items with "... and N more" indicator

  • Nested arrays limited to 3 items

  • Objects with >5 keys are summarized

Architecture

┌──────────┐ ┌───────────────────────────────────┐ │ Claude │ ───▶ │ MCX Server │ │ /LLM │ code │ ┌─────────┐ ┌─────────────────┐ │ └──────────┘ │ │ Sandbox │ │ Adapters │ │ │ │ (Bun │ │ api.getRecords()│ │ ◀───────────│ │ Worker) │ │ api.createItem()│ │ result │ └─────────┘ └─────────────────┘ │ (filtered) │ │ │ │ ▼ │ │ ┌─────────────────────────────┐ │ │ │ Helpers: pick/sum/count/... │ │ │ └─────────────────────────────┘ │ └───────────────────────────────────┘

Runtime

MCX is 100% Bun-native:

  • Sandbox: Bun Workers (native JavaScript isolation)

  • HTTP: Bun.serve (no Express)

  • Files: Bun.file/Bun.Glob (no node:fs, no glob)

  • Env: Automatic .env loading (no dotenv)

Benefits:

  • Faster startup (~100ms)

  • Smaller bundle (~0.5MB vs 1.5MB)

  • No native module compilation issues

  • Single runtime (no Node.js required)

License

MIT

-
security - not tested
F
license - not found
-
quality - not tested

Latest Blog Posts

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/schizoidcock/mcx'

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