Important
Feature support in this Java SDK is currently in progress and is not at parity with the other SDKs (Python, JS/TS, and Go).
The official Java Client SDK for the MCP Toolbox.
This repository contains SDK designed to seamlessly integrate the functionalities of the MCP Toolbox into your Agentic applications. This allows you to load tools defined in Toolbox and use them as standard Java applications (Spring Boot, Quarkus, Jakarta EE) or your custom code. It empowers your AI Agents to "use tools"—querying databases, calling APIs, or managing files—without you writing the boilerplate integration code.
This simplifies the process of incorporating external functionalities (like Databases or APIs) managed by Toolbox into your Agentic applications. It is a framework-agnostic way to interact with Toolbox tools.
- Features
- Supported Environments
- Getting Started
- Installation
- Usage
- Quickstart
- Authentication
- Binding Parameter Values
- Error Handling
- Contributing
- License
- Native Java 17+ Support: Built on modern Java standards (record, CompletableFuture, HttpClient).
- Async-First Architecture: Non-blocking I/O operations perfect for high-throughput AI agent workflows.
- Type-Safe Invocation: Discover tools dynamically and invoke them with strongly typed maps.
- Zero-Config Authentication: Built-in support for Google Cloud Run OIDC (ADC) authentication.
- Minimal Footprint: Lightweight dependency graph (Jackson + Google Auth).
This SDK is designed to be versatile, supporting both modern cloud infrastructures and standard Java runtimes.
| Runtime / Framework | Supported | Notes |
|---|---|---|
| Java 17+ (LTS) | ✅ | Base requirement. Tested on OpenJDK, Corretto, and Temurin. |
| Java 21+ (LTS) | ✅ | Fully compatible, including Virtual Threads support. |
| Spring Boot 3.x | ✅ | Works as a standard library bean. |
| Quarkus | ✅ | Compatible in JVM mode. |
| GraalVM Native Image | 🚧 | Experimental. Reflection configuration may be required for Jackson. |
| Environment | Supported | Notes |
|---|---|---|
| Google Cloud Run | ✅ | First-class support. Automatic OIDC authentication via built-in Service Account. |
| Google Cloud Functions | ✅ | Fully supported (Gen 2 recommended). |
| Google Compute Engine | ✅ | Supported via Metadata Server credentials. |
| Local Development | ✅ | Supported via gcloud CLI credentials. |
| On-Premise / Hybrid | ✅ | Supported via GOOGLE_APPLICATION_CREDENTIALS environment variable. |
| AWS / Azure | ✅ | Supported via Workload Identity Federation or Service Account Keys. |
First make sure Toolbox Server is set up and is running (either locally or deployed on Cloud Run). Follow the instructions here: Toolbox Getting Started Guide
This SDK is distributed via a Google Cloud Storage Maven Repository.
Add the repository to your pom.xml:
<repositories>
<repository>
<id>gcs-repo</id>
<url>[https://storage.googleapis.com/mcp-toolbox-java-sdk/maven](https://storage.googleapis.com/mcp-toolbox-java-sdk/maven)</url>
</repository>
</repositories>
Add the dependency to your pom.xml:
<dependencies>
<dependency>
<groupId>com.google.cloud.mcp</groupId>
<artifactId>mcp-toolbox-sdk-java</artifactId>
<version>0.1.0</version>
</dependency>
</dependencies>
repositories {
maven {
url = uri("[https://storage.googleapis.com/mcp-toolbox-java-sdk/maven](https://storage.googleapis.com/mcp-toolbox-java-sdk/maven)")
}
}
dependencies {
implementation("com.google.cloud.mcp:mcp-toolbox-sdk-java:0.1.0")
}
The McpToolboxClient is your entry point. It is thread-safe and designed to be instantiated once and reused.
import com.google.cloud.mcp.McpToolboxClient;
McpToolboxClient client = McpToolboxClient.builder()
.baseUrl("[https://my-toolbox-service.a.run.app](https://my-toolbox-service.a.run.app)")
// .apiKey("...") // Optional: Overrides automatic Google Auth
.build();
You can load all available tools or a specific subset (toolset) if your server supports it. This returns a Map of tool definitions.
// Load all tools (alias for listTools)
client.loadToolset().thenAccept(tools -> {
System.out.println("Available Tools: " + tools.keySet());
tools.forEach((name, definition) -> {
System.out.println("Tool: " + name);
System.out.println("Description: " + definition.description());
});
});// Load a specific toolset (e.g., 'retail-tools')
client.loadToolset("retail-tools").thenAccept(tools -> {
System.out.println("Tools in Retail Set: " + tools.keySet());
});If you know the specific tool you want to use, you can load its definition directly. This is useful for validation or inspecting the required parameters before execution.
client.loadTool("get-toy-price").thenAccept(toolDef -> {
System.out.println("Loaded Tool: " + toolDef.description());
System.out.println("Parameters: " + toolDef.parameters());
});Invoking a tool sends a request to the MCP Server to execute the logic (SQL, API call, etc.). Arguments are passed as a Map<String, Object>.
import java.util.Map;
Map<String, Object> args = Map.of(
"description", "plush dinosaur",
"limit", 5
);
client.invokeTool("get-toy-price", args).thenAccept(result -> {
System.out.println("Result: " + result.content().get(0).text());Here is the minimal code needed to connect to a toolbox and invoke a tool.
import com.google.cloud.mcp.McpToolboxClient;
import java.util.Map;
public class App {
public static void main(String[] args) {
// 1. Create the Client
McpToolboxClient client = McpToolboxClient.builder()
.baseUrl("[https://my-toolbox-service.a.run.app](https://my-toolbox-service.a.run.app)")
.build();
// 2. Invoke a Tool
client.invokeTool("get-toy-price", Map.of("description", "plush dinosaur"))
.thenAccept(result -> {
System.out.println("Tool Output: " + result.content().get(0).text());
})
.exceptionally(ex -> {
System.err.println("Error: " + ex.getMessage());
return null;
})
.join(); // Wait for completion
}
}
For a detailed example, check the ExampleUsage.java file in teh example folder of this repo.
Note
The SDK is Async-First, using Java's CompletableFuture to bridge both patterns naturally.
- Asynchronous: Chain methods using .thenCompose(), .thenAccept(), and .exceptionally() > for non-blocking execution.
- If you prefer synchronous execution, simply call .join() on the result to block until > completion.
// Async (Non-blocking)
client.invokeTool("tool-name", args).thenAccept(result -> ...);
// Sync (Blocking)
ToolResult result = client.invokeTool("tool-name", args).join();
This section describes how to authenticate the ToolboxClient itself when connecting to a Toolbox server instance that requires authentication. This is crucial for securing your Toolbox server endpoint, especially when deployed on platforms like Cloud Run, GKE, or any environment where unauthenticated access is restricted.
You'll need this if your Toolbox server is configured to deny unauthenticated requests. For example:
- Your Toolbox server is deployed on Google Cloud Run and configured to "Require authentication" (default).
- Your server is behind an Identity-Aware Proxy (IAP).
- You have custom authentication middleware.
Without proper client authentication, attempts to connect (like listTools) will fail with 401 Unauthorized or 403 Forbidden errors.
The Java SDK handles the generation of Authorization headers (Bearer tokens) using the Google Auth Library. It follows the Application Default Credentials (ADC) strategy to find the correct credentials based on the environment where your code is running.
You need to set up ADC.
For Toolbox servers hosted on Google Cloud (e.g., Cloud Run), the SDK provides seamless OIDC authentication.
Grant the roles/run.invoker IAM role on the Cloud Run service to the principal calling the service.
- Local Dev: Grant this role to your User Account Email.
- Production: Grant this role to the Service Account attached to your application.
Option A: Local Development If running on your laptop, use the gcloud CLI to set up your user credentials.
gcloud auth application-default login
The SDK will automatically detect these credentials and generate an OIDC ID Token intended for your Toolbox URL.
Option B: Google Cloud Environments When running within Google Cloud (e.g., Compute Engine, GKE, another Cloud Run service, Cloud Functions), ADC is configured automatically. The SDK uses the environment's default service account. No extra code or configuration is required.
Option C: On-Premise / CI/CD If running outside of Google Cloud (e.g., Jenkins, AWS), create a Service Account Key (JSON) and set the environment variable:
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/key.json"
| Environment | Mechanism | Setup Required |
|---|---|---|
| Local Dev | Uses User Credentials | Run gcloud auth application-default login |
| Cloud Run | Uses Service Account | None. (Automatic) |
| CI/CD | Uses Service Account Key | Set GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json |
Note: If you provide an .apiKey() in the builder, it overrides the automatic ADC mechanism.
Tools can be configured within the Toolbox service to require authentication, ensuring only authorized users or applications can invoke them, especially when accessing sensitive data.
Always use HTTPS to connect your application with the Toolbox service, especially in production environments or whenever the communication involves sensitive data (including scenarios where tools require authentication tokens). Using plain HTTP lacks encryption and exposes your application and data to significant security risks, such as eavesdropping and tampering.
Authentication is configured per-tool within the Toolbox service itself. If a tool you intend to use is marked as requiring authentication in the service, you must configure the SDK client to provide the necessary credentials (currently Oauth2 tokens) when invoking that specific tool.
The Toolbox service enables secure tool usage through Authenticated Parameters. For detailed information on how these mechanisms work within the Toolbox service and how to configure them, please refer to Toolbox Service Documentation - Authenticated Parameters
First, ensure the target tool(s) are configured correctly in the Toolbox service to require authentication. Refer to the Toolbox Service Documentation - Authenticated Parameters for instructions.
Your application needs a way to obtain the required token for the authenticated user. The SDK requires you to provide a function capable of retrieving this token when the tool is invoked.
You must provide the SDK with an AuthTokenGetter (a function that returns a CompletableFuture<String>). This implementation depends on your application's authentication flow (e.g., retrieving a stored token, initiating an OAuth flow).
Important: The Service Name (or Auth Source) used when adding the getter (e.g., "salesforce_auth") must exactly match the name of the corresponding auth source defined in the tool's configuration.
import com.google.cloud.mcp.AuthTokenGetter;
// Define your token retrieval logic
AuthTokenGetter salesforceTokenGetter = () -> {
return CompletableFuture.supplyAsync(() -> fetchTokenFromVault());
};
//example tool: search-salesforce and related sample params
client.loadTool("search-salesforce").thenCompose(tool -> {
// Register the getter. It will be called every time 'execute' is run.
tool.addAuthTokenGetter("salesforce_auth", salesforceTokenGetter);
return tool.execute(Map.of("query", "recent leads"));
});
Tip: Your token retriever function is invoked every time an authenticated parameter requires a token for a tool call. Consider implementing caching logic within this function to avoid redundant token fetching or generation, especially for tokens with longer validity periods or if the retrieval process is resource-intensive.
Here is a complete example of how to configure and invoke an authenticated tool.
import com.google.cloud.mcp.McpToolboxClient;
import com.google.cloud.mcp.AuthTokenGetter;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
public class AuthExample {
public static void main(String[] args) {
// 1. Define your token retrieval logic
AuthTokenGetter tokenGetter = () -> {
// Logic to retrieve ID token (e.g., from local storage, OAuth flow)
return CompletableFuture.completedFuture("YOUR_ID_TOKEN");
};
// 2. Initialize the client
McpToolboxClient client = McpToolboxClient.builder()
.baseUrl("[http://127.0.0.1:5000](http://127.0.0.1:5000)")
.build();
// 3. Load tool, attach auth, and execute
client.loadTool("my-tool")
.thenCompose(tool -> {
// "my_auth" must match the name in the tool's authSources config
tool.addAuthTokenGetter("my_auth", tokenGetter);
return tool.execute(Map.of("input", "some input"));
})
.thenAccept(result -> {
System.out.println(result.content().get(0).text());
})
.join();
}
}The SDK allows you to pre-set, or "bind", values for specific tool parameters before the tool is invoked or even passed to an LLM. These bound values are fixed and will not be requested or modified by the LLM during tool use.
- Protecting sensitive information: API keys, secrets, etc.
- Enforcing consistency: Ensuring specific values for certain parameters.
- Pre-filling known data: Providing defaults or context.
The parameter names used for binding (e.g., "api_key") must exactly match the parameter names defined in the tool's configuration within the Toolbox service.
You do not need to modify the tool's configuration in the Toolbox service to bind parameter values using the SDK.
Bind a fixed value to a tool object.
client.loadTool("get-toy-price").thenCompose(tool -> {
// Bind 'currency' to 'USD' permanently for this tool instance
tool.bindParam("currency", "USD");
// Now invoke without specifying currency
return tool.execute(Map.of("description", "lego set"));
});
Instead of a static value, you can bind a parameter to a synchronous or asynchronous function (Supplier). This function will be called each time the tool is invoked to dynamically determine the parameter's value at runtime.
client.loadTool("check-order-status").thenCompose(tool -> {
// Bind 'user_id' to a function that fetches the current user from context
tool.bindParam("user_id", () -> SecurityContext.getCurrentUser().getId());
// Invoke: The SDK will call the supplier to fill 'user_id'
return tool.execute(Map.of("order_id", "12345"));
});
You don't need to modify tool configurations to bind parameter values.
The SDK uses Java's CompletableFuture API. Errors (Network issues, 4xx/5xx responses) are propagated as exceptions wrapped in CompletionException.
client.invokeTool("invalid-tool", Map.of())
.handle((result, ex) -> {
if (ex != null) {
System.err.println("Invocation Failed: " + ex.getCause().getMessage());
return null; // Handle error
}
return result; // Success path
});
We welcome contributions! Please see CONTRIBUTING.md for details on how to submit pull requests, report bugs, or request features.
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
