Custom Tools
Chain Tools
Chain tools execute multiple tools in sequence, passing results between steps to create complex workflows.
Creating a Chain Tool
create_dynamic_tool({
name: "deploy_and_notify",
description: "Deploy to production and notify the team",
tool_type: "chain",
input_schema: {
type: "object",
properties: {
environment: { type: "string" },
message: { type: "string" }
},
required: ["environment"]
},
chain_config: {
steps: [
{
tool_name: "cloudflare_deploy",
input_mapping: {
env: "{{environment}}"
}
},
{
tool_name: "slack_notify",
input_mapping: {
channel: "#deployments",
text: "Deployed to {{environment}}: {{message}}"
}
}
]
},
activate: true
})
Chain Config Structure
{
chain_config: {
steps: [
{
tool_name: "tool_1", // Tool to execute
input_mapping: { ... }, // Map inputs to tool params
output_key: "step1_result" // Optional: name for this step's output
},
{
tool_name: "tool_2",
input_mapping: {
data: "{{step1_result}}" // Reference previous step output
}
}
],
continue_on_error: false // Stop if any step fails (default)
}
}
Input Mapping
From Chain Input
{
input_mapping: {
query: "{{searchTerm}}", // From chain input
limit: "{{maxResults}}"
}
}
From Previous Steps
{
input_mapping: {
data: "{{step1.result}}", // From step with output_key
id: "{{step1.result.id}}" // Nested access
}
}
Static Values
{
input_mapping: {
channel: "#notifications", // Static value
format: "json"
}
}
Example: GitHub PR Workflow
create_dynamic_tool({
name: "create_pr_with_review",
description: "Create a PR and request review",
tool_type: "chain",
input_schema: {
type: "object",
properties: {
owner: { type: "string" },
repo: { type: "string" },
title: { type: "string" },
branch: { type: "string" },
reviewers: { type: "array", items: { type: "string" } }
},
required: ["owner", "repo", "title", "branch"]
},
chain_config: {
steps: [
{
tool_name: "github_create_pr",
input_mapping: {
owner: "{{owner}}",
repo: "{{repo}}",
title: "{{title}}",
head: "{{branch}}",
base: "main"
},
output_key: "pr"
},
{
tool_name: "github_request_review",
input_mapping: {
owner: "{{owner}}",
repo: "{{repo}}",
pr_number: "{{pr.number}}",
reviewers: "{{reviewers}}"
}
}
]
}
})
Example: Data Pipeline
create_dynamic_tool({
name: "fetch_and_process",
description: "Fetch data from API and process it",
tool_type: "chain",
input_schema: {
type: "object",
properties: {
url: { type: "string" },
filter_field: { type: "string" }
},
required: ["url"]
},
chain_config: {
steps: [
{
tool_name: "http_fetch",
input_mapping: {
url: "{{url}}"
},
output_key: "raw_data"
},
{
tool_name: "transform_filter",
input_mapping: {
data: "{{raw_data}}",
field: "{{filter_field}}"
},
output_key: "filtered"
},
{
tool_name: "format_output",
input_mapping: {
data: "{{filtered}}"
}
}
]
}
})
Error Handling
Stop on Error (Default)
{
chain_config: {
steps: [...],
continue_on_error: false // Chain stops if any step fails
}
}
Continue on Error
{
chain_config: {
steps: [...],
continue_on_error: true // Continue even if steps fail
}
}
Chain Output
The chain returns:
- Results from all steps
- Overall success/failure status
- Error details if any step failed
{
"success": true,
"steps": [
{ "tool": "step1", "success": true, "result": {...} },
{ "tool": "step2", "success": true, "result": {...} }
],
"final_result": {...}
}
Best Practices
Keep Chains Focused
Don't create mega-chains. Break complex workflows into smaller, composable chains.
Name Output Keys Clearly
output_key: "created_issue" // Good
output_key: "result1" // Less clear
Handle Failures Gracefully
Consider what should happen if intermediate steps fail. Use continue_on_error only when appropriate.
Test Individual Tools First
Before chaining tools, test each one individually to ensure they work as expected.