Custom Tools

Code Runners

Code runners handle anything that needs custom logic — calculations, data processing, content generation, and more. Your AI writes the JavaScript; it runs in a secure, isolated container that can't access your other data.

You don't write this code

The JavaScript below is what your AI generates. You just describe what you want: "build a tool that calculates statistics for any list of numbers."


How Code Tools Work

Code tools run in Cloudflare Sandbox - VM-isolated containers that:

  • Execute JavaScript/TypeScript in Node.js 20
  • Have no access to your Kyew data
  • Cannot make unauthorized network requests
  • Run with configurable timeout and memory limits
┌─────────────────────────────────────────┐
│             Kyew Worker              │
│                                          │
│  ┌────────────────────────────────────┐ │
│  │     Cloudflare Sandbox Container   │ │
│  │  ┌──────────────────────────────┐  │ │
│  │  │    Your Code (Isolated VM)   │  │ │
│  │  │                              │  │ │
│  │  │  export default {            │  │ │
│  │  │    fetch(request) { ... }    │  │ │
│  │  │  }                           │  │ │
│  │  └──────────────────────────────┘  │ │
│  └────────────────────────────────────┘ │
└─────────────────────────────────────────┘

Creating Code Tools

Use create_code_tool to define a new code tool:

create_code_tool({
  name: "calculate_statistics",
  description: "Calculate statistical measures for a list of numbers",
  input_schema: {
    type: "object",
    properties: {
      numbers: {
        type: "array",
        items: { type: "number" },
        description: "Array of numbers to analyze"
      }
    },
    required: ["numbers"]
  },
  runtime: "javascript",
  code: `
export default {
  async fetch(request) {
    const { numbers } = await request.json();

    const sum = numbers.reduce((a, b) => a + b, 0);
    const mean = sum / numbers.length;
    const sorted = [...numbers].sort((a, b) => a - b);
    const median = sorted[Math.floor(sorted.length / 2)];
    const variance = numbers.reduce((acc, n) => acc + Math.pow(n - mean, 2), 0) / numbers.length;
    const stdDev = Math.sqrt(variance);

    return Response.json({
      count: numbers.length,
      sum,
      mean,
      median,
      min: Math.min(...numbers),
      max: Math.max(...numbers),
      variance,
      standardDeviation: stdDev
    });
  }
}
  `
})

Code Structure

Your code must export a default object with a fetch method:

export default {
  async fetch(request) {
    // Get input from request body
    const input = await request.json();

    // Do your processing
    const result = processInput(input);

    // Return Response with JSON
    return Response.json(result);
  }
}

Required Parameters

ParameterTypeDescription
namestringUnique tool name
descriptionstringWhat the tool does
input_schemaobjectJSON Schema for inputs
codestringJavaScript/TypeScript code
runtimestring"javascript" or "typescript"

Optional Parameters

ParameterTypeDefaultDescription
timeout_msnumber10000Execution timeout in ms
memory_limit_mbnumber64Memory limit in MB
allowed_domainsstring[][]Domains the code can fetch from
env_varsobject{}Environment variables

Approval Workflow

Code tools require approval before they can be used. This is a security measure since code execution carries more risk than data transforms.

1. Create (Draft Status)

create_code_tool({ ... })
// → Tool created with status: "draft"

2. Review Pending Tools

"list pending code tools"

3. Approve or Reject

"approve code tool tool-abc123 with note 'reviewed - safe statistical functions'"

Or reject:

"reject code tool tool-abc123 because it attempts to access external URLs without allowed_domains"

4. Use the Tool

Once approved, the tool becomes available as a regular MCP tool:

"use calculate_statistics with numbers [1, 2, 3, 4, 5]"

Example: ASCII Art Generator

create_code_tool({
  name: "ascii_art_banner",
  description: "Generate ASCII art text banners",
  input_schema: {
    type: "object",
    properties: {
      text: { type: "string", description: "Text to convert" },
      style: {
        type: "string",
        enum: ["standard", "banner", "big"],
        description: "Art style"
      }
    },
    required: ["text"]
  },
  runtime: "javascript",
  code: `
export default {
  async fetch(request) {
    const { text, style = 'standard' } = await request.json();

    // Simple block letter implementation
    const letters = {
      'A': ['  A  ', ' A A ', 'AAAAA', 'A   A', 'A   A'],
      'B': ['BBBB ', 'B   B', 'BBBB ', 'B   B', 'BBBB '],
      // ... more letters
    };

    const lines = ['', '', '', '', ''];
    for (const char of text.toUpperCase()) {
      const letter = letters[char] || ['     ', '     ', '     ', '     ', '     '];
      for (let i = 0; i < 5; i++) {
        lines[i] += letter[i] + ' ';
      }
    }

    return Response.json({
      banner: lines.join('\\n'),
      text: text
    });
  }
}
  `
})

Example: Data Validator

create_code_tool({
  name: "validate_config",
  description: "Validate configuration objects against a schema",
  input_schema: {
    type: "object",
    properties: {
      config: { type: "object", description: "Configuration to validate" },
      rules: {
        type: "array",
        items: {
          type: "object",
          properties: {
            field: { type: "string" },
            required: { type: "boolean" },
            type: { type: "string" },
            pattern: { type: "string" }
          }
        }
      }
    },
    required: ["config", "rules"]
  },
  runtime: "javascript",
  code: `
export default {
  async fetch(request) {
    const { config, rules } = await request.json();
    const errors = [];

    for (const rule of rules) {
      const value = config[rule.field];

      if (rule.required && value === undefined) {
        errors.push(\`Missing required field: \${rule.field}\`);
        continue;
      }

      if (value !== undefined && rule.type && typeof value !== rule.type) {
        errors.push(\`\${rule.field} should be \${rule.type}, got \${typeof value}\`);
      }

      if (value && rule.pattern && !new RegExp(rule.pattern).test(value)) {
        errors.push(\`\${rule.field} does not match pattern \${rule.pattern}\`);
      }
    }

    return Response.json({
      valid: errors.length === 0,
      errors
    });
  }
}
  `
})

Making HTTP Requests

Code tools can fetch external URLs if you specify allowed_domains:

create_code_tool({
  name: "fetch_github_repo",
  description: "Fetch repository information from GitHub",
  input_schema: {
    type: "object",
    properties: {
      owner: { type: "string" },
      repo: { type: "string" }
    },
    required: ["owner", "repo"]
  },
  runtime: "javascript",
  allowed_domains: ["api.github.com"],
  code: `
export default {
  async fetch(request) {
    const { owner, repo } = await request.json();

    const response = await fetch(
      \`https://api.github.com/repos/\${owner}/\${repo}\`,
      { headers: { 'User-Agent': 'Memory-Alpha-Tool' } }
    );

    if (!response.ok) {
      return Response.json({ error: 'Repository not found' }, { status: 404 });
    }

    const data = await response.json();
    return Response.json({
      name: data.name,
      description: data.description,
      stars: data.stargazers_count,
      forks: data.forks_count,
      language: data.language
    });
  }
}
  `
})

Testing Code Tools

Before approval, test your tools:

"test code tool tool-abc123 with input { \"numbers\": [1, 2, 3, 4, 5] }"

This runs the tool in the sandbox and returns the result without affecting production.


Security Considerations

What Code Tools CAN Do

  • Process input data
  • Perform calculations
  • Fetch from allowed domains
  • Use standard JavaScript APIs

What Code Tools CANNOT Do

  • Access Kyew database
  • Read other users' data
  • Access the worker's environment
  • Make requests to non-allowed domains
  • Run indefinitely (timeout enforced)
  • Use unlimited memory (limit enforced)

Best Practices

  1. Validate inputs - Don't trust input blindly
  2. Handle errors - Return meaningful error responses
  3. Limit scope - Keep tools focused on specific tasks
  4. Specify allowed_domains - Only add domains you actually need
  5. Review before approving - Check for security issues

Troubleshooting

"Execution timeout"

Your code took too long. Optimize or increase timeout_ms.

"Memory limit exceeded"

Your code used too much memory. Optimize or increase memory_limit_mb.

"Fetch failed: domain not allowed"

Add the domain to allowed_domains when creating the tool.

"Unexpected token 'export'"

Ensure your code uses ESM syntax (export default { ... }), not CommonJS.

Previous
Data Transforms