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
endTool Metadata
Each tool defined with deftool creates a module with:
__tool_metadata__/0- Returns tool metadataexecute/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
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.
Parameters
name- Atom tool name (e.g.,:calculator)description- String description of what the tool doesinput_schema- JSON Schema map defining expected inputopts- Keyword list of optionsdo_block- Block containingexecute/1function definition
Options
:annotations- MCP tool annotations map (see MCP spec)
Annotations
Standard MCP tool annotations:
title- Human-readable titlereadOnlyHint- 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
Lists all tools defined in a module.
Parameters
module- The module that usedClaudeAgentSDK.Tool
Returns
List of tool metadata maps.
Examples
iex> ClaudeAgentSDK.Tool.list_tools(MyTools)
[%{name: :calculator, description: "Performs calculations", ...}]
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 propertyOptional fields
simple_schema(name: :string, email: {:string, optional: true})
# => "name" is required, "email" is notMap 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 paritySupported Types
:stringorString- String type:numberor:floatorFloat- Number type (float or int):integerorInteger- 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
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