Custom Tools
Code Tools
Code tools let you run custom JavaScript in isolated containers. Unlike transform tools that use JSONata expressions, code tools give you full Node.js capabilities with proper security isolation.
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
| Parameter | Type | Description |
|---|---|---|
| name | string | Unique tool name |
| description | string | What the tool does |
| input_schema | object | JSON Schema for inputs |
| code | string | JavaScript/TypeScript code |
| runtime | string | "javascript" or "typescript" |
Optional Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| timeout_ms | number | 10000 | Execution timeout in ms |
| memory_limit_mb | number | 64 | Memory limit in MB |
| allowed_domains | string[] | [] | Domains the code can fetch from |
| env_vars | object | {} | 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
- Validate inputs - Don't trust input blindly
- Handle errors - Return meaningful error responses
- Limit scope - Keep tools focused on specific tasks
- Specify allowed_domains - Only add domains you actually need
- 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.