v0.5.2 release - Contributors, Sponsors and Enquiries are most welcome 😌

Tools

Tools extend agent capabilities by allowing them to interact with external systems, perform calculations, manipulate data, and more.

What are Tools?

Tools are functions that agents can call to perform specific tasks. They are defined with:

  • A unique name and description
  • Input schema validation using Zod
  • An execution function that returns results

Built-in Tools

AgentSea includes 10+ powerful built-in tools ready to use:

🧮 Calculator

Perform mathematical calculations with support for basic arithmetic

🌐 HTTP Request

Make HTTP requests to external APIs with retry logic

📁 File Read

Read file contents from the filesystem

✏️ File Write

Write data to files on the filesystem

📋 File List

List files and directories in a path

📊 Text Summary

Extract word count, emails, URLs, and numbers from text

🔤 String Transform

Transform strings (uppercase, lowercase, titlecase, reverse, trim, slug)

📅 Date Time

Get current date/time and format dates

🎨 Figma

Interact with Figma files, nodes, images, and comments via API

n8n

Execute and manage n8n workflows and webhooks for automation

Using Built-in Tools

Import and register tools with your agent:

typescript
import {
  Agent,
  AnthropicProvider,
  ToolRegistry,
  calculatorTool,
  httpRequestTool,
  fileReadTool,
  textSummaryTool,
} from '@lov3kaizen/agentsea-core';
import type { Tool, ToolCall, ToolContext } from '@lov3kaizen/agentsea-types';

// Create tool registry
const toolRegistry = new ToolRegistry();

// Register tools
toolRegistry.register(calculatorTool);
toolRegistry.register(httpRequestTool);
toolRegistry.register(fileReadTool);
toolRegistry.register(textSummaryTool);

// Create agent with tools
const agent = new Agent(
  {
    name: 'tool-agent',
    model: 'claude-sonnet-4-20250514',
    provider: 'anthropic',
    tools: [calculatorTool, httpRequestTool, fileReadTool, textSummaryTool],
  },
  new AnthropicProvider(),
  toolRegistry,
);

// Agent will automatically use tools when needed
const response = await agent.execute(
  'Calculate 42 * 58 and fetch weather data from https://api.weather.com',
  context,
);

Creating Custom Tools

Create your own tools to extend agent capabilities:

typescript
import { Tool } from '@lov3kaizen/agentsea-core';
import { z } from 'zod';

// Define tool
export const databaseQueryTool: Tool = {
  name: 'database_query',
  description: 'Execute SQL queries on the database',
  inputSchema: z.object({
    query: z.string().describe('SQL query to execute'),
    params: z.array(z.any()).optional().describe('Query parameters'),
  }),
  execute: async (input) => {
    const { query, params = [] } = input;

    try {
      // Your database logic here
      const results = await db.query(query, params);

      return {
        success: true,
        data: results,
        message: `Query executed successfully. ${results.length} rows returned.`,
      };
    } catch (error) {
      return {
        success: false,
        error: error.message,
      };
    }
  },
};

// Register with agent
toolRegistry.register(databaseQueryTool);

Tool Schema Validation

Tools use Zod schemas for input validation. Here are common patterns:

typescript
import { z } from 'zod';

// String with constraints
const nameSchema = z.object({
  name: z.string().min(1).max(100).describe('User name'),
});

// Numbers with ranges
const ageSchema = z.object({
  age: z.number().int().min(0).max(120).describe('User age'),
});

// Enums
const statusSchema = z.object({
  status: z.enum(['active', 'inactive', 'pending']).describe('Status'),
});

// Optional fields
const updateSchema = z.object({
  id: z.string().describe('User ID'),
  email: z.string().email().optional().describe('New email'),
  phone: z.string().optional().describe('New phone number'),
});

// Arrays
const bulkSchema = z.object({
  ids: z.array(z.string()).describe('User IDs to process'),
});

// Nested objects
const addressSchema = z.object({
  user: z.object({
    name: z.string(),
    address: z.object({
      street: z.string(),
      city: z.string(),
      zip: z.string(),
    }),
  }),
});

Async Tools

Tools can be async and perform long-running operations:

bash
export const imageGenerationTool: Tool = {
  name: 'generate_image',
  description: 'Generate an image using DALL-E',
  inputSchema: z.object({
    prompt: z.string().describe('Image description'),
    size: z.enum(['256x256', '512x512', '1024x1024']).default('512x512'),
  }),
  execute: async (input) => {
    const { prompt, size } = input;

    // Call image generation API
    const response = await fetch('https://api.openai.com/v1/images/generations', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        prompt,
        size,
        n: 1,
      }),
    });

    const data = await response.json();

    return {
      success: true,
      imageUrl: data.data[0].url,
      message: 'Image generated successfully',
    };
  },
};

Error Handling

Always handle errors gracefully in tools:

bash
export const apiCallTool: Tool = {
  name: 'api_call',
  description: 'Make an API call',
  inputSchema: z.object({
    endpoint: z.string().url(),
  }),
  execute: async (input) => {
    try {
      const response = await fetch(input.endpoint, {
        timeout: 5000, // 5 second timeout
      });

      if (!response.ok) {
        return {
          success: false,
          error: `HTTP error ${response.status}: ${response.statusText}`,
        };
      }

      const data = await response.json();

      return {
        success: true,
        data,
      };
    } catch (error) {
      if (error.name === 'AbortError') {
        return {
          success: false,
          error: 'Request timed out',
        };
      }

      return {
        success: false,
        error: error.message,
      };
    }
  },
};

MCP Tools

Use MCP (Model Context Protocol) to automatically import tools from external servers:

typescript
import { MCPRegistry } from '@lov3kaizen/agentsea-core';

// Create MCP registry
const mcpRegistry = new MCPRegistry();

// Connect to MCP servers
await mcpRegistry.addServer({
  name: 'filesystem',
  command: 'npx',
  args: ['-y', '@modelcontextprotocol/server-filesystem', '/home/user'],
  transport: 'stdio',
});

await mcpRegistry.addServer({
  name: 'github',
  command: 'npx',
  args: ['-y', '@modelcontextprotocol/server-github'],
  transport: 'stdio',
  env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN },
});

// Get all MCP tools (automatically converted)
const mcpTools = mcpRegistry.getTools();

// Register with tool registry
toolRegistry.registerMany(mcpTools);

// Agent now has access to filesystem and GitHub tools
const agent = new Agent(
  {
    name: 'mcp-agent',
    model: 'claude-sonnet-4-20250514',
    provider: 'anthropic',
    tools: mcpTools,
  },
  provider,
  toolRegistry,
);

Tool Registry

Manage tools efficiently with the tool registry:

typescript
import { ToolRegistry } from '@lov3kaizen/agentsea-core';

const toolRegistry = new ToolRegistry();

// Register single tool
toolRegistry.register(calculatorTool);

// Register multiple tools
toolRegistry.registerMany([
  httpRequestTool,
  fileReadTool,
  textSummaryTool,
]);

// Get tool by name
const calculator = toolRegistry.get('calculator');

// Check if tool exists
const exists = toolRegistry.has('calculator');

// List all tools
const allTools = toolRegistry.list();

// Unregister tool
toolRegistry.unregister('calculator');

Isomorphic Tool Management

Isomorphic tools let you define tools once and implement them for different environments (server or client). This enables type-safe tool definitions with Zod schemas for both input and output validation.

The isomorphic tool system provides a clean separation between tool definitions and their implementations, allowing you to:

  • Define tools with full input/output type safety
  • Create server-side implementations for backend operations
  • Create client-side implementations for browser operations
  • Share tool definitions between environments

Tool Definition

Create a tool definition that can be implemented for different environments:

typescript
import { toolDefinition } from '@lov3kaizen/agentsea-core';
import { z } from 'zod';

// Define the tool with input/output schemas
const getUserDef = toolDefinition({
  name: 'get_user',
  description: 'Get user information from the database',
  inputSchema: z.object({
    userId: z.string().describe('The user ID to look up'),
  }),
  outputSchema: z.object({
    name: z.string(),
    email: z.string().email(),
    createdAt: z.string(),
  }),
});

// Server implementation - direct database access
const getUserServer = getUserDef.server(async ({ userId }, context) => {
  const user = await db.users.findUnique({ where: { id: userId } });
  return {
    name: user.name,
    email: user.email,
    createdAt: user.createdAt.toISOString(),
  };
});

// Client implementation - fetch from API
const getUserClient = getUserDef.client(async ({ userId }) => {
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
});

// Use with agent
const agent = new Agent({
  tools: [getUserServer.toTool()],
  // ...
});

Quick Helpers

For simpler cases, use the quick helper functions to create tools in one step:

typescript
import { serverTool, clientTool, hybridTool } from '@lov3kaizen/agentsea-core';
import { z } from 'zod';

// Server-only tool
const calculateTool = serverTool({
  name: 'calculate',
  description: 'Perform arithmetic operations',
  inputSchema: z.object({
    operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
    a: z.number(),
    b: z.number(),
  }),
  outputSchema: z.object({ result: z.number() }),
  execute: async ({ operation, a, b }) => {
    switch (operation) {
      case 'add': return { result: a + b };
      case 'subtract': return { result: a - b };
      case 'multiply': return { result: a * b };
      case 'divide': return { result: a / b };
    }
  },
});

// Client-only tool (runs in browser)
const showNotification = clientTool({
  name: 'show_notification',
  description: 'Show a browser notification',
  inputSchema: z.object({
    title: z.string(),
    body: z.string(),
  }),
  outputSchema: z.object({ shown: z.boolean() }),
  execute: ({ title, body }) => {
    new Notification(title, { body });
    return { shown: true };
  },
});

// Hybrid tool with both implementations
const userTool = hybridTool({
  name: 'get_user',
  description: 'Get user information',
  inputSchema: z.object({ userId: z.string() }),
  outputSchema: z.object({ name: z.string(), email: z.string() }),
  server: async ({ userId }) => {
    return await db.users.findUnique({ where: { id: userId } });
  },
  client: async ({ userId }) => {
    const res = await fetch(`/api/users/${userId}`);
    return res.json();
  },
});

Built-in Isomorphic Tools

AgentSea includes isomorphic versions of built-in tools with both server and client implementations:

typescript
import {
  calculatorDef,
  calculatorServer,
  calculatorClient,
} from '@lov3kaizen/agentsea-core';

// Use the definition to create custom implementations
const customCalc = calculatorDef.server(async ({ operation, a, b }) => {
  // Custom server logic with logging
  console.log(`Calculating: ${a} ${operation} ${b}`);
  // ... implementation
});

// Or use pre-built implementations
const tools = [calculatorServer.toTool()];

// Execute directly
const result = await calculatorServer.execute(
  { operation: 'add', a: 5, b: 3 },
  context
);
// { result: 8 }

Type Safety

Extract input and output types from tool definitions for full type safety:

typescript
import type { ToolInput, ToolOutput } from '@lov3kaizen/agentsea-core';

// Extract types from tool
type CalcInput = ToolInput<typeof calculatorDef>;
// { operation: 'add' | 'subtract' | 'multiply' | 'divide'; a: number; b: number }

type CalcOutput = ToolOutput<typeof calculatorDef>;
// { result: number }

// Use in your code
function runCalculation(input: CalcInput): Promise<CalcOutput> {
  return calculatorServer.execute(input, context);
}

Converting to Legacy Tools

Convert isomorphic tools to the legacy Tool interface for compatibility:

typescript
import { toLegacyTool, toLegacyTools } from '@lov3kaizen/agentsea-core';

// Convert single tool
const legacyCalc = toLegacyTool(calculatorServer);

// Convert multiple tools
const legacyTools = toLegacyTools([
  calculatorServer,
  getUserServer,
  customTool,
]);

// Use with existing code
toolRegistry.registerMany(legacyTools);

Best Practices

  • Descriptive Names: Use clear, descriptive tool names (e.g., database_query not db)
  • Detailed Descriptions: Provide comprehensive descriptions so agents know when to use each tool
  • Validation: Always validate inputs with Zod schemas
  • Error Handling: Return structured error objects, never throw exceptions
  • Timeouts: Set reasonable timeouts for external API calls
  • Idempotency: Make tools idempotent when possible
  • Side Effects: Document any side effects in the description
  • Rate Limiting: Implement rate limiting for expensive operations
  • Use Output Schemas: Define output schemas for better type safety and validation
  • Environment Separation: Use isomorphic tools to keep server and client logic separate

Next Steps