# Tool Use — Java For conceptual overview (tool definitions, tool choice, tips), see [shared/tool-use-concepts.md](../../shared/tool-use-concepts.md). ## Tool Use (Beta) The Java SDK supports beta tool use with annotated classes. Tool classes implement `Supplier` for automatic execution via `BetaToolRunner`. ### Tool Runner (automatic loop) ```java import com.anthropic.models.beta.messages.MessageCreateParams; import com.anthropic.models.beta.messages.BetaMessage; import com.anthropic.helpers.BetaToolRunner; import com.fasterxml.jackson.annotation.JsonClassDescription; import com.fasterxml.jackson.annotation.JsonPropertyDescription; import java.util.function.Supplier; @JsonClassDescription("Get the weather in a given location") static class GetWeather implements Supplier { @JsonPropertyDescription("The city and state, e.g. San Francisco, CA") public String location; @Override public String get() { return "The weather in " + location + " is sunny and 72°F"; } } BetaToolRunner toolRunner = client.beta().messages().toolRunner( MessageCreateParams.builder() .model("{{OPUS_ID}}") .maxTokens(16000L) .putAdditionalHeader("anthropic-beta", "structured-outputs-2025-11-13") .addTool(GetWeather.class) .addUserMessage("What's the weather in San Francisco?") .build()); for (BetaMessage message : toolRunner) { System.out.println(message); } ``` ### Memory Tool The Java SDK provides `BetaMemoryToolHandler` for implementing the memory tool backend. You supply a handler that manages file storage, and the `BetaToolRunner` handles memory tool calls automatically. ```java import com.anthropic.helpers.BetaMemoryToolHandler; import com.anthropic.helpers.BetaToolRunner; import com.anthropic.models.beta.messages.BetaMemoryTool20250818; import com.anthropic.models.beta.messages.BetaMessage; import com.anthropic.models.beta.messages.MessageCreateParams; import com.anthropic.models.beta.messages.ToolRunnerCreateParams; // Implement BetaMemoryToolHandler with your storage backend (e.g., filesystem) BetaMemoryToolHandler memoryHandler = new FileSystemMemoryToolHandler(sandboxRoot); MessageCreateParams createParams = MessageCreateParams.builder() .model("{{OPUS_ID}}") .maxTokens(4096L) .addTool(BetaMemoryTool20250818.builder().build()) .addUserMessage("Remember that my favorite color is blue") .build(); BetaToolRunner toolRunner = client.beta().messages().toolRunner( ToolRunnerCreateParams.builder() .betaMemoryToolHandler(memoryHandler) .initialMessageParams(createParams) .build()); for (BetaMessage message : toolRunner) { System.out.println(message); } ``` See the [shared memory tool concepts](../../shared/tool-use-concepts.md) for more details on the memory tool. ### Non-Beta Tool Declaration (manual JSON schema) `Tool.InputSchema.Properties` is a freeform `Map` wrapper — build property schemas via `putAdditionalProperty`. `type: "object"` is the default. The builder has a direct `.addTool(Tool)` overload that wraps in `ToolUnion` automatically. ```java import com.anthropic.core.JsonValue; import com.anthropic.models.messages.Tool; Tool tool = Tool.builder() .name("get_weather") .description("Get the current weather in a given location") .inputSchema(Tool.InputSchema.builder() .properties(Tool.InputSchema.Properties.builder() .putAdditionalProperty("location", JsonValue.from(Map.of("type", "string"))) .build()) .required(List.of("location")) .build()) .build(); MessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_6) .maxTokens(16000L) .addTool(tool) .addUserMessage("Weather in Paris?") .build(); ``` For manual tool loops, handle `tool_use` blocks in the response, send `tool_result` back, loop until `stop_reason` is `"end_turn"`. See [shared tool use concepts](../../shared/tool-use-concepts.md). ### Building `MessageParam` with Content Blocks (Tool Result Round-Trip) `MessageParam.Content` is an inner union class (string | list). Use the builder's `.contentOfBlockParams(List)` alias — there is NO separate `MessageParamContent` class with a static `ofBlockParams`: ```java import com.anthropic.models.messages.MessageParam; import com.anthropic.models.messages.ContentBlockParam; import com.anthropic.models.messages.ToolResultBlockParam; List results = List.of( ContentBlockParam.ofToolResult(ToolResultBlockParam.builder() .toolUseId(toolUseBlock.id()) .content(yourResultString) .build()) ); MessageParam toolResultMsg = MessageParam.builder() .role(MessageParam.Role.USER) .contentOfBlockParams(results) // builder alias for Content.ofBlockParams(...) .build(); ``` --- ## Structured Output The class-based overload auto-derives the JSON schema from your POJO and gives you a typed `.text()` return — no manual schema, no manual parsing. ```java import com.anthropic.models.messages.StructuredMessageCreateParams; record Book(String title, String author) {} record BookList(List books) {} StructuredMessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_SONNET_4_6) .maxTokens(16000L) .outputConfig(BookList.class) // returns a typed builder .addUserMessage("List 3 classic novels") .build(); client.messages().create(params).content().stream() .flatMap(cb -> cb.text().stream()) .forEach(typed -> { // typed.text() returns BookList, not String for (Book b : typed.text().books()) System.out.println(b.title()); }); ``` Supports Jackson annotations: `@JsonPropertyDescription`, `@JsonIgnore`, `@ArraySchema(minItems=...)`. Manual schema path: `OutputConfig.builder().format(JsonOutputFormat.builder().schema(...).build())`. --- ## Anthropic-Defined Tools Version-suffixed types; `name`/`type` auto-set by builder. Direct `.addTool()` overloads exist for most tool types; where one is missing (newer or less-common tools — see the advisor note below), wrap via the union type's static factory: `.addTool(BetaToolUnion.of(builder…build()))`. Web search and code execution are server-executed; bash and text editor are client-executed (you handle the `tool_use` locally — see `shared/tool-use-concepts.md`). ```java import com.anthropic.models.messages.WebSearchTool20260209; import com.anthropic.models.messages.ToolBash20250124; import com.anthropic.models.messages.ToolTextEditor20250728; import com.anthropic.models.messages.CodeExecutionTool20260120; .addTool(WebSearchTool20260209.builder() .maxUses(5L) // optional .allowedDomains(List.of("example.com")) // optional .build()) .addTool(ToolBash20250124.builder().build()) .addTool(ToolTextEditor20250728.builder().build()) .addTool(CodeExecutionTool20260120.builder().build()) ``` Also available: `WebFetchTool20260209`, `MemoryTool20250818`, `ToolSearchToolBm25_20251119`. For the advisor tool, use `BetaAdvisorTool20260301` in the beta namespace with `.addBeta("advisor-tool-2026-03-01")` (server-side; advisor model ≥ executor model). There is no direct `.addTool(BetaAdvisorTool20260301)` overload on the beta builder — wrap it via the `BetaToolUnion` static factory for the advisor type; if `javac` rejects the specific factory method name, `javap com.anthropic.models.beta.messages.BetaToolUnion | grep -i advisor` shows the exact one. ### Beta namespace (MCP, compaction) For beta-only features use `com.anthropic.models.beta.messages.*` — class names have a `Beta` prefix AND live in the beta package. The beta `MessageCreateParams.Builder` has direct `.addTool(BetaToolBash20250124)` overloads AND `.addMcpServer()`: ```java import com.anthropic.models.beta.messages.MessageCreateParams; import com.anthropic.models.beta.messages.BetaToolBash20250124; import com.anthropic.models.beta.messages.BetaCodeExecutionTool20260120; import com.anthropic.models.beta.messages.BetaRequestMcpServerUrlDefinition; MessageCreateParams params = MessageCreateParams.builder() .model(Model.CLAUDE_OPUS_4_8) .maxTokens(16000L) .addBeta("mcp-client-2025-11-20") .addTool(BetaToolBash20250124.builder().build()) .addTool(BetaCodeExecutionTool20260120.builder().build()) .addMcpServer(BetaRequestMcpServerUrlDefinition.builder() .name("my-server") .url("https://example.com/mcp") .build()) .addUserMessage("...") .build(); client.beta().messages().create(params); ``` `BetaTool*` types are NOT interchangeable with non-beta `Tool*` — pick one namespace per request. **Reading server-tool blocks in the response:** `ServerToolUseBlock` has `.id()`, `.name()` (enum), and `._input()` returning raw `JsonValue` — there is NO typed `.input()`. For code execution results, unwrap two levels: ```java for (ContentBlock block : response.content()) { block.serverToolUse().ifPresent(stu -> { System.out.println("tool: " + stu.name() + " input: " + stu._input()); }); block.codeExecutionToolResult().ifPresent(r -> { r.content().resultBlock().ifPresent(result -> { System.out.println("stdout: " + result.stdout()); System.out.println("stderr: " + result.stderr()); System.out.println("exit: " + result.returnCode()); }); }); } ``` ---