---
title: Server-Tools
url: https://platform.claude.com/docs/de/agents-and-tools/tool-use/server-tools
description: "Arbeite mit von Anthropic ausgeführten Tools: server_tool_use-Blöcke, pause_turn-Fortsetzung, gemischte Server- und Client-Tool-Turns sowie Domain-Filterung."
---

Serverseitig ausgeführte Tools teilen diese Mechanismen: den `server_tool_use`-Block, die `pause_turn`-Fortsetzung, Turns, die Server- und Client-Tools mischen, die Berechtigung für „Zero Data Retention“ (keine Datenspeicherung), oder ZDR, sowie Domain-Filterung. Zu einzelnen Tools siehe die [Tool-Referenz](https://platform.claude.com/docs/de/agents-and-tools/tool-use/tool-reference).

## Der server\_tool\_use-Block

Der `server_tool_use`-Block erscheint in Claudes Antwort, wenn ein serverseitig ausgeführtes Tool läuft. Sein `id`-Feld verwendet das Präfix `srvtoolu_`, um es von Client-Tool-Aufrufen zu unterscheiden:

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

Die API führt das Tool intern aus. Du siehst den Aufruf und sein Ergebnis in der Antwort, kümmerst dich aber nicht um die Ausführung. Anders als bei Client-`tool_use`-Blöcken musst du nicht mit einem `tool_result` antworten. Der Ergebnisblock des Tools (zum Beispiel `web_search_tool_result` für die Websuche) folgt dem `server_tool_use`-Block im selben Assistant-Turn, zugeordnet über `tool_use_id`. Wenn Claude gleichzeitig eines deiner Client-Tools aufruft, erscheint der `server_tool_use`-Block ohne sein Ergebnis, und die Antwort endet mit `stop_reason: "tool_use"`. Die API führt das Tool aus, wenn du die Client-`tool_result`-Blöcke in deiner nächsten Anfrage zurückgibst.

## Die serverseitige Schleife und pause\_turn

Bei der Verwendung von Server-Tools wie der Websuche führt die API Tool-Aufrufe in einer serverseitigen agentischen Schleife aus. Bei einem lang laufenden Turn kann die API diese Schleife pausieren und den Stop-Reason `pause_turn` zurückgeben.

So behandelst du den Stop-Reason `pause_turn`:

<CodeGroup>
  ```bash cURL
  # Erste Anfrage. Wenn "stop_reason" in der Antwort "pause_turn" ist, setze
  # den Turn fort, indem du die Anfrage mit dem an messages angehängten Assistant-Inhalt erneut sendest.
  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
  # Erste Anfrage. Wenn "stop_reason" in der Ausgabe "pause_turn" ist, führe sie erneut aus,
  # wobei der Assistant-Inhalt an messages angehängt wird (siehe die SDK-Tabs).
  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()

  # Erste Anfrage mit Websuche
  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}],
  )

  # Prüfe, ob die Antwort den stop_reason pause_turn hat
  if response.stop_reason == "pause_turn":
      # Setze die Konversation mit dem pausierten Inhalt fort
      messages = [
          {
              "role": "user",
              "content": "Search for comprehensive information about quantum computing breakthroughs in 2025",
          },
          {"role": "assistant", "content": response.content},
      ]

      # Sende die Fortsetzungsanfrage
      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();

  // Erste Anfrage mit Websuche
  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
      }
    ]
  });

  // Prüfe, ob die Antwort den Stop-Grund pause_turn hat
  if (response.stop_reason === "pause_turn") {
    // Setze die Konversation mit dem pausierten Inhalt fort
    const messages: Anthropic.MessageParam[] = [
      {
        role: "user",
        content:
          "Search for comprehensive information about quantum computing breakthroughs in 2025"
      },
      { role: "assistant", content: response.content }
    ];

    // Sende die Fortsetzungsanfrage
    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)
  {
      // Setze die Konversation mit dem pausierten Inhalt fort
      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 {
  	// Gib die pausierte Antwort unverändert zurück, damit Claude den Turn fortsetzen kann
  	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>

Beim Behandeln von `pause_turn`:

* **Setze die Konversation fort:** Gib die pausierte Antwort unverändert in einer nachfolgenden Anfrage zurück, damit Claude seinen Turn fortsetzen kann.
* **Bewahre den Tool-Zustand:** Füge dieselben Tools in die Fortsetzungsanfrage ein. Ein pausierter Turn kann mit einem `server_tool_use`-Block enden, dessen Tool noch nicht gelaufen ist, und die API gibt einen Validierungsfehler zurück, wenn dieses Tool in der Fortsetzung fehlt.
* **Wiederhole bei Bedarf:** Ein fortgesetzter Turn kann erneut pausieren. Prüfe `stop_reason` bei jeder Antwort und setze fort, bis du einen anderen Stop-Reason erhältst, wobei du die Anzahl der Fortsetzungen wie bei jeder Retry-Schleife begrenzt.

Zu den anderen `stop_reason`-Werten und allgemeinen Behandlungsmustern siehe [Stop-Reasons und Fallback](https://platform.claude.com/docs/de/build-with-claude/handling-stop-reasons).

## Server-Tools und Client-Tools in einem Turn mischen

Claude kann ein Server-Tool und ein Client-Tool in derselben Gruppe paralleler Tool-Aufrufe aufrufen, zum Beispiel `web_fetch` zusammen mit einem benutzerdefinierten Tool. Ein Client-Tool ist jedes Tool, das dein Code ausführt und das einen `tool_use`-Block erzeugt, egal ob es benutzerdefiniert ist oder ein Client-Tool mit Anthropic-Schema wie das [Bash-Tool](https://platform.claude.com/docs/de/agents-and-tools/tool-use/bash-tool). Wenn das passiert, führt die API das Server-Tool nicht aus. Sie kehrt sofort zurück, damit du zuerst das Client-Tool ausführen kannst:

* `stop_reason` ist `"tool_use"`, nicht `"pause_turn"`.
* `content` enthält den `server_tool_use`-Block und den Client-`tool_use`-Block, aber keinen Ergebnisblock für das Server-Tool: Dieser Aufruf ist nicht abgeschlossen.
* Es gibt keine weitere Markierung. Erkenne den Zustand, indem du nach einem `server_tool_use`-Block suchst, dessen `id` keinen passenden Ergebnisblock in der Antwort hat. Ein `mcp_tool_use`-Block vom [MCP-Connector](https://platform.claude.com/docs/de/agents-and-tools/mcp-connector) verhält sich genauso. Server-Tool-Aufrufe, die ihren Ergebnisblock bereits in derselben Antwort haben, sind abgeschlossen und benötigen nichts von dir.

<Note>
  Beim [programmatischen Tool-Aufruf](https://platform.claude.com/docs/de/agents-and-tools/tool-use/programmatic-tool-calling) bedeutet dieselbe Antwortform etwas anderes. Der Client-`tool_use`-Block stammt von Code, der im `code_execution`-Tool läuft, und nicht direkt von Claude, und sein `caller`-Feld benennt den `code_execution`-Block, der ihn aufgerufen hat. Dieser Code hat bereits begonnen: Er ist pausiert und wartet auf deine `tool_result`-Blöcke, und das Senden dieser Blöcke setzt die Ausführung fort, anstatt ein zurückgestelltes Tool zu starten. Der eigene Ergebnisblock des `code_execution`-Blocks kommt an, sobald der Code fertig ist, was mehr als eine Runde von Tool-Ergebnissen dauern kann. Die nachfolgende User-Nachricht selbst ist in beiden Fällen gleich; beim programmatischen Tool-Aufruf gibst du zusätzlich die `id` aus dem `container`-Feld der Antwort zurück, wie jene Seite zeigt.
</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" }
    }
  ]
}
```

Um den Turn fortzusetzen, führe die Client-Tools aus und sende eine User-Nachricht, deren Inhalt ausschließlich aus den `tool_result`-Blöcken besteht, einer für jeden `tool_use`-Block in dieser Antwort. Behalte dasselbe `tools`-Array bei: Eine Fortsetzungsanfrage, die das wartende Server-Tool nicht mehr definiert, schlägt mit einem 400 fehl, dessen Meldung mit ``but no `web_fetch` tool was provided`` endet.

```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"
    }
  ]
}
```

Die API hängt deine Ergebnisse an den noch offenen Assistant-Turn an, führt das zurückgestellte Server-Tool aus (bei pausierter Code-Ausführung setzt sie diese fort) und lässt Claude dann fortfahren. Bei einem Server-Tool, das Claude direkt aufgerufen hat, beginnt die nächste Antwort mit dem Ergebnisblock, der die `server_tool_use`-`id` der vorherigen Antwort beantwortet, gefolgt vom neu generierten Inhalt und einem frischen `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..."
    }
  ]
}
```

Ein `server_tool_use`-Block und sein Ergebnisblock werden über `tool_use_id` zugeordnet, nicht über die Position: In diesem Ablauf kommen sie in zwei verschiedenen Antworten an, und der `server_tool_use`-Block wird in der zweiten nicht wiederholt. Behalte bei späteren Anfragen den gesamten Austausch in der richtigen Reihenfolge in deinem `messages`-Array: die erste Antwort als `assistant`-Nachricht, die `tool_result`-User-Nachricht und dann die nächste Antwort als weitere `assistant`-Nachricht, genauso wie du jeden anderen Tool-Use-Austausch ansammelst.

<Warning>
  Die nachfolgende User-Nachricht darf nichts außer `tool_result`-Blöcken enthalten. Ein nach den Ergebnissen hinzugefügter Block, etwa Text, signalisiert der API, dass der Assistant-Turn beendet ist. Bei einem Server-Tool, das Claude direkt aufgerufen hat, bleibt der Turn dadurch mit einem unaufgelösten Server-Tool-Aufruf zurück, und die Anfrage schlägt mit einem 400 `invalid_request_error` fehl:

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

  Eine Folgenachricht, die Inhalt vor die Ergebnisse setzt, nur einige der Client-`tool_use`-IDs beantwortet oder überhaupt keine `tool_result`-Blöcke enthält, schlägt früher fehl, mit dem Client-Tool-Fehler, der in [Tool-Aufrufe behandeln](https://platform.claude.com/docs/de/agents-and-tools/tool-use/handle-tool-calls) beschrieben ist:

  ```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.
  ```

  Um Claude weitere Eingaben zu geben, sende sie als separate User-Nachricht, nachdem der Turn abgeschlossen ist.
</Warning>

**Wie sich das von `pause_turn` unterscheidet:** Eine [`pause_turn`-Antwort](https://platform.claude.com/docs/de/agents-and-tools/tool-use/server-tools#the-server-side-loop-and-pause-turn) kann ebenfalls mit einem `server_tool_use`-Block enden, der nicht gelaufen ist, aber sie lässt nie einen Client-`tool_use`-Block auf dich warten, sodass du sie fortsetzt, indem du den Assistant-Inhalt unverändert erneut sendest. Eine Antwort, die einen Client-`tool_use`-Block auf dich warten lässt, hat nie den `stop_reason` `pause_turn`: Wenn Claude anhält, um deine Tools aufzurufen, ist `stop_reason` `tool_use`, und du setzt sie fort, indem du die Client-`tool_result`-Blöcke sendest, statt die Antwort erneut zu senden. In beiden Fällen führt die API das ausstehende Server-Tool zu Beginn der nächsten Anfrage aus.

Das folgende Beispiel aktiviert Web Fetch zusammen mit einem benutzerdefinierten `run_command`-Tool und behandelt die gemischte Antwort:

<CodeGroup>
  ```bash cURL
  # Wenn "stop_reason" gleich "tool_use" ist und ein server_tool_use-Block keinen passenden
  # Ergebnisblock hat, ist dieser Aufruf nicht abgeschlossen. Führe die Client-Tools aus, sende dann
  # erneut per POST mit einer weiteren User-Nachricht, die nur deren tool_result-Blöcke enthält,
  # und demselben tools-Array (siehe die SDK-Tabs).
  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
  # Wenn "stop_reason" gleich "tool_use" ist und ein server_tool_use-Block keinen passenden
  # Ergebnisblock hat, führe die Client-Tools aus und starte erneut mit einer User-Nachricht,
  # an die nur deren tool_result-Blöcke angehängt sind (siehe die SDK-Tabs).
  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,
          # Führe hier dein Tool aus. Dieses Beispiel gibt einen festen String zurück.
          "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:
      # Ein server_tool_use-Block ohne Ergebnisblock in dieser Antwort ist nicht abgeschlossen; sein Ergebnis kommt in einer späteren Antwort.
      # Sende nur die Client-tool_result-Blöcke zurück, mit denselben Tools.
      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},
          ],
      )
      # Wurde ein web_fetch aufgeschoben, läuft er bei dieser Anfrage und sein
      # web_fetch_tool_result ist der erste Block von 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,
        // Führe hier dein Tool aus. Dieses Beispiel gibt einen festen String zurück.
        content: "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux"
      });
    }
  }

  if (response.stop_reason === "tool_use" && toolResults.length > 0) {
    // Ein server_tool_use-Block ohne Ergebnisblock in dieser Antwort ist nicht abgeschlossen; sein Ergebnis kommt in einer späteren Antwort.
    // Sende nur die Client-tool_result-Blöcke zurück, mit denselben Tools.
    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 }
      ]
    });
    // Wurde ein web_fetch aufgeschoben, läuft er bei dieser Anfrage und sein
    // web_fetch_tool_result ist der erste Block von 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,
              // Führe dein Tool hier aus. Dieses Beispiel gibt einen festen String zurück.
              Content = "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux",
          }));
      }
  }

  if (response.StopReason?.Value() == StopReason.ToolUse && toolResults.Count > 0)
  {
      // Ein server_tool_use-Block ohne Ergebnisblock in dieser Antwort ist nicht abgeschlossen; sein Ergebnis kommt in einer späteren Antwort.
      // Sende nur die Client-tool_result-Blöcke zurück, mit denselben Tools.
      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) }
          ]
      });
      // Wurde ein web_fetch aufgeschoben, läuft er bei dieser Anfrage und sein
      // web_fetch_tool_result ist der erste Block von 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 {
  		// Führe dein Tool hier aus. Dieses Beispiel gibt einen festen String zurück.
  		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 {
  	// Ein server_tool_use-Block ohne Ergebnisblock in dieser Antwort ist nicht abgeschlossen; sein Ergebnis kommt in einer späteren Antwort.
  	// Sende nur die Client-tool_result-Blöcke zurück, mit denselben Tools.
  	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)
  	}
  	// Wurde ein web_fetch aufgeschoben, läuft er bei dieser Anfrage und sein
  	// web_fetch_tool_result ist der erste Block von 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())
                  // Führe hier dein Tool aus. Dieses Beispiel gibt einen festen String zurück.
                  .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()) {
          // Ein server_tool_use-Block ohne Ergebnisblock in dieser Antwort ist nicht abgeschlossen; sein Ergebnis kommt in einer späteren Antwort.
          // Sende nur die Client-tool_result-Blöcke zurück, mit denselben Tools.
          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());
          // Wurde ein web_fetch aufgeschoben, läuft er bei dieser Anfrage und sein
          // web_fetch_tool_result ist der erste Block von 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,
              // Führe hier dein Tool aus. Dieses Beispiel gibt einen festen String zurück.
              'content' => 'Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux'
          ];
      }
  }

  if ($response->stopReason === 'tool_use' && count($toolResults) > 0) {
      // Ein server_tool_use-Block ohne Ergebnisblock in dieser Antwort ist nicht abgeschlossen; sein Ergebnis kommt in einer späteren Antwort.
      // Sende nur die Client-tool_result-Blöcke zurück, mit denselben Tools.
      $continuation = $client->messages->create(
          maxTokens: 1024,
          messages: [
              $userMessage,
              ['role' => 'assistant', 'content' => $response->content],
              ['role' => 'user', 'content' => $toolResults],
          ],
          model: 'claude-opus-5-5',
          tools: $tools,
      );
      // Wurde ein web_fetch aufgeschoben, läuft er bei dieser Anfrage und sein
      // web_fetch_tool_result ist der erste Block von $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,
      # Führe hier dein Tool aus. Dieses Beispiel gibt einen festen String zurück.
      content: "Linux demo-host 6.8.0-52-generic x86_64 GNU/Linux"
    }
  end

  if response.stop_reason == :tool_use && !tool_results.empty?
    # Ein server_tool_use-Block ohne Ergebnisblock in dieser Antwort ist nicht abgeschlossen; sein Ergebnis kommt in einer späteren Antwort.
    # Sende nur die Client-tool_result-Blöcke zurück, mit denselben Tools.
    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 }
      ]
    )
    # Wurde ein web_fetch aufgeschoben, läuft er bei dieser Anfrage und sein
    # web_fetch_tool_result ist der erste Block von continuation.content.
    puts continuation
  else
    puts response
  end
  ```
</CodeGroup>

Dieser Code ist auch korrekt, wenn Claude die beiden Arten von Aufrufen nicht mischt. Ein Turn mit ausschließlich Client-`tool_use`-Blöcken nimmt denselben Fortsetzungspfad, und ein Turn mit ausschließlich Server-Tool-Aufrufen benötigt keine Client-`tool_result`-Blöcke von dir: Seine Ergebnisblöcke sind normalerweise bereits vorhanden, und einer, der angehalten zurückkommt, wie etwa eine [`pause_turn`-Antwort](https://platform.claude.com/docs/de/agents-and-tools/tool-use/server-tools#the-server-side-loop-and-pause-turn), wird stattdessen unverändert erneut gesendet.

## ZDR und allowed\_callers

Die Basisversionen von Web Search (`web_search_20250305`) und Web Fetch (`web_fetch_20250910`) sind für [Zero Data Retention (ZDR)](https://platform.claude.com/docs/de/manage-claude/api-and-data-retention) berechtigt.

Die Versionen `_20260209` und später mit dynamischer Filterung sind standardmäßig **nicht** ZDR-berechtigt, da die dynamische Filterung intern auf Code-Ausführung beruht.

Um ein Server-Tool der Version `_20260209` oder später mit ZDR zu verwenden, deaktiviere die dynamische Filterung, indem du `"allowed_callers": ["direct"]` am Tool setzt:

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

Dies beschränkt das Tool auf den direkten Aufruf und umgeht den internen Code-Ausführungsschritt.

`allowed_callers` steuert, wie ein Tool aufgerufen werden kann: direkt durch Claude (`"direct"`), aus einem Code-Ausführungscontainer heraus (zum Beispiel `"code_execution_20260120"`) oder beides. Die `_20260209`-Versionen der Web-Tools verwenden standardmäßig nur den Code-Execution-Caller; frühere Versionen verwenden standardmäßig `["direct"]`. Auf Modellen, die programmatischen Tool-Aufruf nicht unterstützen, erfordern diese Versionen `allowed_callers: ["direct"]`; ohne diese Angabe gibt die API einen Validierungsfehler zurück, der dazu auffordert, sie zu setzen.

<Note>
  Selbst wenn Web Fetch in einer ZDR-berechtigten Konfiguration verwendet wird, können Website-Betreiber alle an die URL übergebenen Parameter speichern, wenn Claude Inhalte von ihrer Website abruft.
</Note>

## Domain-Filterung

Server-Tools, die auf das Web zugreifen, akzeptieren die Parameter `allowed_domains` und `blocked_domains`, um zu steuern, welche Domains Claude erreichen kann. Beide sind Felder am Tool-Objekt:

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

Bei der Verwendung von Domain-Filtern:

* Domains sollten das HTTP/HTTPS-Schema nicht enthalten (verwende `example.com` statt `https://example.com`).
* Subdomains werden automatisch eingeschlossen (`example.com` deckt `docs.example.com` ab).
* Spezifische Subdomains beschränken die Ergebnisse auf genau diese Subdomain (`docs.example.com` liefert nur Ergebnisse von dieser Subdomain, nicht von `example.com` oder `api.example.com`).
* Unterpfade werden für die Websuche unterstützt und passen auf alles nach dem Pfad (`example.com/blog` passt auf `example.com/blog/post-1`).
* Web Fetch gleicht nur die Domain ab: Ein Eintrag, der einen Pfad enthält, passt nie auf eine Web-Fetch-URL.
* Du kannst entweder `allowed_domains` oder `blocked_domains` verwenden, aber nicht beide in derselben Anfrage.

**Wildcard-Unterstützung:**

* Wildcards (`*`) sind in der Domain selbst nicht erlaubt, nur im Pfad danach.
* Gültig: `example.com/*`, `example.com/*/articles`
* Ungültig: `*.example.com`, `ex*.com`

Ungültige Domain-Formate werden zum Zeitpunkt der Anfrage mit einem 400 `invalid_request_error` abgelehnt.

<Note>
  Domain-Beschränkungen auf Anfrageebene wirken zusammen mit allen Domain-Beschränkungen auf Organisationsebene, die in der Claude Console konfiguriert sind. `allowed_domains` auf Anfrageebene müssen eine Teilmenge der erlaubten Liste auf Organisationsebene sein; Einträge außerhalb davon führen dazu, dass die API einen Validierungsfehler zurückgibt. Eine erlaubte Liste auf Anfrageebene, die eine Domain enthält, die deine Organisation blockiert, wird mit einem `400`-Fehler abgelehnt, der die widersprüchlichen Einträge benennt.
</Note>

<Warning>
  Unicode-Zeichen in Domainnamen können Domain-Filter durch Homograph-Angriffe umgehen: `аmazon.com` (mit einem kyrillischen `а`) sieht identisch aus wie `amazon.com`, ist aber eine andere Domain. Verwende ausschließlich ASCII-Domainnamen in Allow- und Block-Listen und prüfe bestehende Einträge auf Nicht-ASCII-Zeichen.
</Warning>

[Claude Managed Agents](https://platform.claude.com/docs/de/managed-agents/overview) verwendet dieselben Felder `allowed_domains` und `blocked_domains` für die Einträge `web_search` und `web_fetch` des Agent-Toolsets. Bei Managed Agents enthält jede Liste höchstens 64 Einträge, für `web_fetch` aufgeführte Domains dürfen keinen Pfad enthalten, und Felder, die spezifisch für die Messages-API-Tools sind, wie `max_uses`, `citations` und `cache_control`, sind nicht verfügbar. Die vollständigen Regeln findest du unter [Regeln für Domainlisten](https://platform.claude.com/docs/de/managed-agents/tools-web-restrictions#domain-list-rules).

Einstellungen für Websuche und Web Fetch auf Organisationsebene in der Claude Console gelten nur für Messages-API-Anfragen. Sie gelten nicht für Managed-Agents-Sitzungen, die stattdessen die Listen pro Tool im Agent-Toolset verwenden. Für eine Sitzung in einer Cloud-Umgebung mit `limited`-Networking gilt auch `allowed_hosts` der Umgebung für `web_search` und `web_fetch`; siehe [Networking](https://platform.claude.com/docs/de/managed-agents/environments#networking). Die Listen pro Tool schränken diese Tools innerhalb der von `allowed_hosts` erlaubten Hosts weiter ein.

## Dynamische Filterung mit Code-Ausführung

Die Versionen `_20260209` und später von Web Search und Web Fetch verwenden intern Code-Ausführung, um dynamische Filter auf Suchergebnisse anzuwenden.

<Note>
  Du musst für diese Versionen kein `code_execution`-Tool hinzufügen: Wenn die dynamische Filterung läuft, stellt die API die Code-Ausführung für die Anfrage automatisch bereit, und beide Tools teilen sich einen einzigen Ausführungscontainer. Falls du dennoch eines einfügst, verwende `code_execution_20260120` oder später; die API lehnt ältere Code-Execution-Versionen zusammen mit diesen Web-Tool-Versionen ab.
</Note>

## Streaming von Server-Tool-Events

Server-Tool-Events werden als Teil des normalen Flusses von „server-sent events“ (vom Server gesendete Ereignisse), oder SSE, gestreamt. Ein `server_tool_use`-Block, den Claude direkt aufruft, wird wie ein Client-`tool_use`-Block gestreamt: ein `content_block_start`-Event, gefolgt von `input_json_delta`-Events. Der Ergebnisblock kommt vollständig in einem einzigen `content_block_start`-Event an, ohne Deltas.

Siehe [Streaming](https://platform.claude.com/docs/de/build-with-claude/streaming) für die vollständige Event-Referenz. Die einzelnen Tool-Seiten dokumentieren toolspezifische Event-Namen, wo sie abweichen.

## Batch-Anfragen

Alle Server-Tools unterstützen Batch-Verarbeitung. In einem Batch läuft die agentische Schleife genauso wie bei synchronen Anfragen, mit einem höheren Iterationslimit pro Turn. Wenn die Schleife dieses Limit erreicht, endet die Antwort mit `stop_reason: "pause_turn"`; du kannst sie fortsetzen, indem du eine Folgeanfrage mit dem zurückgegebenen Inhalt einreichst. Siehe [Server-Tools und die agentische Schleife](https://platform.claude.com/docs/de/build-with-claude/batch-processing#server-tools-and-the-agentic-loop) für Details.

Häufige Batch-Workloads umfassen das Anreichern eines Datensatzes mit Informationen aus dem Web, das Prüfen einer großen Menge von Dokumenten gegen aktuelle Quellen und das Ausführen von Analysecode über viele Dateien.

## Nächste Schritte

<CardGroup cols={2}>
  <Card title="Fehlerbehebung bei der Tool-Nutzung" icon="wrench" href="https://platform.claude.com/docs/de/agents-and-tools/tool-use/troubleshooting-tool-use">
    Behebe die häufigsten Tool-Use-Fehler mit Diagnosetabellen vom Symptom zur Lösung.
  </Card>

  <Card title="Web-Search-Tool" icon="magnifying-glass" href="https://platform.claude.com/docs/de/agents-and-tools/tool-use/web-search-tool">
    Durchsuche das Web und zitiere Ergebnisse.
  </Card>

  <Card title="Web-Fetch-Tool" icon="download" href="https://platform.claude.com/docs/de/agents-and-tools/tool-use/web-fetch-tool">
    Rufe Inhalte von bestimmten URLs ab und lies sie, um Claudes Kontext mit Live-Webinhalten zu erweitern.
  </Card>

  <Card title="Code-Execution-Tool" icon="terminal" href="https://platform.claude.com/docs/de/agents-and-tools/tool-use/code-execution-tool">
    Führe Python- und Bash-Code in einem Sandbox-Container aus, um Daten zu analysieren, Dateien zu generieren und Lösungen iterativ zu verbessern.
  </Card>

  <Card title="Tool-Search-Tool" icon="compass" href="https://platform.claude.com/docs/de/agents-and-tools/tool-use/tool-search-tool">
    Entdecke und lade Tools bei Bedarf.
  </Card>
</CardGroup>
