Skip to main content
CodeCall lets LLMs orchestrate hundreds of tools through a code-first interface while maintaining strict security boundaries. Instead of flooding the context window with tool definitions, the model discovers, describes, and executes tools through a sandboxed JavaScript environment.

Scalable Discovery

Search across hundreds of tools using natural language

Code Orchestration

LLMs write JavaScript to combine tools, filter data, and build workflows

Bank-Grade Security

Sandboxed execution with AST validation, resource limits, and audit logging

Direct Invocation

Optionally bypass the VM for simple single-tool calls

Quick Start

npm install @frontmcp/plugins
import { App, Tool, ToolContext } from '@frontmcp/sdk';
import CodeCallPlugin from '@frontmcp/plugins/codecall';

@Tool({
  name: 'users:list',
  description: 'List all users with pagination',
  codecall: {
    enabledInCodeCall: true,
    visibleInListTools: false, // Hidden from direct list, accessible via CodeCall
  },
})
class ListUsersTool extends ToolContext {
  async execute(input: { limit?: number }) {
    return { users: [/* ... */] };
  }
}

@App({
  id: 'example',
  plugins: [
    CodeCallPlugin.init({
      mode: 'codecall_only',
      security: {
        level: 'SECURE', // Bank-grade security preset
      },
    }),
  ],
  tools: [ListUsersTool],
})
export default class ExampleApp {}
The model now sees only four meta-tools:
  • codecall:search - Find relevant tools
  • codecall:describe - Get detailed schemas
  • codecall:execute - Run JavaScript orchestration plans
  • codecall:invoke - Direct tool calls (optional)

Security Model

CodeCall implements defense-in-depth with multiple security layers:

Security Levels

Choose a preset that matches your threat model:
LevelTimeoutMax IterationsTool CallsUse Case
STRICT1s1005Ultra-sensitive environments
SECURE3s1,00020Production default
STANDARD5s10,00050Internal/trusted models
PERMISSIVE30s100,000200Development only
CodeCallPlugin.init({
  security: {
    level: 'SECURE', // or 'STRICT', 'STANDARD', 'PERMISSIVE'
    // Override specific limits:
    timeout: 5000, // Override timeout
    maxToolCalls: 30, // Override tool call limit
  },
});

Self-Reference Blocking

Critical Security Feature: Scripts cannot call CodeCall meta-tools from within scripts.
// This is BLOCKED - returns error instead of executing
const result = await callTool('codecall:execute', { script: '...' });
// Result: { success: false, error: { code: 'SELF_REFERENCE_BLOCKED' } }
This prevents:
  • Recursive script execution (infinite loops)
  • Sandbox escape attempts
  • Privilege escalation attacks

AST Validation

Every script is parsed and validated before execution:
  • eval() and Function() constructor
  • with statements
  • Direct property access on dangerous objects
  • __proto__, constructor, prototype access
  • Async generators (resource exhaustion)
  • Import/export (module system bypass)
  • callTool(name, args) - Make tool calls
  • parallel(fns, options) - Concurrent execution
  • Math, JSON, Array, Object, String, Number, Date
  • Custom globals you explicitly allow

Result-Based Error Handling

Security Design: Tool calls return results instead of throwing exceptions:
// Inside sandbox, callTool returns:
type ToolResult<T> =
  | { success: true; data: T }
  | { success: false; error: { code: string; message: string } };

// Usage in script:
const result = await callTool('users:get', { id: '123' });
if (!result.success) {
  // Handle error - no exception escapes
  return { error: result.error.message };
}
return result.data;
This prevents:
  • Information leakage through stack traces
  • Internal system path exposure
  • Exception-based control flow manipulation

Resource Limits

Timeout

Enforced execution time limit prevents infinite loops

Iterations

Loop iteration counter prevents while(true) attacks

Tool Calls

Maximum tool invocations per script execution
// All loops are instrumented:
for (let i = 0; i < 1000; i++) {
  // Each iteration increments counter
  // Throws when maxIterations exceeded
}

Tool Visibility Modes

Control which tools appear in list_tools vs. CodeCall: Hide all tools from list_tools, expose via CodeCall:
CodeCallPlugin.init({ mode: 'codecall_only' });
  • list_tools: Only CodeCall meta-tools visible
  • CodeCall: All tools searchable and callable
  • Override: Set visibleInListTools: true per tool

codecall_opt_in

Tools must explicitly opt into CodeCall:
CodeCallPlugin.init({ mode: 'codecall_opt_in' });

@Tool({
  codecall: {
    enabledInCodeCall: true, // Required for CodeCall access
    visibleInListTools: true, // Also visible normally
  },
})

metadata_driven

Full control per tool:
CodeCallPlugin.init({ mode: 'metadata_driven' });

@Tool({
  codecall: {
    enabledInCodeCall: true,  // Available in scripts
    visibleInListTools: false, // Hidden from list_tools
  },
})

Meta-Tools Reference

codecall:search

Find tools by natural language query:
{
  "tool": "codecall:search",
  "input": {
    "query": "get user profile information",
    "topK": 5,
    "filter": {
      "appIds": ["user-service"]
    }
  }
}
Response:
{
  "tools": [
    {
      "name": "users:getProfile",
      "description": "Get user profile by ID",
      "score": 0.94,
      "appId": "user-service"
    }
  ]
}

codecall:describe

Get detailed schemas for selected tools:
{
  "tool": "codecall:describe",
  "input": {
    "tools": ["users:getProfile", "users:updateProfile"],
    "options": {
      "includeExamples": true,
      "verbosity": "full"
    }
  }
}
Response includes:
  • Full JSON Schema for inputs/outputs
  • Description and usage notes
  • Example inputs/outputs
  • Type information with constraints

codecall:execute

Run a JavaScript orchestration script:
{
  "tool": "codecall:execute",
  "input": {
    "script": "const users = await callTool('users:list', { limit: 100 });\nreturn users.data.filter(u => u.active);",
    "context": {
      "tenantId": "t-123"
    }
  }
}
Response:
{
  "status": "success",
  "result": [/* filtered users */],
  "stats": {
    "duration": 234,
    "toolCallCount": 1,
    "iterationCount": 100
  }
}
Error Response:
{
  "status": "error",
  "error": {
    "code": "TOOL_ERROR",
    "message": "Tool 'users:list' failed: Rate limit exceeded",
    "category": "tool_error",
    "suggestion": "The tool call failed. Check the input parameters and try again."
  }
}

codecall:invoke

Direct tool invocation without JavaScript:
{
  "tool": "codecall:invoke",
  "input": {
    "tool": "users:getById",
    "input": { "id": "user-123" }
  }
}
Benefits:
  • No VM overhead for simple calls
  • Still enforces access control
  • Maintains audit logging
  • Applies output sanitization

AgentScript API

Inside codecall:execute, scripts have access to:

callTool(name, args)

// Returns result object, never throws
const result = await callTool('users:get', { id: '123' });

if (result.success) {
  console.log(result.data);
} else {
  console.log(result.error.message);
}

parallel(functions, options)

Execute multiple operations concurrently:
// Fetch multiple users in parallel
const results = await parallel([
  () => callTool('users:get', { id: '1' }),
  () => callTool('users:get', { id: '2' }),
  () => callTool('users:get', { id: '3' }),
], { maxConcurrency: 10 });

// Results are in order
const [user1, user2, user3] = results;
Limits:
  • Maximum 100 parallel operations
  • Maximum 20 concurrent executions
  • Shares tool call limit with sequential calls

Available Globals

// Safe built-ins
Math.round(3.7);
JSON.parse('{"a":1}');
new Date().toISOString();
[1,2,3].filter(x => x > 1);
Object.keys({ a: 1, b: 2 });

// Context (read-only)
codecallContext.tenantId;
codecallContext.userId;

Audit Logging

CodeCall emits detailed audit events for security monitoring:
import { AuditLoggerService, AUDIT_EVENT_TYPES } from '@frontmcp/plugins/codecall';

// Subscribe to audit events
const auditLogger = scope.get(AuditLoggerService);

auditLogger.subscribe((event) => {
  switch (event.type) {
    case AUDIT_EVENT_TYPES.EXECUTION_START:
      console.log(`Script started: ${event.executionId}`);
      break;
    case AUDIT_EVENT_TYPES.SECURITY_SELF_REFERENCE:
      console.warn(`Self-reference blocked: ${event.toolName}`);
      break;
    case AUDIT_EVENT_TYPES.TOOL_CALL:
      console.log(`Tool called: ${event.toolName}`);
      break;
  }
});
Event Types:
  • execution:start / execution:success / execution:failure
  • security:self-reference - Blocked recursive call
  • security:validation-failure - AST validation failed
  • tool:call / tool:error - Individual tool calls
  • resource:limit-exceeded - Hit iteration/timeout/call limits

Error Enrichment

Errors are categorized with actionable suggestions:
CategoryExampleSuggestion
syntaxUnexpected tokenCheck JavaScript syntax at line X
securityeval is not allowedRemove prohibited construct
timeoutExecution exceeded 3sSimplify logic or increase timeout
tool_not_foundUnknown tool ‘foo’Use codecall:search to find tools
tool_errorTool threw errorCheck tool input parameters
runtimeCannot read propertyDebug the script logic

Output Sanitization

All outputs are sanitized before being returned:
// Configuration
CodeCallPlugin.init({
  sanitization: {
    maxDepth: 10,
    maxStringLength: 10000,
    maxArrayLength: 1000,
    maxObjectKeys: 100,
    removeStackTraces: true,
    removeFilePaths: true,
  },
});
Sanitization includes:
  • Circular reference detection → [circular]
  • Prototype pollution prevention → removes __proto__, constructor
  • Large output truncation with warnings
  • Stack trace removal (configurable)
  • File path scrubbing (configurable)

Configuration Reference

CodeCallPlugin.init({
  // Tool visibility mode
  mode: 'codecall_only' | 'codecall_opt_in' | 'metadata_driven',

  // Security configuration
  security: {
    level: 'STRICT' | 'SECURE' | 'STANDARD' | 'PERMISSIVE',
    timeout?: number,        // Override timeout (ms)
    maxIterations?: number,  // Override max loop iterations
    maxToolCalls?: number,   // Override max tool invocations
  },

  // Search configuration
  search: {
    topK: 8,                 // Default results per search
    similarityThreshold: 0.5, // Minimum relevance score
  },

  // Describe configuration
  describe: {
    maxTools: 10,            // Max tools per describe call
    includeExamples: true,   // Include example inputs/outputs
  },

  // Direct invocation
  directInvoke: {
    enabled: true,           // Enable codecall:invoke
    allowedTools?: string[], // Whitelist (optional)
  },

  // Output sanitization
  sanitization: {
    maxDepth: 10,
    maxStringLength: 10000,
    removeStackTraces: true,
    removeFilePaths: true,
  },

  // Custom globals for scripts
  globals: {
    MY_CONSTANT: 'value',
    config: { key: 'value' },
  },
});

Best Practices

The SECURE preset provides the right balance of functionality and safety:
CodeCallPlugin.init({
  security: { level: 'SECURE' },
});
For large tool sets, hide tools from list_tools to reduce context usage:
CodeCallPlugin.init({
  mode: 'codecall_only',
});
Set up alerting for security events:
auditLogger.subscribe((event) => {
  if (event.type.startsWith('security:')) {
    alertSecurityTeam(event);
  }
});
Avoid VM overhead for single-tool operations:
{ "tool": "codecall:invoke", "input": { "tool": "users:get", "input": { "id": "123" } } }
Always include tenant/user IDs in tool calls:
callTool('users:list', { tenantId: codecallContext.tenantId })

Security Checklist

1

Choose Security Level

Use SECURE for production, STRICT for ultra-sensitive environments
2

Enable Audit Logging

Subscribe to audit events and monitor for security incidents
3

Configure Output Sanitization

Ensure stack traces and file paths are removed in production
4

Review Tool Access

Use appropriate mode and metadata to control tool visibility
5

Test Security Boundaries

Verify self-reference blocking and resource limits work correctly

Example: Multi-Tool Workflow

// Script for codecall:execute
async function analyzeUserActivity() {
  // Search across multiple services in parallel
  const [users, orders, sessions] = await parallel([
    () => callTool('users:list', { status: 'active', limit: 100 }),
    () => callTool('orders:recent', { days: 7 }),
    () => callTool('sessions:active', {}),
  ]);

  if (!users.success || !orders.success || !sessions.success) {
    return { error: 'Failed to fetch data' };
  }

  // Join data in JavaScript
  const enrichedUsers = users.data.map(user => {
    const userOrders = orders.data.filter(o => o.userId === user.id);
    const userSession = sessions.data.find(s => s.userId === user.id);

    return {
      ...user,
      recentOrders: userOrders.length,
      isOnline: !!userSession,
      lastActivity: userSession?.lastActivity || user.lastLogin,
    };
  });

  // Filter and sort
  return enrichedUsers
    .filter(u => u.recentOrders > 0)
    .sort((a, b) => b.recentOrders - a.recentOrders)
    .slice(0, 10);
}

return analyzeUserActivity();