Skip to main content

What are Custom Tools?

Custom Tools are Python functions that orchestrate multiple MCP servers and can be deployed as:
  • REST API endpoints - Call from any system
  • Reusable MCP tools - Available in Claude and other MCP clients
  • Scheduled jobs - Run automatically on a schedule
Custom Tools let you write business logic once and reuse it everywhere - from Claude conversations to external integrations.

Creating a Custom Tool

Step 1: Write Your Code

Use the DataGen SDK to call MCP tools as Python functions:
from datagen_sdk import DatagenClient

client = DatagenClient()

# Call MCP tools like regular functions
issues = client.execute_tool("mcp_Linear_list_issues", {
    "filter": {"state": {"name": {"eq": "In Progress"}}}
})

# Process the data
active_count = len(issues)
result = f"Found {active_count} active issues"

Step 2: Define Input Schema

Specify what parameters your tool accepts using JSON Schema:
{
  "type": "object",
  "properties": {
    "campaign_id": {
      "type": "string",
      "description": "The HeyReach campaign ID to analyze"
    },
    "days": {
      "type": "integer",
      "description": "Number of days to look back",
      "default": 30
    }
  },
  "required": ["campaign_id"]
}

Step 3: Define Output Variables

List the variables your code produces:
# Your code assigns these variables
result = {"total_leads": 150, "conversion_rate": 0.12}
summary = "Campaign performed above average"

# Output variables: ["result", "summary"]

Step 4: Configure Dependencies

Specify what your tool needs:
Dependency TypeDescriptionExample
MCP ServersWhich MCP servers to connect["Linear", "Gmail"]
SecretsEnvironment variables needed["OPENAI_API_KEY"]
ImportsPython packages to import["pandas", "httpx"]

Deploying Your Tool

Ask Claude to deploy using natural language:

Deployment Examples

Basic deployment:
"Deploy this as a custom tool called 'analyze_campaign'"
With scheduling:
"Deploy this tool and schedule it to run daily at 9 AM"
With parameters:
"Deploy this as an API that accepts campaign_id and date_range parameters"
Or use the deployCode tool directly:
# Claude will call deployCode with:
{
  "deployment_name": "analyze_campaign",
  "description": "Analyze HeyReach campaign performance",
  "script": "...",  # Your Python code
  "input_schema": {...},  # JSON Schema
  "output_variables": ["result", "summary"],
  "mcp_server_names": ["HeyReach"],
  "required_secrets": ["OPENAI_API_KEY"],
  "additional_imports": ["pandas"]
}

Testing Your Tool

Test with executeCode First

Before deploying, test your code with executeCode:
"Run this code to test my campaign analysis logic"
This runs your code in a sandbox and returns results immediately.

Test Deployed Tool

After deployment, test with submitCustomToolRun:
"Run my analyze_campaign tool with campaign_id='abc123'"

Managing Custom Tools

Finding Your Tools

Use searchCustomTools to find your deployed tools:
"Search for my campaign tools"

Updating a Tool

Use updateCustomTool to modify an existing deployment:
"Update my analyze_campaign tool to also return the top performing messages"
You can update:
  • Python code
  • Input/output schemas
  • Dependencies
  • Name and description

Checking Tool Status

Use checkRunStatus to monitor running tools:
"Check the status of my last campaign analysis run"

Example: Lead Enrichment Tool

Here’s a complete example of a custom tool that enriches leads:
from datagen_sdk import DatagenClient

client = DatagenClient()

# Input: list of company domains
domains = input_domains  # From input schema

enriched = []
for domain in domains:
    # Call web research MCP
    research = client.execute_tool("mcp_Perplexity_search", {
        "query": f"What does {domain} company do? Who are the founders?"
    })

    # Call LinkedIn MCP for employee count
    company = client.execute_tool("mcp_LinkedIn_get_company", {
        "domain": domain
    })

    enriched.append({
        "domain": domain,
        "description": research.get("answer"),
        "employee_count": company.get("employeeCount"),
        "industry": company.get("industry")
    })

# Output variables
result = enriched
total_enriched = len(enriched)
Input Schema:
{
  "type": "object",
  "properties": {
    "input_domains": {
      "type": "array",
      "items": {"type": "string"},
      "description": "List of company domains to enrich"
    }
  },
  "required": ["input_domains"]
}
Dependencies:
  • MCP Servers: ["Perplexity", "LinkedIn"]
  • Output Variables: ["result", "total_enriched"]

Best Practices

Each tool should do one thing well. Create separate tools for different tasks rather than one massive tool.
Use try/except blocks and return meaningful error messages:
try:
    result = client.execute_tool("mcp_Linear_create_issue", {...})
except DatagenToolError as e:
    error_message = f"Failed to create issue: {e}"
Name tools clearly: enrich_company_data not tool1. Good descriptions help Claude understand when to use your tool.
Always test with executeCode first. Deployed tools are harder to debug.

What’s Next?

Deploy & Schedule

Learn about API endpoints and scheduling options

Connect MCPs

Add more MCP servers to use in your tools

Deploy Agents

Run Claude Code agents on schedule

Built-in Tools

See examples of pre-built tools