ClaudeAgentSDK.Tool (claude_agent_sdk v0.11.0)

Copy Markdown View Source

Tool definition macro for creating in-process MCP tools.

Provides the deftool macro for defining tools that can be used with create_sdk_mcp_server/2 to create SDK-based MCP servers without subprocess overhead.

Usage

defmodule MyTools do
  use ClaudeAgentSDK.Tool

  deftool :calculator,
          "Performs basic calculations",
          %{
            type: "object",
            properties: %{
              expression: %{type: "string"}
            },
            required: ["expression"]
          } do
    def execute(%{"expression" => expr}) do
      result = eval_expression(expr)
      {:ok, %{"content" => [%{"type" => "text", "text" => "Result: #{result}"}]}}
    end

    defp eval_expression(expr) do
      # Implementation
    end
  end
end

Tool Metadata

Each tool defined with deftool creates a module with:

  • __tool_metadata__/0 - Returns tool metadata
  • execute/1 - Executes the tool with given input

Input/Output Format

Tools receive input as a map matching the input_schema and return:

  • {:ok, result} - Success with result map
  • {:error, reason} - Error with reason string

Result map should contain:

  • "content" - List of content blocks (text, image, etc.)
  • Optional: "is_error" - Boolean indicating error state

Summary

Functions

Collects all defined tools and makes them discoverable.

When used, defines the deftool macro in the calling module.

Shorthand for deftool with minimal schema (just type: object).

Defines a tool with name, description, input schema, and optional options.

Lists all tools defined in a module.

Creates a simple JSON Schema for common tool patterns.

Validates a JSON schema map.

Functions

__before_compile__(env)

(macro)

Collects all defined tools and makes them discoverable.

__using__(opts)

(macro)

When used, defines the deftool macro in the calling module.

deftool(name, description, list)

(macro)

Shorthand for deftool with minimal schema (just type: object).

deftool(name, description, input_schema, list)

(macro)

deftool(name, description, input_schema, opts, list)

(macro)

Defines a tool with name, description, input schema, and optional options.

Parameters

  • name - Atom tool name (e.g., :calculator)
  • description - String description of what the tool does
  • input_schema - JSON Schema map defining expected input
  • opts - Keyword list of options
  • do_block - Block containing execute/1 function definition

Options

  • :annotations - MCP tool annotations map (see MCP spec)

Annotations

Standard MCP tool annotations:

  • title - Human-readable title
  • readOnlyHint - Tool doesn't modify state (boolean)
  • destructiveHint - Tool may perform destructive operations (boolean)
  • idempotentHint - Repeated calls have same effect (boolean)
  • openWorldHint - Tool interacts with external entities (boolean)

Examples

deftool :read_file, "Read a file", %{type: "object"},
  annotations: %{readOnlyHint: true, openWorldHint: false} do
  def execute(%{"path" => path}) do
    {:ok, %{"content" => [%{"type" => "text", "text" => File.read!(path)}]}}
  end
end

list_tools(module)

@spec list_tools(module()) :: [map()]

Lists all tools defined in a module.

Parameters

Returns

List of tool metadata maps.

Examples

iex> ClaudeAgentSDK.Tool.list_tools(MyTools)
[%{name: :calculator, description: "Performs calculations", ...}]

simple_schema(fields)

@spec simple_schema(keyword() | [atom()] | map()) :: map()

Creates a simple JSON Schema for common tool patterns.

This helper reduces boilerplate when defining tools with straightforward input requirements. It supports several input formats for flexibility.

Input Formats

List of atoms (all string, all required)

simple_schema([:name, :path])
# => %{type: "object", properties: %{name: %{type: "string"}, path: %{type: "string"}}, required: ["name", "path"]}

Keyword list with types

simple_schema(name: :string, count: :number, enabled: :boolean)
# => %{type: "object", properties: %{...}, required: ["name", "count", "enabled"]}

Keyword list with descriptions

simple_schema(name: {:string, "User's full name"}, age: {:number, "Age in years"})
# => Adds description field to each property

Optional fields

simple_schema(name: :string, email: {:string, optional: true})
# => "name" is required, "email" is not

Map syntax (Python parity)

simple_schema(%{a: :float, b: :float})
# => %{"type" => "object", "properties" => %{"a" => %{"type" => "number"}, ...}, "required" => ["a", "b"]}

simple_schema(%{"name" => String, "age" => Integer})
# => Supports module types (String, Integer, Float) for Python parity

Supported Types

  • :string or String - String type
  • :number or :float or Float - Number type (float or int)
  • :integer or Integer - Integer type
  • :boolean - Boolean type
  • :array - Array type
  • :object - Object type

Examples

# Simple tool with two required string fields
deftool :create_file, "Create a file", Tool.simple_schema([:path, :content]) do
  def execute(%{"path" => path, "content" => content}) do
    File.write!(path, content)
    {:ok, %{"content" => [%{"type" => "text", "text" => "Created #{path}"}]}}
  end
end

# Tool with mixed types
deftool :search, "Search files",
  Tool.simple_schema(query: :string, max_results: {:integer, optional: true}) do
  def execute(%{"query" => query} = args) do
    max = Map.get(args, "max_results", 10)
    # ... search logic
  end
end

# Python-style map syntax
deftool :add, "Add two numbers", Tool.simple_schema(%{a: :float, b: :float}) do
  def execute(%{"a" => a, "b" => b}) do
    {:ok, %{"content" => [%{"type" => "text", "text" => "Result: #{a + b}"}]}}
  end
end

valid_schema?(schema)

@spec valid_schema?(map()) :: boolean()

Validates a JSON schema map.

Parameters

  • schema - JSON Schema map

Returns

Boolean indicating if schema is valid.

Examples

iex> ClaudeAgentSDK.Tool.valid_schema?(%{type: "object"})
true

iex> ClaudeAgentSDK.Tool.valid_schema?(%{})
false