Skip to main content
This example demonstrates how to create custom tools with Composio, including both standalone tools and toolkit-integrated tools that can access authentication credentials.

Overview

In this example, you’ll learn how to:
  • Create custom tools with Zod schemas
  • Integrate custom tools with existing toolkits
  • Access authentication credentials in custom tools
  • Execute HTTP requests within custom tool logic
  • Use custom tools in your applications

Prerequisites

1

Install dependencies

npm install @composio/core zod dotenv
2

Set up environment variables

Create a .env file with your API key:
COMPOSIO_API_KEY=your_composio_api_key

Complete Example

import { Composio } from '@composio/core';
import 'dotenv/config';
import { z } from 'zod';

/**
 * Initialize Composio
 */
const composio = new Composio({
  apiKey: process.env.COMPOSIO_API_KEY,
});

/**
 * Create a custom hackernews tool
 * This tool will be registerd in the composio instance and store in memory temporarily.
 */
const customToolSlug = 'GITHUB_STAR_COMPOSIOHQ_REPOSITORY';
const tool = await composio.tools.createCustomTool({
  slug: customToolSlug,
  name: 'Github star composio repositories',
  toolkitSlug: 'github',
  description: 'For any given repository of the user composiohq, star the repository',
  inputParams: z.object({
    repository: z.string().describe('The repository to star'),
  }),
  execute: async (input, connectionConfig, executeToolRequest) => {
    console.log('🚀 ~ execute: ~ params:', input);
    console.log('🚀 ~ execute: ~ connectionConfig:', connectionConfig);

    const result = await executeToolRequest({
      endpoint: `/user/starred/composiohq/${input.repository}`,
      method: 'PUT',
    });
    return result;
  },
});

console.log('🚀 created tool:', tool);

/**
 * Main function to run the example
 */
async function main() {
  try {
    console.log('🚀 Starting Custom-tools Example...');

    // Get available tools
    const tools = await composio.tools.get('default', customToolSlug);

    console.log('tools:', tools);

    const result = await composio.tools.execute(customToolSlug, {
      arguments: {
        repository: 'composio',
      },
      userId: 'default',
    });

    console.log('🚀 Result:', result);
  } catch (error) {
    console.error('❌ Error running example:', error);
  }
}

// Run the example
main().catch(console.error);

How It Works

1

Define Tool Schema

Use Zod to define the input parameters for your tool. Each parameter should have a description for better AI understanding.
inputParams: z.object({
  repository: z.string().describe('The repository to star'),
})
2

Specify Toolkit Integration

By setting toolkitSlug: 'github', the custom tool inherits GitHub’s authentication and can make authenticated API calls.
3

Implement Execute Function

The execute function receives three parameters:
  • input: The validated input parameters
  • connectionConfig: Authentication credentials for the toolkit
  • executeToolRequest: Helper function to make authenticated HTTP requests
4

Make API Requests

Use executeToolRequest to make authenticated requests to the toolkit’s API. It automatically handles authentication headers.
5

Execute the Tool

Call composio.tools.execute() with the tool slug and arguments to run your custom tool.

Execute Function Parameters

input
object
The validated input parameters matching your Zod schema
connectionConfig
object
Authentication credentials and configuration for the associated toolkit
{
  access_token: string,
  // other auth fields depending on toolkit
}
executeToolRequest
function
Helper function to make authenticated HTTP requests
executeToolRequest({
  endpoint: '/api/endpoint',
  method: 'GET' | 'POST' | 'PUT' | 'DELETE',
  body?: object,
  headers?: object,
})

Expected Output

🚀 created tool: {
  slug: 'GITHUB_STAR_COMPOSIOHQ_REPOSITORY',
  name: 'Github star composio repositories',
  description: 'For any given repository of the user composiohq, star the repository'
}
🚀 Starting Custom-tools Example...
tools: [{
  type: 'function',
  function: {
    name: 'GITHUB_STAR_COMPOSIOHQ_REPOSITORY',
    description: 'For any given repository of the user composiohq, star the repository',
    parameters: { ... }
  }
}]
🚀 ~ execute: ~ params: { repository: 'composio' }
🚀 ~ execute: ~ connectionConfig: { access_token: '...' }
🚀 Result: {
  successful: true,
  data: { ... },
  error: null
}

Creating Standalone Custom Tools

You can also create custom tools without toolkit integration:
const standaloneToolSlug = 'ADD_TWO_NUMBERS';
const addTool = await composio.tools.createCustomTool({
  slug: standaloneToolSlug,
  name: 'Add Two Numbers',
  description: 'Adds two numbers together',
  inputParams: z.object({
    a: z.number().describe('First number'),
    b: z.number().describe('Second number'),
  }),
  execute: async (input) => {
    return {
      successful: true,
      data: { result: input.a + input.b },
      error: null,
    };
  },
});

Use Cases

Custom Business Logic

Wrap your internal APIs and business logic as tools for AI agents

API Extensions

Extend existing toolkit capabilities with custom endpoints

Data Transformations

Create tools that transform or aggregate data from multiple sources

Validation & Processing

Add custom validation or preprocessing before calling external APIs

Best Practices

Always add clear descriptions to your Zod schema fields. These descriptions help AI models understand how to use your tool correctly.
Always return a consistent result format with successful, data, and error fields to make error handling predictable.
Use toolkitSlug when your tool needs to authenticate with an existing service. This provides automatic credential management.

Next Steps

File Handling

Learn how to handle file uploads in tools

OpenAI Example

Use custom tools with OpenAI

Build docs developers (and LLMs) love