Sections in this lesson

Spring AI Tool Calling

Expose narrow Java tools and enforce resource authorization inside the application.

Reviewed: · Content owner: Interview Preparator

What you will learn

  • Register annotated methods as tool callbacks.
  • Use trusted identity instead of model-supplied tenant arguments.
  • Verify both the callback and the model/tool round trip.

Before you start

The flow

  1. 1.Register tools
  2. 2.Model requests
  3. 3.Validate ID
  4. 4.Authorize resource
  5. 5.Observe result

A narrow Java capability

StudyTools exposes a read-only planStatus method with @Tool. The constructor receives the trusted tenant and resource ownership map; neither is a model argument. Arguments are validated before the ownership check. An unknown or foreign resource is rejected.

Instantiate request-scoped tool capabilities or supply trusted context explicitly. Do not put the latest request's tenant in a mutable shared singleton field. Tools must enforce authorization even when called outside an HTTP controller.

Understand the Spring AI 2.0 loop

Pass the tool object through ChatClient.tools. In Spring AI 2.0, ToolCallingAdvisor handles the client advisor-chain loop. A synthetic ChatModel used in a test must expose tool-capable options; a text-only fake may return a tool request without executing it.

The tests first invoke a real ToolCallback to verify validation and access denial, then simulate one tool request and one observation to verify the round trip. This proves wiring, not that a live model always chooses the right tool.

Reads and writes have different risks

Read-only tools can still leak private data. Side-effecting tools additionally need confirmation rules, idempotency keys, deadlines and audit records. Tool schemas describe an input shape; they are not permission grants. Limit exposed capabilities rather than giving an agent arbitrary SQL or shell access.

Try it

StudyTools.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.interviewpreparator.lab;
import java.util.Map;
import org.springframework.ai.tool.annotation.Tool;
public final class StudyTools {
private final String tenant;
private final Map<String, String> owners;
public StudyTools(String tenant, Map<String, String> owners) {
this.tenant = tenant;
this.owners = Map.copyOf(owners);
}
@Tool(description = "Read the status of a study plan by its public plan ID")
public String planStatus(String planId) {
if (planId == null || !planId.matches("PLAN-[0-9]+")) throw new IllegalArgumentException("Invalid plan ID");
if (!tenant.equals(owners.get(planId))) throw new SecurityException("Forbidden");
return "IN_PROGRESS";
}
}

examples/spring-ai-lab/src/main/java/com/interviewpreparator/lab/StudyTools.java · mvn -f examples/spring-ai-lab/pom.xml test. Java 21+, Spring Boot 4.0.5, Spring AI 2.0.2 where applicable. The demo uses synthetic models; live inference quality is a separate check.

Interview questions

Does @Tool enforce ownership?

No. It exposes metadata and invocation; application code must check identity and the resource.

Why test a callback directly?

To prove validation and denial independent of probabilistic model selection.

What changes for write tools?

Add explicit side-effect policies, idempotency, time limits and an audit trail before execution.

Practice

Add a write-like completePlan operation with confirmation and idempotency, then prove denied calls have no effect.

Check your solution

  • Malformed IDs fail.
  • Foreign resources fail even with valid syntax.
  • The tool round trip returns an observation.

Official references

Continue learning

Category sequence

Spring AI

Lesson 4 / 7

Was this lesson useful?

Change notes: Phase 2: bilingual lesson with versioned executable reference.