---
title: Серверные инструменты
url: https://platform.claude.com/docs/ru/agents-and-tools/tool-use/server-tools
description: "Работа с инструментами, выполняемыми Anthropic: блоки server_tool_use, продолжение после pause_turn, ходы со смешанными серверными и клиентскими инструментами и фильтрация доменов."
---

Инструменты, выполняемые на сервере, имеют общую механику: блок `server_tool_use`, продолжение после `pause_turn`, ходы, в которых сочетаются серверные и клиентские инструменты, соответствие требованиям «Zero Data Retention» (нулевое хранение данных), или ZDR, и фильтрация доменов. Сведения об отдельных инструментах см. в [справочнике по инструментам](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/tool-reference).

## Блок server\_tool\_use

Блок `server_tool_use` появляется в ответе Claude, когда выполняется серверный инструмент. Его поле `id` использует префикс `srvtoolu_`, чтобы отличать его от вызовов клиентских инструментов:

```json
{
  "type": "server_tool_use",
  "id": "srvtoolu_01A2B3C4D5E6F7G8H9",
  "name": "web_search",
  "input": { "query": "latest quantum computing breakthroughs" }
}
```

API выполняет инструмент внутренне. Вы видите вызов и его результат в ответе, но не занимаетесь выполнением. В отличие от клиентских блоков `tool_use`, вам не нужно отвечать блоком `tool_result`. Блок результата инструмента (например, `web_search_tool_result` для веб-поиска) следует за блоком `server_tool_use` в том же ходе ассистента и связан с ним по `tool_use_id`. Если Claude одновременно вызывает один из ваших клиентских инструментов, блок `server_tool_use` появляется без своего результата, а ответ завершается с `stop_reason: "tool_use"`. API запускает инструмент, когда вы возвращаете клиентские блоки `tool_result` в следующем запросе.

## Серверный цикл и pause\_turn

При использовании серверных инструментов, таких как веб-поиск, API выполняет вызовы инструментов в серверном «agentic loop» (агентном цикле). Во время длительного хода API может приостановить этот цикл и вернуть причину остановки `pause_turn`.

Вот как обработать причину остановки `pause_turn`:

<CodeGroup>
  ```bash cURL
  # Начальный запрос. Если "stop_reason" в ответе равен "pause_turn", продолжите
  # ход, повторно отправив запрос с содержимым ответа ассистента, добавленным в messages.
  curl https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 1024,
      "messages": [
        {
          "role": "user",
          "content": "Search for comprehensive information about quantum computing breakthroughs in 2025"
        }
      ],
      "tools": [{"type": "web_search_20250305", "name": "web_search", "max_uses": 10}]
    }'
  ```

  ```bash CLI
  # Начальный запрос. Если "stop_reason" в выводе равен "pause_turn", повторите запрос,
  # добавив содержимое ответа ассистента в messages (см. вкладки SDK).
  ant messages create <<'YAML'
  model: claude-opus-5-5
  max_tokens: 1024
  tools:
    - {type: web_search_20250305, name: web_search, max_uses: 10}
  messages:
    - {role: user, content: "Search for comprehensive information about quantum computing breakthroughs in 2025"}
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  # Начальный запрос с веб-поиском
  response = client.messages.create(
      model="claude-opus-5-5",
      max_tokens=1024,
      messages=[
          {
              "role": "user",
              "content": "Search for comprehensive information about quantum computing breakthroughs in 2025",
          }
      ],
      tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 10}],
  )

  # Проверяем, имеет ли ответ причину остановки pause_turn
  if response.stop_reason == "pause_turn":
      # Продолжаем диалог с приостановленным содержимым
      messages = [
          {
              "role": "user",
              "content": "Search for comprehensive information about quantum computing breakthroughs in 2025",
          },
          {"role": "assistant", "content": response.content},
      ]

      # Отправляем запрос на продолжение
      continuation = client.messages.create(
          model="claude-opus-5-5",
          max_tokens=1024,
          messages=messages,
          tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 10}],
      )

      print(continuation)
  else:
      print(response)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  // Начальный запрос с веб-поиском
  const response = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [
      {
        role: "user",
        content:
          "Search for comprehensive information about quantum computing breakthroughs in 2025"
      }
    ],
    tools: [
      {
        type: "web_search_20250305",
        name: "web_search",
        max_uses: 10
      }
    ]
  });

  // Проверяем, имеет ли ответ причину остановки pause_turn
  if (response.stop_reason === "pause_turn") {
    // Продолжаем диалог с приостановленным содержимым
    const messages: Anthropic.MessageParam[] = [
      {
        role: "user",
        content:
          "Search for comprehensive information about quantum computing breakthroughs in 2025"
      },
      { role: "assistant", content: response.content }
    ];

    // Отправляем запрос на продолжение
    const continuation = await client.messages.create({
      model: "claude-opus-5-5",
      max_tokens: 1024,
      messages,
      tools: [
        {
          type: "web_search_20250305",
          name: "web_search",
          max_uses: 10
        }
      ]
    });

    console.log(continuation);
  } else {
    console.log(response);
  }
  ```

  ```csharp C#
  AnthropicClient client = new();

  var parameters = new MessageCreateParams
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Messages = [
          new() {
              Role = Role.User,
              Content = "Search for comprehensive information about quantum computing breakthroughs in 2025"
          }
      ],
      Tools = [new ToolUnion(new WebSearchTool20250305 { MaxUses = 10 })]
  };

  var response = await client.Messages.Create(parameters);

  if (response.StopReason?.Value() == StopReason.PauseTurn)
  {
      // Продолжить диалог с приостановленным содержимым
      var continuationParams = new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 1024,
          Messages = [
              new() {
                  Role = Role.User,
                  Content = "Search for comprehensive information about quantum computing breakthroughs in 2025"
              },
              new() {
                  Role = Role.Assistant,
                  Content = response.Content.Select(block => new ContentBlockParam(block.Json)).ToList()
              }
          ],
          Tools = [new ToolUnion(new WebSearchTool20250305 { MaxUses = 10 })]
      };

      var continuation = await client.Messages.Create(continuationParams);
      Console.WriteLine(continuation);
  }
  else
  {
      Console.WriteLine(response);
  }
  ```

  ```go Go
  client := anthropic.NewClient()

  webSearchTool := []anthropic.ToolUnionParam{
  	{OfWebSearchTool20250305: &anthropic.WebSearchTool20250305Param{
  		MaxUses: anthropic.Int(10),
  	}},
  }

  response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	Messages: []anthropic.MessageParam{
  		anthropic.NewUserMessage(anthropic.NewTextBlock("Search for comprehensive information about quantum computing breakthroughs in 2025")),
  	},
  	Tools: webSearchTool,
  })
  if err != nil {
  	log.Fatal(err)
  }

  if response.StopReason == anthropic.StopReasonPauseTurn {
  	// Передайте приостановленный ответ обратно без изменений, чтобы Claude мог продолжить ход
  	continuation, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  		Model:     anthropic.ModelClaudeOpus5_5,
  		MaxTokens: 1024,
  		Messages: []anthropic.MessageParam{
  			anthropic.NewUserMessage(anthropic.NewTextBlock("Search for comprehensive information about quantum computing breakthroughs in 2025")),
  			response.ToParam(),
  		},
  		Tools: webSearchTool,
  	})
  	if err != nil {
  		log.Fatal(err)
  	}
  	fmt.Println(continuation)
  } else {
  	fmt.Println(response)
  }
  ```

  ```java Java
  import com.anthropic.models.messages.StopReason;
  import com.anthropic.models.messages.WebSearchTool20250305;

  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      MessageCreateParams params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          .maxTokens(1024L)
          .addUserMessage("Search for comprehensive information about quantum computing breakthroughs in 2025")
          .addTool(WebSearchTool20250305.builder()
              .maxUses(10L)
              .build())
          .build();

      Message response = client.messages().create(params);

      if (response.stopReason().isPresent()
              && response.stopReason().get().equals(StopReason.PAUSE_TURN)) {
          MessageCreateParams continuationParams = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(1024L)
              .addUserMessage("Search for comprehensive information about quantum computing breakthroughs in 2025")
              .addMessage(response)
              .addTool(WebSearchTool20250305.builder()
                  .maxUses(10L)
                  .build())
              .build();

          Message continuation = client.messages().create(continuationParams);
          IO.println(continuation);
      } else {
          IO.println(response);
      }
  }
  ```

  ```php PHP
  $client = new Client();

  $response = $client->messages->create(
      maxTokens: 1024,
      messages: [
          [
              'role' => 'user',
              'content' => 'Search for comprehensive information about quantum computing breakthroughs in 2025'
          ]
      ],
      model: 'claude-opus-5-5',
      tools: [
          [
              'type' => 'web_search_20250305',
              'name' => 'web_search',
              'max_uses' => 10
          ]
      ],
  );

  if ($response->stopReason === 'pause_turn') {
      $messages = [
          [
              'role' => 'user',
              'content' => 'Search for comprehensive information about quantum computing breakthroughs in 2025'
          ],
          [
              'role' => 'assistant',
              'content' => $response->content
          ]
      ];

      $continuation = $client->messages->create(
          maxTokens: 1024,
          messages: $messages,
          model: 'claude-opus-5-5',
          tools: [
              [
                  'type' => 'web_search_20250305',
                  'name' => 'web_search',
                  'max_uses' => 10
              ]
          ],
      );

      echo $continuation;
  } else {
      echo $response;
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  response = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 1024,
    messages: [
      {
        role: "user",
        content:
          "Search for comprehensive information about quantum computing breakthroughs in 2025"
      }
    ],
    tools: [
      {
        type: "web_search_20250305",
        name: "web_search",
        max_uses: 10
      }
    ]
  )

  if response.stop_reason == :pause_turn
    messages = [
      {
        role: "user",
        content: "Search for comprehensive information about quantum computing breakthroughs in 2025"
      },
      {
        role: "assistant",
        content: response.content
      }
    ]

    continuation = client.messages.create(
      model: "claude-opus-5-5",
      max_tokens: 1024,
      messages: messages,
      tools: [
        {
          type: "web_search_20250305",
          name: "web_search",
          max_uses: 10
        }
      ]
    )

    puts continuation
  else
    puts response
  end
  ```
</CodeGroup>

При обработке `pause_turn`:

* **Продолжите разговор:** передайте приостановленный ответ без изменений в следующем запросе, чтобы Claude продолжил свой ход.
* **Сохраните состояние инструментов:** включите те же инструменты в запрос продолжения. Приостановленный ход может завершиться блоком `server_tool_use`, инструмент которого ещё не запускался. Если этого инструмента нет в продолжении, API возвращает ошибку валидации.
* **Повторяйте по мере необходимости:** продолженный ход может снова приостановиться. Проверяйте `stop_reason` в каждом ответе и продолжайте, пока не получите другую причину остановки. Ограничьте число продолжений, как в любом цикле повторных попыток.

Другие значения `stop_reason` и общие шаблоны обработки см. в разделе [Причины остановки и резервные варианты](https://platform.claude.com/docs/ru/build-with-claude/handling-stop-reasons).

## Сочетание серверных и клиентских инструментов в одном ходе

Claude может вызвать серверный и клиентский инструмент в одной группе параллельных вызовов инструментов, например `web_fetch` вместе с пользовательским инструментом. Клиентский инструмент — это любой инструмент, который выполняет ваш код и который порождает блок `tool_use`, будь то пользовательский инструмент или клиентский инструмент со схемой Anthropic, такой как [инструмент Bash](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/bash-tool). Когда это происходит, API не запускает серверный инструмент. Он немедленно возвращает ответ, чтобы вы могли сначала выполнить клиентский инструмент:

* `stop_reason` равен `"tool_use"`, а не `"pause_turn"`.
* `content` содержит блок `server_tool_use` и клиентский блок `tool_use`, но не содержит блока результата для серверного инструмента: этот вызов не завершён.
* Других маркеров нет. Определяйте это состояние по наличию блока `server_tool_use`, для `id` которого в ответе нет соответствующего блока результата. Блок `mcp_tool_use` от [коннектора MCP](https://platform.claude.com/docs/ru/agents-and-tools/mcp-connector) ведёт себя так же. Вызовы серверных инструментов, у которых уже есть блок результата в том же ответе, завершены и ничего от вас не требуют.

<Note>
  При [программном вызове инструментов](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/programmatic-tool-calling) та же форма ответа означает нечто иное. Клиентский блок `tool_use` исходит от кода, выполняющегося в инструменте `code_execution`, а не напрямую от Claude, и его поле `caller` указывает на блок `code_execution`, который его вызвал. Этот код уже запущен: он приостановлен в ожидании ваших блоков `tool_result`, и их отправка возобновляет выполнение, а не запускает отложенный инструмент. Собственный блок результата блока `code_execution` приходит после завершения кода, что может потребовать более одного раунда результатов инструментов. Само последующее сообщение пользователя одинаково в обоих случаях; при программном вызове инструментов также передавайте обратно `id` из поля `container` ответа, как показано на той странице.
</Note>

```json
{
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "text",
      "text": "I'll fetch the article and check your system at the same time."
    },
    {
      "type": "server_tool_use",
      "id": "srvtoolu_01HxbWnMRmbWyMfUtJKC45rA",
      "name": "web_fetch",
      "input": { "url": "https://example.com/article" }
    },
    {
      "type": "tool_use",
      "id": "toolu_01PjgRJLbXrXEMZwDNYLnBqk",
      "name": "run_command",
      "input": { "command": "uname -a" }
    }
  ]
}
```

Чтобы продолжить ход, выполните клиентские инструменты и отправьте сообщение пользователя, содержимое которого состоит только из блоков `tool_result` — по одному на каждый блок `tool_use` в этом ответе. Сохраните тот же массив `tools`: запрос на возобновление, в котором больше не определён ожидающий серверный инструмент, завершается ошибкой 400, сообщение которой заканчивается на ``but no `web_fetch` tool was provided``.

```json
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_01PjgRJLbXrXEMZwDNYLnBqk",
      "content": "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux"
    }
  ]
}
```

API присоединяет ваши результаты к всё ещё открытому ходу ассистента, запускает отложенный серверный инструмент (для приостановленного выполнения кода — возобновляет его), а затем позволяет Claude продолжить. Для серверного инструмента, вызванного Claude напрямую, следующий ответ начинается с блока результата, отвечающего на `id` блока `server_tool_use` из предыдущего ответа, за которым следуют вновь сгенерированное содержимое и новый `stop_reason`:

```json
{
  "stop_reason": "end_turn",
  "content": [
    {
      "type": "web_fetch_tool_result",
      "tool_use_id": "srvtoolu_01HxbWnMRmbWyMfUtJKC45rA",
      "content": {
        "type": "web_fetch_result",
        "url": "https://example.com/article",
        "content": {
          "type": "document",
          "source": {
            "type": "text",
            "media_type": "text/plain",
            "data": "Full text content of the article..."
          }
        }
      }
    },
    {
      "type": "text",
      "text": "The article argues that... and your machine is running Linux..."
    }
  ]
}
```

Блок `server_tool_use` и его блок результата связываются по `tool_use_id`, а не по позиции: в этом сценарии они приходят в двух разных ответах, и блок `server_tool_use` не повторяется во втором. В последующих запросах сохраняйте весь обмен в массиве `messages` по порядку: первый ответ как сообщение `assistant`, сообщение пользователя с `tool_result`, а затем следующий ответ как ещё одно сообщение `assistant` — так же, как вы накапливаете любой другой обмен с использованием инструментов.

<Warning>
  Последующее сообщение пользователя не должно содержать ничего, кроме блоков `tool_result`. Блок, добавленный после результатов, например текст, сообщает API, что ход ассистента завершён. Для серверного инструмента, вызванного Claude напрямую, это оставляет ход с неразрешённым вызовом серверного инструмента, и запрос завершается ошибкой 400 `invalid_request_error`:

  ```text wrap
  `web_fetch` tool use with id `srvtoolu_01HxbWnMRmbWyMfUtJKC45rA` was found without a corresponding `web_fetch_tool_result` block
  ```

  Последующее сообщение, в котором содержимое помещено перед результатами, которое отвечает только на часть клиентских идентификаторов `tool_use` или вовсе не содержит блоков `tool_result`, завершается ошибкой раньше — с ошибкой клиентского инструмента, описанной в разделе [Обработка вызовов инструментов](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/handle-tool-calls):

  ```text wrap
  `tool_use` ids were found without `tool_result` blocks immediately after: toolu_01PjgRJLbXrXEMZwDNYLnBqk. Each `tool_use` block must have a corresponding `tool_result` block in the next message.
  ```

  Чтобы передать Claude дополнительные входные данные, отправьте их отдельным сообщением пользователя после завершения хода.
</Warning>

**Чем это отличается от `pause_turn`:** [ответ `pause_turn`](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/server-tools#the-server-side-loop-and-pause-turn) также может завершаться блоком `server_tool_use`, который ещё не выполнялся, но он никогда не оставляет клиентский блок `tool_use`, ожидающий вас, поэтому вы продолжаете его, повторно отправляя содержимое ассистента как есть. Ответ, который оставляет клиентский блок `tool_use`, ожидающий вас, никогда не имеет `stop_reason` со значением `pause_turn`: когда Claude останавливается, чтобы вызвать ваши инструменты, `stop_reason` равен `tool_use`, и вы продолжаете его, отправляя клиентские блоки `tool_result`, а не повторно отправляя ответ. В обоих случаях API запускает ожидающий серверный инструмент в начале следующего запроса.

В следующем примере веб-загрузка включена вместе с пользовательским инструментом `run_command`, и обрабатывается смешанный ответ:

<CodeGroup>
  ```bash cURL
  # Если "stop_reason" равен "tool_use" и у блока server_tool_use нет соответствующего
  # блока результата, этот вызов не завершён. Запустите клиентские инструменты, затем снова
  # отправьте POST с ещё одним сообщением user, содержащим только их блоки tool_result,
  # и тем же массивом tools (см. вкладки SDK).
  curl https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 1024,
      "messages": [
        {
          "role": "user",
          "content": "Summarize https://example.com/article and run uname -a to tell me what system this is on."
        }
      ],
      "tools": [
        {"type": "web_fetch_20250910", "name": "web_fetch", "max_uses": 5},
        {
          "name": "run_command",
          "description": "Run a shell command on this computer and return its output.",
          "input_schema": {
            "type": "object",
            "properties": {"command": {"type": "string", "description": "The command to run"}},
            "required": ["command"]
          }
        }
      ]
    }'
  ```

  ```bash CLI
  # Если "stop_reason" равен "tool_use" и у блока server_tool_use нет соответствующего
  # блока результата, выполните клиентские инструменты и повторите запрос, добавив сообщение user
  # только с их блоками tool_result (см. вкладки SDK).
  ant messages create <<'YAML'
  model: claude-opus-5-5
  max_tokens: 1024
  messages:
    - role: user
      content: "Summarize https://example.com/article and run uname -a to tell me what system this is on."
  tools:
    - {type: web_fetch_20250910, name: web_fetch, max_uses: 5}
    - name: run_command
      description: Run a shell command on this computer and return its output.
      input_schema:
        type: object
        properties:
          command: {type: string, description: The command to run}
        required: [command]
  YAML
  ```

  ```python Python
  client = anthropic.Anthropic()

  tools = [
      {"type": "web_fetch_20250910", "name": "web_fetch", "max_uses": 5},
      {
          "name": "run_command",
          "description": "Run a shell command on this computer and return its output.",
          "input_schema": {
              "type": "object",
              "properties": {
                  "command": {"type": "string", "description": "The command to run"}
              },
              "required": ["command"],
          },
      },
  ]
  messages = [
      {
          "role": "user",
          "content": "Summarize https://example.com/article and run uname -a to tell me what system this is on.",
      }
  ]

  response = client.messages.create(
      model="claude-opus-5-5", max_tokens=1024, tools=tools, messages=messages
  )

  tool_results = [
      {
          "type": "tool_result",
          "tool_use_id": block.id,
          # Запустите здесь свой инструмент. В этом примере возвращается фиксированная строка.
          "content": "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux",
      }
      for block in response.content
      if block.type == "tool_use"
  ]

  if response.stop_reason == "tool_use" and tool_results:
      # Блок server_tool_use без блока результата в этом ответе не завершён; его результат придёт в следующем ответе.
      # Отправьте обратно только клиентские блоки tool_result с теми же инструментами.
      continuation = client.messages.create(
          model="claude-opus-5-5",
          max_tokens=1024,
          tools=tools,
          messages=[
              *messages,
              {"role": "assistant", "content": response.content},
              {"role": "user", "content": tool_results},
          ],
      )
      # Если web_fetch был отложен, он выполняется в этом запросе, и его
      # web_fetch_tool_result будет первым блоком в continuation.content.
      print(continuation)
  else:
      print(response)
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const webFetchTool = {
    type: "web_fetch_20250910",
    name: "web_fetch",
    max_uses: 5
  } as const;
  const runCommandTool: Anthropic.Tool = {
    name: "run_command",
    description: "Run a shell command on this computer and return its output.",
    input_schema: {
      type: "object" as const,
      properties: {
        command: { type: "string", description: "The command to run" }
      },
      required: ["command"]
    }
  };
  const messages: Anthropic.MessageParam[] = [
    {
      role: "user",
      content:
        "Summarize https://example.com/article and run uname -a to tell me what system this is on."
    }
  ];

  const response = await client.messages.create({
    model: "claude-opus-5-5",
    max_tokens: 1024,
    tools: [webFetchTool, runCommandTool],
    messages
  });

  const toolResults: Anthropic.ToolResultBlockParam[] = [];
  for (const block of response.content) {
    if (block.type === "tool_use") {
      toolResults.push({
        type: "tool_result",
        tool_use_id: block.id,
        // Запустите здесь свой инструмент. В этом примере возвращается фиксированная строка.
        content: "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux"
      });
    }
  }

  if (response.stop_reason === "tool_use" && toolResults.length > 0) {
    // Блок server_tool_use без блока результата в этом ответе не завершён; его результат придёт в следующем ответе.
    // Отправьте обратно только клиентские блоки tool_result с теми же инструментами.
    const continuation = await client.messages.create({
      model: "claude-opus-5-5",
      max_tokens: 1024,
      tools: [webFetchTool, runCommandTool],
      messages: [
        ...messages,
        { role: "assistant", content: response.content },
        { role: "user", content: toolResults }
      ]
    });
    // Если web_fetch был отложен, он выполняется в этом запросе, и его
    // web_fetch_tool_result будет первым блоком в continuation.content.
    console.log(continuation);
  } else {
    console.log(response);
  }
  ```

  ```csharp C#
  AnthropicClient client = new();

  List<ToolUnion> tools =
  [
      new ToolUnion(new WebFetchTool20250910() { MaxUses = 5 }),
      new ToolUnion(new Tool()
      {
          Name = "run_command",
          Description = "Run a shell command on this computer and return its output.",
          InputSchema = new InputSchema()
          {
              Properties = new Dictionary<string, JsonElement>
              {
                  ["command"] = JsonSerializer.SerializeToElement(
                      new { type = "string", description = "The command to run" }
                  ),
              },
              Required = ["command"],
          },
      }),
  ];
  MessageParam userMessage = new()
  {
      Role = Role.User,
      Content = "Summarize https://example.com/article and run uname -a to tell me what system this is on."
  };

  var response = await client.Messages.Create(new MessageCreateParams
  {
      Model = Model.ClaudeOpus5_5,
      MaxTokens = 1024,
      Tools = tools,
      Messages = [userMessage]
  });

  var toolResults = new List<ContentBlockParam>();
  foreach (var block in response.Content)
  {
      if (block.TryPickToolUse(out var toolUse))
      {
          toolResults.Add(new ContentBlockParam(new ToolResultBlockParam()
          {
              ToolUseID = toolUse.ID,
              // Запустите здесь свой инструмент. В этом примере возвращается фиксированная строка.
              Content = "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux",
          }));
      }
  }

  if (response.StopReason?.Value() == StopReason.ToolUse && toolResults.Count > 0)
  {
      // Блок server_tool_use без блока результата в этом ответе не завершён; его результат придёт в одном из следующих ответов.
      // Отправьте обратно только клиентские блоки tool_result с теми же инструментами.
      var continuation = await client.Messages.Create(new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 1024,
          Tools = tools,
          Messages =
          [
              userMessage,
              new()
              {
                  Role = Role.Assistant,
                  Content = response.Content.Select(block => new ContentBlockParam(block.Json)).ToList()
              },
              new() { Role = Role.User, Content = new MessageParamContent(toolResults) }
          ]
      });
      // Если web_fetch был отложен, он выполняется в этом запросе, и его
      // web_fetch_tool_result будет первым блоком в continuation.Content.
      Console.WriteLine(continuation);
  }
  else
  {
      Console.WriteLine(response);
  }
  ```

  ```go Go
  client := anthropic.NewClient()

  tools := []anthropic.ToolUnionParam{
  	{OfWebFetchTool20250910: &anthropic.WebFetchTool20250910Param{
  		MaxUses: anthropic.Int(5),
  	}},
  	{OfTool: &anthropic.ToolParam{
  		Name:        "run_command",
  		Description: anthropic.String("Run a shell command on this computer and return its output."),
  		InputSchema: anthropic.ToolInputSchemaParam{
  			Properties: map[string]any{
  				"command": map[string]any{
  					"type":        "string",
  					"description": "The command to run",
  				},
  			},
  			Required: []string{"command"},
  		},
  	}},
  }
  userMessage := anthropic.NewUserMessage(anthropic.NewTextBlock("Summarize https://example.com/article and run uname -a to tell me what system this is on."))

  response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  	Model:     anthropic.ModelClaudeOpus5_5,
  	MaxTokens: 1024,
  	Tools:     tools,
  	Messages:  []anthropic.MessageParam{userMessage},
  })
  if err != nil {
  	log.Fatal(err)
  }

  var toolResults []anthropic.ContentBlockParamUnion
  for _, block := range response.Content {
  	if toolUse, ok := block.AsAny().(anthropic.ToolUseBlock); ok {
  		// Запустите здесь свой инструмент. Этот пример возвращает фиксированную строку.
  		output := "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux"
  		toolResults = append(toolResults, anthropic.NewToolResultBlock(toolUse.ID, output, false))
  	}
  }

  if response.StopReason == anthropic.StopReasonToolUse && len(toolResults) > 0 {
  	// Блок server_tool_use без блока результата в этом ответе не завершён; его результат придёт в следующем ответе.
  	// Отправьте обратно только клиентские блоки tool_result с теми же инструментами.
  	continuation, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
  		Model:     anthropic.ModelClaudeOpus5_5,
  		MaxTokens: 1024,
  		Tools:     tools,
  		Messages: []anthropic.MessageParam{
  			userMessage,
  			response.ToParam(),
  			anthropic.NewUserMessage(toolResults...),
  		},
  	})
  	if err != nil {
  		log.Fatal(err)
  	}
  	// Если web_fetch был отложен, он выполняется в этом запросе, и его
  	// web_fetch_tool_result — первый блок в continuation.Content.
  	fmt.Println(continuation)
  } else {
  	fmt.Println(response)
  }
  ```

  ```java Java
  void main() {
      AnthropicClient client = AnthropicOkHttpClient.fromEnv();

      Tool runCommandTool = Tool.builder()
          .name("run_command")
          .description("Run a shell command on this computer and return its output.")
          .inputSchema(Tool.InputSchema.builder()
              .properties(JsonValue.from(Map.of(
                  "command", Map.of("type", "string", "description", "The command to run")
              )))
              .putAdditionalProperty("required", JsonValue.from(List.of("command")))
              .build())
          .build();
      String prompt = "Summarize https://example.com/article and run uname -a to tell me what system this is on.";

      Message response = client.messages().create(MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          .maxTokens(1024L)
          .addTool(WebFetchTool20250910.builder().maxUses(5L).build())
          .addTool(runCommandTool)
          .addUserMessage(prompt)
          .build());

      List<ContentBlockParam> toolResults = new ArrayList<>();
      for (ContentBlock block : response.content()) {
          block.toolUse().ifPresent(toolUse -> toolResults.add(ContentBlockParam.ofToolResult(
              ToolResultBlockParam.builder()
                  .toolUseId(toolUse.id())
                  // Запустите здесь свой инструмент. В этом примере возвращается фиксированная строка.
                  .content("Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux")
                  .build()
          )));
      }

      boolean isToolUse = response.stopReason()
          .map(StopReason.TOOL_USE::equals)
          .orElse(false);
      if (isToolUse && !toolResults.isEmpty()) {
          // Блок server_tool_use без блока результата в этом ответе не завершён; его результат придёт в следующем ответе.
          // Отправьте обратно только клиентские блоки tool_result с теми же инструментами.
          Message continuation = client.messages().create(MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(1024L)
              .addTool(WebFetchTool20250910.builder().maxUses(5L).build())
              .addTool(runCommandTool)
              .addUserMessage(prompt)
              .addMessage(response)
              .addUserMessageOfBlockParams(toolResults)
              .build());
          // Если web_fetch был отложен, он выполняется в этом запросе, и его
          // web_fetch_tool_result будет первым блоком в continuation.content().
          IO.println(continuation);
      } else {
          IO.println(response);
      }
  }
  ```

  ```php PHP
  $client = new Client();

  $tools = [
      ['type' => 'web_fetch_20250910', 'name' => 'web_fetch', 'max_uses' => 5],
      [
          'name' => 'run_command',
          'description' => 'Run a shell command on this computer and return its output.',
          'input_schema' => [
              'type' => 'object',
              'properties' => [
                  'command' => ['type' => 'string', 'description' => 'The command to run']
              ],
              'required' => ['command']
          ]
      ]
  ];
  $userMessage = ['role' => 'user', 'content' => 'Summarize https://example.com/article and run uname -a to tell me what system this is on.'];

  $response = $client->messages->create(
      maxTokens: 1024,
      messages: [$userMessage],
      model: 'claude-opus-5-5',
      tools: $tools,
  );

  $toolResults = [];
  foreach ($response->content as $block) {
      if ($block->type === 'tool_use') {
          $toolResults[] = [
              'type' => 'tool_result',
              'tool_use_id' => $block->id,
              // Запустите здесь свой инструмент. Этот пример возвращает фиксированную строку.
              'content' => 'Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux'
          ];
      }
  }

  if ($response->stopReason === 'tool_use' && count($toolResults) > 0) {
      // Блок server_tool_use без блока результата в этом ответе не завершён; его результат придёт в последующем ответе.
      // Отправьте обратно только клиентские блоки tool_result с теми же инструментами.
      $continuation = $client->messages->create(
          maxTokens: 1024,
          messages: [
              $userMessage,
              ['role' => 'assistant', 'content' => $response->content],
              ['role' => 'user', 'content' => $toolResults],
          ],
          model: 'claude-opus-5-5',
          tools: $tools,
      );
      // Если web_fetch был отложен, он выполняется в этом запросе, и его
      // web_fetch_tool_result будет первым блоком в $continuation->content.
      echo $continuation;
  } else {
      echo $response;
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  tools = [
    { type: "web_fetch_20250910", name: "web_fetch", max_uses: 5 },
    {
      name: "run_command",
      description: "Run a shell command on this computer and return its output.",
      input_schema: {
        type: "object",
        properties: {
          command: { type: "string", description: "The command to run" }
        },
        required: ["command"]
      }
    }
  ]
  user_message = {
    role: "user",
    content: "Summarize https://example.com/article and run uname -a to tell me what system this is on."
  }

  response = client.messages.create(
    model: "claude-opus-5-5",
    max_tokens: 1024,
    tools: tools,
    messages: [user_message]
  )

  tool_results = []
  response.content.each do |block|
    next unless block.type == :tool_use

    tool_results << {
      type: "tool_result",
      tool_use_id: block.id,
      # Запустите здесь свой инструмент. В этом примере возвращается фиксированная строка.
      content: "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux"
    }
  end

  if response.stop_reason == :tool_use && !tool_results.empty?
    # Блок server_tool_use без блока результата в этом ответе не завершён; его результат придёт в последующем ответе.
    # Отправьте обратно только клиентские блоки tool_result с теми же инструментами.
    continuation = client.messages.create(
      model: "claude-opus-5-5",
      max_tokens: 1024,
      tools: tools,
      messages: [
        user_message,
        { role: "assistant", content: response.content },
        { role: "user", content: tool_results }
      ]
    )
    # Если web_fetch был отложен, он выполняется в этом запросе, и его
    # web_fetch_tool_result будет первым блоком в continuation.content.
    puts continuation
  else
    puts response
  end
  ```
</CodeGroup>

Этот код также корректен, когда Claude не смешивает два вида вызовов. Ход, содержащий только клиентские блоки `tool_use`, проходит по тому же пути продолжения, а ход, содержащий только вызовы серверных инструментов, не требует от вас клиентских блоков `tool_result`: его блоки результатов обычно уже присутствуют, а ход, вернувшийся приостановленным, например [ответ `pause_turn`](https://platform.claude.com/docs/ru/agents-and-tools/tool-use/server-tools#the-server-side-loop-and-pause-turn), вместо этого повторно отправляется как есть.

## ZDR и allowed\_callers

Базовые версии веб-поиска (`web_search_20250305`) и веб-загрузки (`web_fetch_20250910`) соответствуют требованиям [Zero Data Retention (ZDR)](https://platform.claude.com/docs/ru/manage-claude/api-and-data-retention).

Версии `_20260209` и более поздние с динамической фильтрацией по умолчанию **не** соответствуют требованиям ZDR, поскольку динамическая фильтрация внутренне опирается на выполнение кода.

Чтобы использовать серверный инструмент версии `_20260209` или более поздней с ZDR, отключите динамическую фильтрацию, задав для инструмента `"allowed_callers": ["direct"]`:

```json
{
  "type": "web_search_20260209",
  "name": "web_search",
  "allowed_callers": ["direct"]
}
```

Это ограничивает инструмент только прямым вызовом, минуя внутренний этап выполнения кода.

`allowed_callers` управляет тем, как может быть вызван инструмент: напрямую Claude (`"direct"`), изнутри контейнера выполнения кода (например, `"code_execution_20260120"`) или обоими способами. Версии `_20260209` веб-инструментов по умолчанию допускают только вызов из выполнения кода; более ранние версии по умолчанию используют `["direct"]`. На моделях, не поддерживающих программный вызов инструментов, эти версии требуют `allowed_callers: ["direct"]`; без этого API возвращает ошибку валидации с указанием задать это значение.

<Note>
  Даже когда веб-загрузка используется в конфигурации, соответствующей требованиям ZDR, издатели веб-сайтов могут сохранять любые параметры, переданные в URL, если Claude загружает содержимое с их сайта.
</Note>

## Фильтрация доменов

Серверные инструменты, обращающиеся к вебу, принимают параметры `allowed_domains` и `blocked_domains` для управления тем, к каким доменам Claude может обращаться. Оба являются полями объекта инструмента:

```json
{
  "type": "web_search_20250305",
  "name": "web_search",
  "allowed_domains": ["example.com", "docs.python.org"]
}
```

При использовании фильтров доменов:

* Домены не должны включать схему HTTP/HTTPS (используйте `example.com` вместо `https://example.com`).
* Поддомены включаются автоматически (`example.com` охватывает `docs.example.com`).
* Конкретные поддомены ограничивают результаты только этим поддоменом (`docs.example.com` возвращает результаты только с этого поддомена, а не с `example.com` или `api.example.com`).
* Подпути поддерживаются для веб-поиска и соответствуют всему, что следует после пути (`example.com/blog` соответствует `example.com/blog/post-1`).
* Веб-загрузка сопоставляет только домен: запись, включающая путь, никогда не соответствует URL веб-загрузки.
* Вы можете использовать либо `allowed_domains`, либо `blocked_domains`, но не оба параметра в одном запросе.

**Поддержка подстановочных знаков:**

* Подстановочные знаки (`*`) не допускаются в самом домене, только в пути после него.
* Допустимо: `example.com/*`, `example.com/*/articles`
* Недопустимо: `*.example.com`, `ex*.com`

Недопустимые форматы доменов отклоняются во время запроса с ошибкой 400 `invalid_request_error`.

<Note>
  Ограничения доменов на уровне запроса действуют совместно с любыми ограничениями доменов на уровне организации, настроенными в Claude Console. `allowed_domains` на уровне запроса должен быть подмножеством разрешённого списка на уровне организации; записи за его пределами приводят к тому, что API возвращает ошибку валидации. Разрешённый список на уровне запроса, включающий домен, который блокирует ваша организация, отклоняется с ошибкой `400`, в которой указаны конфликтующие записи.
</Note>

<Warning>
  Символы Unicode в доменных именах могут обходить фильтры доменов посредством омографических атак: `аmazon.com` (с кириллической `а`) выглядит идентично `amazon.com`, но является другим доменом. Используйте в списках разрешённых и заблокированных доменов только доменные имена в ASCII и проверяйте существующие записи на наличие символов, не входящих в ASCII.
</Warning>

[Claude Managed Agents](https://platform.claude.com/docs/ru/managed-agents/overview) использует те же поля `allowed_domains` и `blocked_domains` в записях `web_search` и `web_fetch` набора инструментов агента. В Managed Agents каждый список содержит не более 64 записей, домены, указанные для `web_fetch`, не могут включать путь, а поля, специфичные для инструментов Messages API, такие как `max_uses`, `citations` и `cache_control`, недоступны. Полные правила см. в разделе [Правила списков доменов](https://platform.claude.com/docs/ru/managed-agents/tools-web-restrictions#domain-list-rules).

Настройки веб-поиска и веб-загрузки на уровне организации в Claude Console применяются только к запросам Messages API. Они не применяются к сессиям Managed Agents, которые вместо этого используют списки для каждого инструмента в наборе инструментов агента. Для сессии в облачной среде с сетевым режимом `limited` параметр `allowed_hosts` среды также применяется к `web_search` и `web_fetch`; см. раздел [Сеть](https://platform.claude.com/docs/ru/managed-agents/environments#networking). Списки для каждого инструмента дополнительно ограничивают эти инструменты в пределах хостов, разрешённых `allowed_hosts`.

## Динамическая фильтрация с выполнением кода

Версии `_20260209` и более поздние веб-поиска и веб-загрузки внутренне используют выполнение кода для применения динамических фильтров к результатам поиска.

<Note>
  Вам не нужно добавлять инструмент `code_execution` для этих версий: когда выполняется динамическая фильтрация, API автоматически предоставляет выполнение кода для запроса, и оба инструмента используют один общий контейнер выполнения. Если вы всё же включаете его, используйте `code_execution_20260120` или более позднюю версию; API отклоняет более старые версии выполнения кода в сочетании с этими версиями веб-инструментов.
</Note>

## Потоковая передача событий серверных инструментов

События серверных инструментов передаются в рамках обычного потока «server-sent events» (события, отправляемые сервером), или SSE. Блок `server_tool_use`, который Claude вызывает напрямую, передаётся потоком так же, как клиентский блок `tool_use`: событие `content_block_start`, за которым следуют события `input_json_delta`. Блок результата приходит целиком в одном событии `content_block_start`, без дельт.

Полный справочник по событиям см. в разделе [Потоковая передача](https://platform.claude.com/docs/ru/build-with-claude/streaming). На страницах отдельных инструментов описаны специфичные для инструментов имена событий там, где они отличаются.

## Пакетные запросы

Все серверные инструменты поддерживают пакетную обработку. В пакете агентный цикл работает так же, как и для синхронных запросов, но с более высоким лимитом итераций на ход. Если цикл достигает этого лимита, ответ завершается с `stop_reason: "pause_turn"`; вы можете продолжить его, отправив последующий запрос с возвращённым содержимым. Подробности см. в разделе [Серверные инструменты и агентный цикл](https://platform.claude.com/docs/ru/build-with-claude/batch-processing#server-tools-and-the-agentic-loop).

Типичные пакетные нагрузки включают обогащение набора данных информацией из веба, проверку большого набора документов по актуальным источникам и выполнение аналитического кода над множеством файлов.

## Следующие шаги

<CardGroup cols={2}>
  <Card title="Устранение неполадок при использовании инструментов" icon="wrench" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/troubleshooting-tool-use">
    Исправьте наиболее распространённые ошибки использования инструментов с помощью диагностических таблиц «симптом — решение».
  </Card>

  <Card title="Инструмент веб-поиска" icon="magnifying-glass" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/web-search-tool">
    Ищите в вебе и цитируйте результаты.
  </Card>

  <Card title="Инструмент веб-загрузки" icon="download" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/web-fetch-tool">
    Загружайте и читайте содержимое по конкретным URL, чтобы дополнить контекст Claude актуальным веб-содержимым.
  </Card>

  <Card title="Инструмент выполнения кода" icon="terminal" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/code-execution-tool">
    Запускайте код на Python и bash в изолированном контейнере для анализа данных, создания файлов и итеративной работы над решениями.
  </Card>

  <Card title="Инструмент поиска инструментов" icon="compass" href="https://platform.claude.com/docs/ru/agents-and-tools/tool-use/tool-search-tool">
    Находите и загружайте инструменты по требованию.
  </Card>
</CardGroup>
