# `Phantom.Tool`
[🔗](https://github.com/dbernheisel/phantom_mcp/blob/main/lib/phantom/tool.ex#L1)

The Model Context Protocol (MCP) allows servers to expose tools
that can be invoked by language models. Tools enable models to
interact with external systems, such as querying databases,
calling APIs, or performing computations. Each tool is uniquely
identified by a name and includes metadata describing its schema.

https://modelcontextprotocol.io/specification/2025-03-26/server/tools

```mermaid
sequenceDiagram
    participant LLM
    participant Client
    participant Server

    Note over Client,Server: Discovery
    Client->>Server: tools/list
    Server-->>Client: List of tools

    Note over Client,LLM: Tool Selection
    LLM->>Client: Select tool to use

    Note over Client,Server: Invocation
    Client->>Server: tools/call
    Server-->>Client: Tool result
    Client->>LLM: Process result

    Note over Client,Server: Updates
    Server--)Client: tools/list_changed
    Client->>Server: tools/list
    Server-->>Client: Updated tools
```

# `audio_response`

```elixir
@type audio_response() :: %{
  content: [
    %{type: :audio, data: base64_binary :: binary(), mimeType: String.t()}
  ]
}
```

# `embedded_blob_resource`

```elixir
@type embedded_blob_resource() :: %{
  :uri =&gt; String.t(),
  :data =&gt; String.t(),
  optional(:mimeType) =&gt; String.t(),
  optional(:title) =&gt; String.t(),
  optional(:description) =&gt; String.t()
}
```

# `embedded_resource_response`

```elixir
@type embedded_resource_response() :: %{
  content: [
    %{
      type: :resource,
      resource: embedded_text_resource() | embedded_blob_resource()
    }
  ]
}
```

# `embedded_text_resource`

```elixir
@type embedded_text_resource() :: %{
  :uri =&gt; String.t(),
  :text =&gt; String.t(),
  optional(:mimeType) =&gt; String.t(),
  optional(:title) =&gt; String.t(),
  optional(:description) =&gt; String.t()
}
```

# `error_response`

```elixir
@type error_response() :: %{
  isError: true,
  content: [%{type: :text, text: String.t()}]
}
```

# `image_response`

```elixir
@type image_response() :: %{
  content: [
    %{type: :image, data: base64_binary :: binary(), mimeType: String.t()}
  ]
}
```

# `json`

```elixir
@type json() :: %{
  :name =&gt; String.t(),
  :description =&gt; String.t(),
  :inputSchema =&gt; Phantom.Tool.JSONSchema.json(),
  optional(:outputSchema) =&gt; Phantom.Tool.JSONSchema.json(),
  optional(:annotations) =&gt; Phantom.Tool.Annotation.json()
}
```

# `resource_link_response`

```elixir
@type resource_link_response() :: %{
  content: [
    %{
      type: :resource_link,
      uri: String.t(),
      name: String.t(),
      description: String.t(),
      mimeType: String.t()
    }
  ]
}
```

# `response`

```elixir
@type response() ::
  audio_response()
  | embedded_resource_response()
  | error_response()
  | image_response()
  | resource_link_response()
  | structured_response()
  | text_response()
```

# `structured_response`

```elixir
@type structured_response() :: %{
  structuredContent: map(),
  content: [%{type: :text, text: json_encoded :: String.t()}]
}
```

# `t`

```elixir
@type t() :: %Phantom.Tool{
  annotations: Phantom.Tool.Annotation.t(),
  description: String.t(),
  function: atom(),
  handler: module(),
  icons: [Phantom.Icon.t()] | nil,
  input_schema: Phantom.Tool.JSONSchema.t() | nil,
  meta: map(),
  mime_type: String.t(),
  name: String.t(),
  output_schema: Phantom.Tool.JSONSchema.t() | nil
}
```

# `text_response`

```elixir
@type text_response() :: %{content: [%{type: :text, text: String.t()}]}
```

# `audio`
*macro* 

Tool response as audio content

The `:mime_type` will be fetched from the current tool within the scope of
the request if not provided, but you will need to provide the rest.

- `binary` - Binary data.
- `:mime_type` (optional) MIME type. Defaults to `"application/octet-stream"`

For example:

    Phantom.Tool.audio(File.read!("game-over.wav"))

    Phantom.Tool.audio(
      File.read!("game-over.wav"),
      mime_type: "audio/wav"
    )

# `build`

Build a tool spec. Be intentional with the name and description when defining
the tool since it will inform the LLM when to use the tool.

The `Phantom.Router.tool/3` macro will build these specs.

Fields:

- `:name` - The name of the tool.
- `:title` A human-readable title for the tool, useful for UI display.
- `:description` - The description of the tool and when to use it.
- `:mime_type` - the MIME type of the results.
- `:handler` - The module to call.
- `:function` - The function to call on the handler module.
- `:output_schema` - the JSON schema of the results.
- `:input_schema` - The JSON schema of the input arguments.
- `:read_only` If `true`, indicates the tool does not modify its environment.
- `:destructive` If `true`, the tool may perform destructive updates (only meaningful when `:read_only` is `false`).
- `:idempotent` If `true`, calling the tool repeatedly with the same arguments has no additional effect (only meaningful when `:read_only` is `false`).
- `:open_world` If `true`, the tool may interact with an "open world" of external entities.

# `embedded_resource`

```elixir
@spec embedded_resource(string_uri :: String.t(), map()) ::
  embedded_resource_response()
```

Embedded resource response.

Typically used with your router's `read_resource/3` function.
See `Phantom.Router.read_resource/3` for more information

# `error`

```elixir
@spec error(message :: String.t()) :: error_response()
```

# `image`
*macro* 

Tool response as image content

The `:mime_type` will be fetched from the current tool within the scope of
the request if not provided, but you will need to provide the rest.

- `binary` - Binary data.
- `:mime_type` (optional) MIME type. Defaults to `"application/octet-stream"`

For example:

    Phantom.Tool.image(File.read!("tower.png"))

    Phantom.Tool.audio(
      File.read!("tower.png"),
      mime_type: "image/png"
    )

# `resource_link`

```elixir
@spec resource_link(string_uri :: String.t(), Phantom.ResourceTemplate.t(), map()) ::
  resource_link_response()
```

Resource link reponse.

Typically used with your router's `resource_uri/3` function.
See `Phantom.Router.resource_uri/3` for more information.

# `response`

Formats the response from an MCP Router to the MCP specification

# `text`

```elixir
@spec text(map()) :: structured_response()
@spec text(String.t()) :: text_response()
```

# `to_json`

Represent a Tool spec as json when listing the available tools to clients.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
