# `ExMCP.Client.Operations.Tools`
[🔗](https://github.com/azmaveth/ex_mcp/blob/v1.0.0/lib/ex_mcp/client/operations/tools.ex#L1)

Tool operations for ExMCP client.

This module handles all tool-related operations including listing available tools,
calling specific tools, and finding tools by name or pattern.

# `call_tool`

```elixir
@spec call_tool(
  ExMCP.Client.Types.client(),
  ExMCP.Client.Types.tool_name(),
  ExMCP.Client.Types.tool_arguments(),
  ExMCP.Client.Types.request_opts_or_timeout()
) :: ExMCP.Client.Types.mcp_response()
```

Calls a tool on the MCP server.

## Options

- `:timeout` - Request timeout (default: 30000)
- `:format` - Response format (default: :struct)
- `:progress_token` - Token sent as `_meta.progressToken`, which the server
  handler can use with `ExMCP.Server.Context.report_progress/3`; modern HTTP
  clients receive events through `c:ExMCP.Client.Handler.handle_progress/3`
- `:meta` - Additional `_meta` entries; merged with `:progress_token`
- `:http_stream_retry` - `:at_least_once` (default) retries one ambiguous
  modern HTTP response-stream break; `:safe_only` returns
  `:outcome_unknown` for tools unless `:retry_safe` is explicitly `true`
- `:retry_safe` - Caller attestation that reissuing this operation is safe.
  Tool `readOnlyHint` is intentionally not treated as a security boundary.
- `:idempotency_key` - Non-empty application key injected into the tool
  arguments once, before any retry. The tool must implement deduplication.
- `:idempotency_key_path` - String or list path for the injected key
  (default: `["idempotencyKey"]`). If the path already contains a different
  value, the call fails instead of silently changing it.

## Examples

    ExMCP.Client.Operations.Tools.call_tool(client, "my_tool", %{arg1: "value"})
    ExMCP.Client.Operations.Tools.call_tool(client, "my_tool", %{arg1: "value"}, timeout: 60_000)

    ExMCP.Client.Operations.Tools.call_tool(client, "slow_tool", %{},
      progress_token: "job-42"
    )

    ExMCP.Client.Operations.Tools.call_tool(client, "charge", %{amount: 100},
      idempotency_key: order_id,
      idempotency_key_path: ["request", "idempotencyKey"]
    )

# `find_tool`

```elixir
@spec find_tool(
  ExMCP.Client.Types.client(),
  String.t() | nil,
  ExMCP.Client.Types.request_opts()
) ::
  {:ok, map()} | {:error, :not_found} | {:error, any()}
```

Finds a tool by name or pattern.

If `name_or_pattern` is nil, it returns the first tool from the list.

Handles both response formats: the default `:struct` format
(`%ExMCP.Response{}`) and the raw `:map` format.

## Options

- `:fuzzy` - If true, performs a fuzzy search (default: false)
- `:timeout` - Request timeout (default: 5000)
- `:format` - Response format (default: :struct)

## Examples

    {:ok, tool} = ExMCP.Client.Operations.Tools.find_tool(client, "my_tool")
    {:ok, tool} = ExMCP.Client.Operations.Tools.find_tool(client, "tool", fuzzy: true)

# `list_tools`

```elixir
@spec list_tools(ExMCP.Client.Types.client(), ExMCP.Client.Types.request_opts()) ::
  ExMCP.Client.Types.mcp_response()
```

Lists all available tools from the MCP server.

## Options

- `:timeout` - Request timeout (default: 5000)
- `:format` - Response format (default: :struct)

## Examples

    {:ok, tools} = ExMCP.Client.Operations.Tools.list_tools(client)
    {:ok, tools} = ExMCP.Client.Operations.Tools.list_tools(client, timeout: 10_000)

# `tools`

```elixir
@spec tools(ExMCP.Client.Types.client(), ExMCP.Client.Types.request_opts()) ::
  ExMCP.Client.Types.mcp_response()
```

Alias for `list_tools/2`.

---

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