ts/docs/api/custom-tools.md
Custom tools allow you to create your own tools that can be used with Composio. There are two types of custom tools:
A standalone tool is the simplest form of custom tool. It only requires input parameters and an execute function:
const tool = await composio.tools.createCustomTool({
slug: 'CALCULATE_SQUARE',
name: 'Calculate Square',
description: 'Calculates the square of a number',
inputParams: z.object({
number: z.number().describe('The number to calculate the square of'),
}),
execute: async input => {
const { number } = input;
return {
data: { result: number * number },
error: null,
successful: true,
};
},
});
A toolkit-based tool has access to two ways of making authenticated requests:
executeToolRequest - The recommended way to make authenticated requests to the toolkit's API endpoints. Composio automatically handles credential injection and baseURL resolution:const tool = await composio.tools.createCustomTool({
slug: 'GITHUB_STAR_COMPOSIOHQ_REPOSITORY',
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'),
page: z.number().optional().describe('Page number for pagination'),
customHeader: z.string().optional().describe('Custom header value'),
}),
execute: async (input, connectionConfig, executeToolRequest) => {
// executeToolRequest makes authenticated requests to the toolkit's API
// You can use relative paths - Composio will automatically inject the baseURL
const result = await executeToolRequest({
endpoint: `/user/starred/composiohq/${input.repository}`,
method: 'PUT',
body: {},
// Add custom headers or query parameters
parameters: [
// Add query parameters
{
name: 'page',
value: input.page?.toString() || '1',
in: 'query',
},
// Add custom headers
{
name: 'x-custom-header',
value: input.customHeader || 'default-value',
in: 'header',
},
],
});
return result;
},
});
connectionConfig - For making direct API calls when needed:const tool = await composio.tools.createCustomTool({
slug: 'GITHUB_DIRECT_API',
name: 'Direct GitHub API Call',
description: 'Makes direct calls to GitHub API',
toolkitSlug: 'github',
inputParams: z.object({
repo: z.string().describe('Repository name'),
}),
execute: async (input, connectionConfig, executeToolRequest) => {
// Use connectionConfig for direct API calls
const result = await fetch(`https://api.github.com/repos/${input.repo}`, {
headers: {
Authorization: `Bearer ${connectionConfig.val?.access_token}`,
},
});
return {
data: await result.json(),
error: null,
successful: true,
};
},
});
You can add custom headers and query parameters to your toolkit-based tools using the parameters option in executeToolRequest:
const tool = await composio.tools.createCustomTool({
slug: 'GITHUB_SEARCH_REPOSITORIES',
name: 'Search GitHub Repositories',
description: 'Search for repositories with custom parameters',
toolkitSlug: 'github',
inputParams: z.object({
query: z.string().describe('Search query'),
perPage: z.number().optional().describe('Results per page'),
acceptType: z.string().optional().describe('Custom accept header'),
}),
execute: async (input, connectionConfig, executeToolRequest) => {
const result = await executeToolRequest({
endpoint: '/search/repositories',
method: 'GET',
parameters: [
// Add query parameters for pagination
{
name: 'q',
value: input.query,
in: 'query',
},
{
name: 'per_page',
value: (input.perPage || 30).toString(),
in: 'query',
},
// Add custom headers
{
name: 'Accept',
value: input.acceptType || 'application/vnd.github.v3+json',
in: 'header',
},
{
name: 'X-Custom-Header',
value: 'custom-value',
in: 'header',
},
],
});
return result;
},
});
You can execute custom tools just like any other tool:
const result = await composio.tools.execute('TOOL_SLUG', {
arguments: {
// Tool input parameters
},
userId: 'user-id',
connectedAccountId: 'optional-account-id', // Required for toolkit-based tools
});
The custom tools implementation provides full type safety:
(input) => Promise<ToolExecuteResponse>(input, connectionConfig, executeToolRequest) => Promise<ToolExecuteResponse>describe()executeToolRequest over direct API calls when possibleexecuteToolRequest - Composio will automatically inject the correct baseURLparameters option to add custom headers or query parameters:
parameters: [
{ name: 'page', value: '1', in: 'query' }, // Adds ?page=1 to URL
{ name: 'x-custom', value: 'value', in: 'header' }, // Adds header
];
executeToolRequest can only call tools from the same toolkitexecuteToolRequest to leverage Composio's automatic credential handlingconnectionConfig when you need to make direct API calls or interact with different servicesexecuteToolRequest for better maintainabilityexecuteToolRequest can only execute tools from the same toolkit that the custom tool belongs to