AI Tools
Register custom AI tools from your plugin for use with MCP and AI agents.

AI Tools
Plugins can register custom tools that AI agents can discover and call through the MCP server. This lets your plugin expose WhatsApp functionality to AI agents like Claude, Cursor, and Windsurf.
What Are Plugin Tools
Tools are functions that AI agents can call. Each tool has a name, description, argument schema, and execution function.
ToolDefinition Structure
init: async ({ client }) => ({
tool: {
toolName: {
description: 'What this tool does',
args: {
argName: z.string().describe('Description of the argument'),
},
execute: async (args, context) => {
// Tool implementation
return 'result';
},
},
},
})Fields
- description: What the tool does. AI agents use this to decide when to call the tool.
- args: Zod schema defining the arguments the tool accepts.
- execute: The function that runs when the tool is called.
ToolContext
The execute function receives a ToolContext with these guaranteed fields:
execute: async (args, context) => {
context.logger.info('Tool called', { sessionId: context.sessionId });
if (context.abort.aborted) {
return 'Tool cancelled before work started.';
}
return `Tool ran for session ${context.sessionId}`;
}sessionId: current session IDlogger: scoped plugin loggerabort:AbortSignalfor cancellation
The tool context does not include client. If a tool needs to call WhatsApp methods, capture client from the plugin init() input and use it inside the returned tool handlers.
Example: Lookup Contact Tool
export default createPlugin({
meta: { name: 'contact-tools' },
init: async ({ client }) => ({
tool: {
lookupContact: {
description: 'Look up a contact by phone number',
args: {
phone: z.string().describe('Phone number to look up'),
},
execute: async ({ phone }, context) => {
if (typeof phone !== 'string') {
return JSON.stringify({ success: false, error: 'phone must be a string' });
}
const chatId = `${phone}@c.us`;
const contact = await client.getContact(chatId);
context.logger.info('Contact looked up', { phone });
return JSON.stringify({ success: true, contact });
},
},
},
}),
});Example: Send Message Tool
init: async ({ client }) => ({
tool: {
sendMessage: {
description: 'Send a WhatsApp message to a contact',
args: {
phone: z.string().describe('Phone number to send to'),
message: z.string().describe('Message text'),
},
execute: async ({ phone, message }, context) => {
if (typeof phone !== 'string' || typeof message !== 'string') {
return JSON.stringify({ success: false, error: 'phone and message must be strings' });
}
const chatId = `${phone}@c.us`;
const messageId = await client.sendText(chatId, message);
context.logger.info('Message sent', { phone, messageId });
return JSON.stringify({ success: true, messageId });
},
},
},
})Best Practices
Descriptive Names
Use clear, action-oriented names like lookupContact not getContact, and sendMessage not send.
Clear Descriptions
Write descriptions that help AI agents decide when to use the tool:
description: 'Look up a contact by phone number. Returns the contact name and profile info.'Argument Descriptions
Describe each argument so AI agents know what to pass:
args: {
phone: z.string().describe('Phone number with country code, e.g. 1234567890'),
}Error Handling
Catch errors and return meaningful results:
execute: async (args, context) => {
try {
if (typeof args.chatId !== 'string' || typeof args.message !== 'string') {
return JSON.stringify({ success: false, error: 'chatId and message must be strings' });
}
const messageId = await client.sendText(args.chatId, args.message);
return JSON.stringify({ success: true, messageId });
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
context.logger.error('Failed to send message', { error: message });
return JSON.stringify({ success: false, error: message });
}
}Return Structured Data
Tool handlers return strings. If you want to return structured data to an agent, serialize a JSON object:
return JSON.stringify({
success: true,
data: { name: 'John', phone: '1234567890' },
});Related
- Plugin getting started - Build your first plugin
- MCP Integration - AI agent integration
- Hooks reference - Available hooks

Was this helpful?
Wally and his cute companion coffee mug are coding day and night to keep this up-to-date!
