From 25c39b9533d44d0dff1f16a172e3a108fa5ef6f9 Mon Sep 17 00:00:00 2001 From: Anmol Shukla Date: Mon, 9 Feb 2026 14:27:53 +0530 Subject: [PATCH] docs: migration of Go Sdk docs (#2292) Related PRs : [Core] https://github.com/googleapis/genai-toolbox/pull/2330 [tbADK] https://github.com/googleapis/genai-toolbox/pull/2393 [tbGenkit] https://github.com/googleapis/genai-toolbox/pull/2394 --------- Co-authored-by: Anubhav Dhawan Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- docs/en/sdks/go-sdk/_index.md | 89 +++ docs/en/sdks/go-sdk/core/_index.md | 932 +++++++++++++++++++++++++ docs/en/sdks/go-sdk/tbadk/_index.md | 683 ++++++++++++++++++ docs/en/sdks/go-sdk/tbgenkit/_index.md | 121 ++++ 4 files changed, 1825 insertions(+) create mode 100644 docs/en/sdks/go-sdk/core/_index.md create mode 100644 docs/en/sdks/go-sdk/tbadk/_index.md create mode 100644 docs/en/sdks/go-sdk/tbgenkit/_index.md diff --git a/docs/en/sdks/go-sdk/_index.md b/docs/en/sdks/go-sdk/_index.md index 91ece12cb7..24d4f93810 100644 --- a/docs/en/sdks/go-sdk/_index.md +++ b/docs/en/sdks/go-sdk/_index.md @@ -7,6 +7,41 @@ description: > --- +## Overview + +![MCP Toolbox +Logo](https://raw.githubusercontent.com/googleapis/genai-toolbox/main/logo.png) + +# MCP Toolbox SDKs for Go + +[![License: Apache +2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![Docs](https://img.shields.io/badge/Docs-MCP_Toolbox-blue)](https://googleapis.github.io/genai-toolbox/) +[![Discord](https://img.shields.io/badge/Discord-%235865F2.svg?style=flat&logo=discord&logoColor=white)](https://discord.gg/Dmm69peqjh) +[![Medium](https://img.shields.io/badge/Medium-12100E?style=flat&logo=medium&logoColor=white)](https://medium.com/@mcp_toolbox) +[![Go Report Card](https://goreportcard.com/badge/github.com/googleapis/mcp-toolbox-sdk-go)](https://goreportcard.com/report/github.com/googleapis/mcp-toolbox-sdk-go) +[![Module Version](https://img.shields.io/github/v/release/googleapis/mcp-toolbox-sdk-go)](https://img.shields.io/github/v/release/googleapis/mcp-toolbox-sdk-go) +[![Go Version](https://img.shields.io/github/go-mod/go-version/googleapis/mcp-toolbox-sdk-go)](https://img.shields.io/github/go-mod/go-version/googleapis/mcp-toolbox-sdk-go) + +This repository contains the Go SDK designed to seamlessly integrate the +functionalities of the [MCP +Toolbox](https://github.com/googleapis/genai-toolbox) into your Agentic +applications. The SDK allow you to load tools defined in Toolbox and use them +as standard Go tools within popular orchestration frameworks +or your custom code. + +This simplifies the process of incorporating external functionalities (like +Databases or APIs) managed by Toolbox into your GenAI applications. + + + +- [Overview](#overview) +- [Which Package Should I Use?](#which-package-should-i-use) +- [Available Packages](#available-packages) +- [Getting Started](#getting-started) + + + ## Overview The MCP Toolbox service provides a centralized way to manage and expose tools @@ -22,4 +57,58 @@ The Go SDK act as clients for that service. They handle the communication needed By using the SDK, you can easily leverage your Toolbox-managed tools directly within your Go applications or AI orchestration frameworks. +## Which Package Should I Use? + +Choosing the right package depends on how you are building your application: + +- [**`core`**](core/): + This is a framework-agnostic way to connect tools to popular frameworks + like Google GenAI, LangChain, etc. + +- [**`tbadk`**](tbadk/): + This package provides a way to connect tools to ADK Go. + +- [**`tbgenkit`**](tbgenkit/): + This package provides functionality to convert the Tool fetched using the core package + into a Genkit Go compatible tool. + +## Available Packages + +This repository hosts the following Go packages. See the package-specific +README for detailed installation and usage instructions: + +| Package | Target Use Case | Integration | Path | Details (README) | +| :------ | :----------| :---------- | :---------------------- | :---------- | +| [`core`](core/) | Framework-agnostic / Custom applications | Use directly / Custom | `core/` | 📄 [View README](https://github.com/googleapis/mcp-toolbox-sdk-go/blob/main/core/README.md) | +| [`tbadk`](tbadk/) | ADK Go | Use directly | `tbadk/` | 📄 [View README](https://github.com/googleapis/mcp-toolbox-sdk-go/blob/main/tbadk/README.md) | +| [`tbgenkit`](tbgenkit/) | Genkit Go | Along with core | `tbgenkit/` | 📄 [View README](https://github.com/googleapis/mcp-toolbox-sdk-go/blob/main/tbgenkit/README.md) | + +## Getting Started + +To get started using Toolbox tools with an application, follow these general steps: + +1. **Set up and Run the Toolbox Service:** + + Before using the SDKs, you need the MCP Toolbox server running. Follow + the instructions here: [**Toolbox Getting Started + Guide**](https://github.com/googleapis/genai-toolbox?tab=readme-ov-file#getting-started) + +2. **Install the Appropriate SDK:** + + Choose the package based on your needs (see "[Which Package Should I Use?](#which-package-should-i-use)" above) + Use this command to install the SDK module + + ```bash + # For the core, framework-agnostic SDK + go get github.com/googleapis/mcp-toolbox-sdk-go + ``` + +3. **Use the SDK:** + + Consult the `README` for your chosen package (linked in the "[Available + Packages](#available-packages)" section above) for detailed instructions on + how to connect the client, load tool definitions, invoke tools, configure + authentication/binding, and integrate them into your application or + framework. + [Github](https://github.com/googleapis/mcp-toolbox-sdk-go) \ No newline at end of file diff --git a/docs/en/sdks/go-sdk/core/_index.md b/docs/en/sdks/go-sdk/core/_index.md new file mode 100644 index 0000000000..f273a57f27 --- /dev/null +++ b/docs/en/sdks/go-sdk/core/_index.md @@ -0,0 +1,932 @@ +--- +title: "Core Package" +linkTitle: "Core" +type: docs +weight: 1 +--- + +![MCP Toolbox Logo](https://raw.githubusercontent.com/googleapis/genai-toolbox/main/logo.png) + +# MCP Toolbox For Go Core SDK + +[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +This SDK allows you to seamlessly integrate the functionalities of +[MCP Toolbox](https://github.com/googleapis/genai-toolbox) allowing you to load and +use tools defined in the service as standard Go structs within your GenAI +applications. + +This simplifies integrating external functionalities (like APIs, databases, or +custom logic) managed by the Toolbox into your workflows, especially those +involving Large Language Models (LLMs). + +## Installation + +```bash +go get github.com/googleapis/mcp-toolbox-sdk-go +``` +This SDK is supported on Go version 1.24.4 and higher. + +{{< notice note >}} +While the SDK itself is synchronous, you can execute its functions within goroutines to achieve asynchronous behavior. +{{< /notice >}} + + +## Quickstart + +Here's a minimal example to get you started. Ensure your Toolbox service is +running and accessible. + +```go +package main + +import ( + "context" + "fmt" + "github.com/googleapis/mcp-toolbox-sdk-go/core" +) + +func quickstart() string { + ctx := context.Background() + inputs := map[string]any{"location": "London"} + client, err := core.NewToolboxClient("http://localhost:5000") + if err != nil { + return fmt.Sprintln("Could not start Toolbox Client", err) + } + tool, err := client.LoadTool("get_weather", ctx) + if err != nil { + return fmt.Sprintln("Could not load Toolbox Tool", err) + } + result, err := tool.Invoke(ctx, inputs) + if err != nil { + return fmt.Sprintln("Could not invoke tool", err) + } + return fmt.Sprintln(result) +} + +func main() { + fmt.Println(quickstart()) +} +``` + +## Usage + +Import and initialize a Toolbox client, pointing it to the URL of your running +Toolbox service. + +```go +import "github.com/googleapis/mcp-toolbox-sdk-go/core" + +client, err := core.NewToolboxClient("http://localhost:5000") +``` + +All interactions for loading and invoking tools happen through this client. + +{{< notice note >}} +For advanced use cases, you can provide an external custom `http.Client` during initialization (e.g., `core.NewToolboxClient(URL, core.WithHTTPClient(myClient)`). +If you provide your own session, you are responsible for managing its lifecycle; `ToolboxClient` *will not* close it. +{{< /notice >}} + +{{< notice info >}} +Closing the `ToolboxClient` also closes the underlying network session shared by all tools loaded from that client. As a result, any tool instances you have loaded will cease to function and will raise an error if you attempt to invoke them after the client is closed. +{{< /notice >}} + +## Transport Protocols + +The SDK supports multiple transport protocols for communicating with the Toolbox server. By default, the client uses the latest supported version of the **Model Context Protocol (MCP)**. + +You can explicitly select a protocol using the `core.WithProtocol` option during client initialization. This is useful if you need to use the native Toolbox HTTP protocol or pin the client to a specific legacy version of MCP. + +{{< notice note >}} +* **Native Toolbox Transport**: This uses the service's native **REST over HTTP** API. +* **MCP Transports**: These options use the **Model Context Protocol over HTTP**. +{{< /notice >}} + + +### Supported Protocols + +| Constant | Description | +| :--- | :--- | +| `core.MCP` | **(Default)** Alias for the latest supported MCP version (currently `v2025-06-18`). | +| `core.Toolbox` | The native Toolbox HTTP protocol. | +| `core.MCPv20250618` | MCP Protocol version 2025-06-18. | +| `core.MCPv20250326` | MCP Protocol version 2025-03-26. | +| `core.MCPv20241105` | MCP Protocol version 2024-11-05. | + +### Example + +If you wish to use the native Toolbox protocol: + +```go +import "github.com/googleapis/mcp-toolbox-sdk-go/core" + +client, err := core.NewToolboxClient( + "http://localhost:5000", + core.WithProtocol(core.Toolbox), +) +``` +If you want to pin the MCP Version 2025-03-26: + +```go +import "github.com/googleapis/mcp-toolbox-sdk-go/core" + +client, err := core.NewToolboxClient( + "http://localhost:5000", + core.WithProtocol(core.MCPv20250326), +) +``` + +## Loading Tools + +You can load tools individually or in groups (toolsets) as defined in your +Toolbox service configuration. Loading a toolset is convenient when working with +multiple related functions, while loading a single tool offers more granular +control. + +### Load a toolset + +A toolset is a collection of related tools. You can load all tools in a toolset +or a specific one: + +```go +// Load default toolset by providing an empty string as the name +tools, err := client.LoadToolset("", ctx) + +// Load a specific toolset +tools, err := client.LoadToolset("my-toolset", ctx) +``` + + +### Load a single tool + +Loads a specific tool by its unique name. This provides fine-grained control. + +```go +tool, err = client.LoadTool("my-tool", ctx) +``` + +## Invoking Tools + +Once loaded, tools behave like Go structs. You invoke them using `Invoke` method +by passing arguments corresponding to the parameters defined in the tool's +configuration within the Toolbox service. + +```go +tool, err = client.LoadTool("my-tool", ctx) +inputs := map[string]any{"location": "London"} +result, err := tool.Invoke(ctx, inputs) +``` + +{{< notice tip >}} +For a more comprehensive guide on setting up the Toolbox service itself, which you'll need running to use this SDK, please refer to the [Toolbox Quickstart Guide](https://googleapis.github.io/genai-toolbox/getting-started/local_quickstart). +{{< /notice >}} + +## Client to Server Authentication + +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. + +This client-to-server authentication ensures that the Toolbox server can verify +the identity of the client making the request before any tool is loaded or +called. It is different from [Authenticating Tools](#authenticating-tools), +which deals with providing credentials for specific tools within an already +connected Toolbox session. + +### When is Client-to-Server Authentication Needed? + +You'll need this type of authentication if your Toolbox server is configured to +deny unauthenticated requests. For example: + +- Your Toolbox server is deployed on Cloud Run and configured to "Require authentication." +- Your server is behind an Identity-Aware Proxy (IAP) or a similar + authentication layer. +- You have custom authentication middleware on your self-hosted Toolbox server. + +Without proper client authentication in these scenarios, attempts to connect or +make calls (like `LoadTool`) will likely fail with `Unauthorized` errors. + +### How it works + +The `ToolboxClient` allows you to specify TokenSources that dynamically generate HTTP headers for +every request sent to the Toolbox server. The most common use case is to add an +Authorization header with a bearer token (e.g., a Google ID token). + +These header-generating functions are called just before each request, ensuring +that fresh credentials or header values can be used. + +### Configuration + +You can configure these dynamic headers as seen below: + + +```go +import "github.com/googleapis/mcp-toolbox-sdk-go/core" + +tokenProvider := func() string { + return "header3_value" +} + +staticTokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: "header2_value"}) +dynamicTokenSource := core.NewCustomTokenSource(tokenProvider) + +client, err := core.NewToolboxClient( + "toolbox-url", + core.WithClientHeaderString("header1", "header1_value"), + core.WithClientHeaderTokenSource("header2", staticTokenSource), + core.WithClientHeaderTokenSource("header3", dynamicTokenSource), +) +``` + +### Authenticating with Google Cloud Servers + +For Toolbox servers hosted on Google Cloud (e.g., Cloud Run) and requiring +`Google ID token` authentication, the helper module +[auth_methods](https://github.com/googleapis/mcp-toolbox-sdk-go/blob/main/core/auth.go) provides utility functions. + +### Step by Step Guide for Cloud Run + +1. **Configure Permissions**: [Grant](https://cloud.google.com/run/docs/securing/managing-access#service-add-principals) the `roles/run.invoker` IAM role on the Cloud + Run service to the principal. This could be your `user account email` or a + `service account`. +2. **Configure Credentials** + - Local Development: Set up + [ADC](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment). + - Google Cloud Environments: When running within Google Cloud (e.g., Compute + Engine, GKE, another Cloud Run service, Cloud Functions), ADC is typically + configured automatically, using the environment's default service account. +3. **Connect to the Toolbox Server** + ```go + import "github.com/googleapis/mcp-toolbox-sdk-go/core" + import "context" + + ctx := context.Background() + + token, err := core.GetGoogleIDToken(ctx, URL) + + client, err := core.NewToolboxClient( + URL, + core.WithClientHeaderString("Authorization", token), + ) + + // Now, you can use the client as usual. + ``` + +## Authenticating Tools + +{{< notice warning >}} +**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 requireauthentication tokens). Using plain HTTP lacks encryption and exposes your application and data to significant security risks, such as eavesdropping and tampering. +{{< /notice >}} + +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. + +### When is Authentication Needed? + +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. + +### Supported Authentication Mechanisms + +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](https://googleapis.github.io/genai-toolbox/resources/tools/#authenticated-parameters). + +### Step 1: Configure Tools in Toolbox Service + +First, ensure the target tool(s) are configured correctly in the Toolbox service +to require authentication. Refer to the [Toolbox Service Documentation - +Authenticated +Parameters](https://googleapis.github.io/genai-toolbox/resources/tools/#authenticated-parameters) +for instructions. + +### Step 2: Configure SDK Client + +Your application needs a way to obtain the required Oauth2 token for the +authenticated user. The SDK requires you to provide a function capable of +retrieving this token *when the tool is invoked*. + +#### Provide an ID Token Retriever Function + +You must provide the SDK with a function that returns the +necessary token when called. The implementation depends on your application's +authentication flow (e.g., retrieving a stored token, initiating an OAuth flow). + +{{< notice info >}} +The name used when registering the getter function with the SDK (e.g., `"my_api_token"`) must exactly match the `name` of the corresponding `authServices` defined in the tool's configuration within the Toolbox service. +{{< /notice >}} + +```go +func getAuthToken() string { + // ... Logic to retrieve ID token (e.g., from local storage, OAuth flow) + // This example just returns a placeholder. Replace with your actual token retrieval. + return "YOUR_ID_TOKEN" // Placeholder +} +``` + +{{< notice 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. +{{< /notice >}} + +#### Option A: Add Default Authentication to a Client + +You can add default tool level authentication to a client. +Every tool / toolset loaded by the client will contain the auth token. + +```go + +ctx := context.Background() + +client, err := core.NewToolboxClient("http://127.0.0.1:5000", + core.WithDefaultToolOptions( + core.WithAuthTokenString("my-auth-1", "auth-value"), + ), +) + +AuthTool, err := client.LoadTool("my-tool", ctx) +``` + +#### Option B: Add Authentication to a Loaded Tool + +You can add the token retriever function to a tool object *after* it has been +loaded. This modifies the specific tool instance. + +```go + +ctx := context.Background() + +client, err := core.NewToolboxClient("http://127.0.0.1:5000") + +tool, err := client.LoadTool("my-tool", ctx) + +AuthTool, err := tool.ToolFrom( + core.WithAuthTokenSource("my-auth", headerTokenSource), + core.WithAuthTokenString("my-auth-1", "value"), + ) +``` + +#### Option C: Add Authentication While Loading Tools + +You can provide the token retriever(s) directly during the `LoadTool` or +`LoadToolset` calls. This applies the authentication configuration only to the +tools loaded in that specific call, without modifying the original tool objects +if they were loaded previously. + +```go +AuthTool, err := client.LoadTool("my-tool", ctx, core.WithAuthTokenString("my-auth-1", "value")) + +// or + +AuthTools, err := client.LoadToolset( + "my-toolset", + ctx, + core.WithAuthTokenString("my-auth-1", "value"), +) +``` + +{{< notice note >}} +Adding auth tokens during loading only affect the tools loaded within that call. +{{< /notice >}} + +### Complete Authentication Example + +```go +import "github.com/googleapis/mcp-toolbox-sdk-go/core" +import "fmt" + +func getAuthToken() string { + // ... Logic to retrieve ID token (e.g., from local storage, OAuth flow) + // This example just returns a placeholder. Replace with your actual token retrieval. + return "YOUR_ID_TOKEN" // Placeholder +} + +func main() { + ctx := context.Background() + inputs := map[string]any{"input": "some input"} + + dynamicTokenSource := core.NewCustomTokenSource(getAuthToken) + + client, err := core.NewToolboxClient("http://127.0.0.1:5000") + tool, err := client.LoadTool("my-tool", ctx) + AuthTool, err := tool.ToolFrom(core.WithAuthTokenSource("my_auth", dynamicTokenSource)) + + result, err := AuthTool.Invoke(ctx, inputs) + + fmt.Println(result) +} +``` + +{{< notice note >}} +An auth token getter for a specific name (e.g., "GOOGLE_ID") will replace any client header with the same name followed by "_token" (e.g., "GOOGLE_ID_token"). +{{< /notice >}} + +## Binding Parameter Values + +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. + +### Why Bind Parameters? + +- **Protecting sensitive information:** API keys, secrets, etc. +- **Enforcing consistency:** Ensuring specific values for certain parameters. +- **Pre-filling known data:** Providing defaults or context. + +{{< notice info >}} +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. +{{< /notice >}} + +{{< notice note >}} +You do not need to modify the tool's configuration in the Toolbox service to bind parameter values using the SDK. +{{< /notice >}} + +#### Option A: Add Default Bound Parameters to a Client + +You can add default tool level bound parameters to a client. Every tool / toolset +loaded by the client will have the bound parameter. + +```go + +ctx := context.Background() + +client, err := core.NewToolboxClient("http://127.0.0.1:5000", + core.WithDefaultToolOptions( + core.WithBindParamString("param1", "value"), + ), +) + +boundTool, err := client.LoadTool("my-tool", ctx) +``` + +### Option B: Binding Parameters to a Loaded Tool + +Bind values to a tool object *after* it has been loaded. This modifies the +specific tool instance. + +```go +client, err := core.NewToolboxClient("http://127.0.0.1:5000") + +tool, err := client.LoadTool("my-tool", ctx) + +boundTool, err := tool.ToolFrom( + core.WithBindParamString("param1", "value"), + core.WithBindParamString("param2", "value") + ) +``` + +### Option C: Binding Parameters While Loading Tools + +Specify bound parameters directly when loading tools. This applies the binding +only to the tools loaded in that specific call. + +```go +boundTool, err := client.LoadTool("my-tool", ctx, core.WithBindParamString("param", "value")) + +// OR + +boundTool, err := client.LoadToolset("", ctx, core.WithBindParamString("param", "value")) +``` + +{{< notice note >}} Bound values during loading only affect the tools loaded in that call. {{< /notice >}} + +### Binding Dynamic Values + +Instead of a static value, you can bind a parameter to a synchronous or +asynchronous function. This function will be called *each time* the tool is +invoked to dynamically determine the parameter's value at runtime. +Functions with the return type (data_type, error) can be provided. + +```go +getDynamicValue := func() (string, error) { return "req-123", nil } + +dynamicBoundTool, err := tool.ToolFrom(core.WithBindParamStringFunc("param", getDynamicValue)) +``` + +{{< notice info >}} You don't need to modify tool configurations to bind parameter values. {{< /notice >}} + + +# Using with Orchestration Frameworks + +To see how the MCP Toolbox Go SDK works with orchestration frameworks, check out these end-to-end examples given below. + +
+Google GenAI + +```go +// This sample demonstrates integration with the standard Google GenAI framework. +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + + "github.com/googleapis/mcp-toolbox-sdk-go/core" + "google.golang.org/genai" +) + +// ConvertToGenaiTool translates a ToolboxTool into the genai.FunctionDeclaration format. +func ConvertToGenaiTool(toolboxTool *core.ToolboxTool) *genai.Tool { + + inputschema, err := toolboxTool.InputSchema() + if err != nil { + return &genai.Tool{} + } + + var schema *genai.Schema + _ = json.Unmarshal(inputschema, &schema) + // First, create the function declaration. + funcDeclaration := &genai.FunctionDeclaration{ + Name: toolboxTool.Name(), + Description: toolboxTool.Description(), + Parameters: schema, + } + + // Then, wrap the function declaration in a genai.Tool struct. + return &genai.Tool{ + FunctionDeclarations: []*genai.FunctionDeclaration{funcDeclaration}, + } +} + +// printResponse extracts and prints the relevant parts of the model's response. +func printResponse(resp *genai.GenerateContentResponse) { + for _, cand := range resp.Candidates { + if cand.Content != nil { + for _, part := range cand.Content.Parts { + fmt.Println(part.Text) + } + } + } +} + +func main() { + // Setup + ctx := context.Background() + apiKey := os.Getenv("GOOGLE_API_KEY") + toolboxURL := "http://localhost:5000" + + // Initialize the Google GenAI client using the explicit ClientConfig. + client, err := genai.NewClient(ctx, &genai.ClientConfig{ + APIKey: apiKey, + }) + if err != nil { + log.Fatalf("Failed to create Google GenAI client: %v", err) + } + + // Initialize the MCP Toolbox client. + toolboxClient, err := core.NewToolboxClient(toolboxURL) + if err != nil { + log.Fatalf("Failed to create Toolbox client: %v", err) + } + + // Load the tools using the MCP Toolbox SDK. + tools, err := toolboxClient.LoadToolset("my-toolset", ctx) + if err != nil { + log.Fatalf("Failed to load tools: %v\nMake sure your Toolbox server is running and the tool is configured.", err) + } + + genAITools := make([]*genai.Tool, len(tools)) + toolsMap := make(map[string]*core.ToolboxTool, len(tools)) + + for i, tool := range tools { + // Convert the tools into usable format + genAITools[i] = ConvertToGenaiTool(tool) + // Add tool to a map for lookup later + toolsMap[tool.Name()] = tool + } + + // Set up the generative model with the available tool. + modelName := "gemini-2.0-flash" + + query := "Find hotels in Basel with Basel in it's name and share the names with me" + + // Create the initial content prompt for the model. + contents := []*genai.Content{ + genai.NewContentFromText(query, genai.RoleUser), + } + config := &genai.GenerateContentConfig{ + Tools: genAITools, + ToolConfig: &genai.ToolConfig{ + FunctionCallingConfig: &genai.FunctionCallingConfig{ + Mode: genai.FunctionCallingConfigModeAny, + }, + }, + } + genContentResp, _ := client.Models.GenerateContent(ctx, modelName, contents, config) + + printResponse(genContentResp) + + functionCalls := genContentResp.FunctionCalls() + if len(functionCalls) == 0 { + log.Println("No function call returned by the AI. The model likely answered directly.") + return + } + + // Process the first function call (the example assumes one for simplicity). + fc := functionCalls[0] + log.Printf("--- Gemini requested function call: %s ---\n", fc.Name) + log.Printf("--- Arguments: %+v ---\n", fc.Args) + + var toolResultString string + + if fc.Name == "search-hotels-by-name" { + tool := toolsMap["search-hotels-by-name"] + toolResult, err := tool.Invoke(ctx, fc.Args) + toolResultString = fmt.Sprintf("%v", toolResult) + if err != nil { + log.Fatalf("Failed to execute tool '%s': %v", fc.Name, err) + } + + } else { + log.Println("LLM did not request our tool") + } + resultContents := []*genai.Content{ + genai.NewContentFromText("The tool returned this result, share it with the user based of their previous querys"+toolResultString, genai.RoleUser), + } + finalResponse, err := client.Models.GenerateContent(ctx, modelName, resultContents, &genai.GenerateContentConfig{}) + if err != nil { + log.Fatalf("Error calling GenerateContent (with function result): %v", err) + } + log.Println("=== Final Response from Model (after processing function result) ===") + printResponse(finalResponse) + +} +``` + +
+ +
+LangChain + +```go +// This sample demonstrates how to use Toolbox tools as function definitions in LangChain Go. +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + + "github.com/googleapis/mcp-toolbox-sdk-go/core" + "github.com/tmc/langchaingo/llms" + "github.com/tmc/langchaingo/llms/googleai" +) + +// ConvertToLangchainTool converts a generic core.ToolboxTool into a LangChainGo llms.Tool. +func ConvertToLangchainTool(toolboxTool *core.ToolboxTool) llms.Tool { + + // Fetch the tool's input schema + inputschema, err := toolboxTool.InputSchema() + if err != nil { + return llms.Tool{} + } + + var paramsSchema map[string]any + _ = json.Unmarshal(inputschema, ¶msSchema) + + // Convert into LangChain's llms.Tool + return llms.Tool{ + Type: "function", + Function: &llms.FunctionDefinition{ + Name: toolboxTool.Name(), + Description: toolboxTool.Description(), + Parameters: paramsSchema, + }, + } +} + +func main() { + genaiKey := os.Getenv("GOOGLE_API_KEY") + toolboxURL := "http://localhost:5000" + ctx := context.Background() + + // Initialize the Google AI client (LLM). + llm, err := googleai.New(ctx, googleai.WithAPIKey(genaiKey), googleai.WithDefaultModel("gemini-1.5-flash")) + if err != nil { + log.Fatalf("Failed to create Google AI client: %v", err) + } + + // Initialize the MCP Toolbox client. + toolboxClient, err := core.NewToolboxClient(toolboxURL) + if err != nil { + log.Fatalf("Failed to create Toolbox client: %v", err) + } + + // Load the tools using the MCP Toolbox SDK. + tools, err := toolboxClient.LoadToolset("my-toolset", ctx) + if err != nil { + log.Fatalf("Failed to load tools: %v\nMake sure your Toolbox server is running and the tool is configured.", err) + } + + toolsMap := make(map[string]*core.ToolboxTool, len(tools)) + + langchainTools := make([]llms.Tool, len(tools)) + for i, tool := range tools { + // Convert the loaded ToolboxTools into the format LangChainGo requires. + langchainTools[i] = ConvertToLangchainTool(tool) + // Add tool to a map for lookup later + toolsMap[tool.Name()] = tool + } + + // Start the conversation history. + messageHistory := []llms.MessageContent{ + llms.TextParts(llms.ChatMessageTypeHuman, "Find hotels in Basel with Basel in it's name."), + } + + // Make the first call to the LLM, making it aware of the tool. + resp, err := llm.GenerateContent(ctx, messageHistory, llms.WithTools(langchainTools)) + if err != nil { + log.Fatalf("LLM call failed: %v", err) + } + + // Add the model's response (which should be a tool call) to the history. + respChoice := resp.Choices[0] + assistantResponse := llms.TextParts(llms.ChatMessageTypeAI, respChoice.Content) + for _, tc := range respChoice.ToolCalls { + assistantResponse.Parts = append(assistantResponse.Parts, tc) + } + messageHistory = append(messageHistory, assistantResponse) + + // Process each tool call requested by the model. + for _, tc := range respChoice.ToolCalls { + toolName := tc.FunctionCall.Name + + switch tc.FunctionCall.Name { + case "search-hotels-by-name": + var args map[string]any + if err := json.Unmarshal([]byte(tc.FunctionCall.Arguments), &args); err != nil { + log.Fatalf("Failed to unmarshal arguments for tool '%s': %v", toolName, err) + } + tool := toolsMap["search-hotels-by-name"] + toolResult, err := tool.Invoke(ctx, args) + if err != nil { + log.Fatalf("Failed to execute tool '%s': %v", toolName, err) + } + + // Create the tool call response message and add it to the history. + toolResponse := llms.MessageContent{ + Role: llms.ChatMessageTypeTool, + Parts: []llms.ContentPart{ + llms.ToolCallResponse{ + Name: toolName, + Content: fmt.Sprintf("%v", toolResult), + }, + }, + } + messageHistory = append(messageHistory, toolResponse) + default: + log.Fatalf("got unexpected function call: %v", tc.FunctionCall.Name) + } + } + + // Final LLM Call for Natural Language Response + log.Println("Sending tool response back to LLM for a final answer...") + + // Call the LLM again with the updated history, which now includes the tool's result. + finalResp, err := llm.GenerateContent(ctx, messageHistory) + if err != nil { + log.Fatalf("Final LLM call failed: %v", err) + } + + // Display the Result + fmt.Println("\n======================================") + fmt.Println("Final Response from LLM:") + fmt.Println(finalResp.Choices[0].Content) + fmt.Println("======================================") +} + +``` +
+ +
+OpenAI + +```go +// This sample demonstrates integration with the OpenAI Go client. +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + + "github.com/googleapis/mcp-toolbox-sdk-go/core" + openai "github.com/openai/openai-go" +) + +// ConvertToOpenAITool converts a ToolboxTool into the go-openai library's Tool format. +func ConvertToOpenAITool(toolboxTool *core.ToolboxTool) openai.ChatCompletionToolParam { + // Get the input schema + jsonSchemaBytes, err := toolboxTool.InputSchema() + if err != nil { + return openai.ChatCompletionToolParam{} + } + + // Unmarshal the JSON bytes into FunctionParameters + var paramsSchema openai.FunctionParameters + if err := json.Unmarshal(jsonSchemaBytes, ¶msSchema); err != nil { + return openai.ChatCompletionToolParam{} + } + + // Create and return the final tool parameter struct. + return openai.ChatCompletionToolParam{ + Function: openai.FunctionDefinitionParam{ + Name: toolboxTool.Name(), + Description: openai.String(toolboxTool.Description()), + Parameters: paramsSchema, + }, + } +} + +func main() { + // Setup + ctx := context.Background() + toolboxURL := "http://localhost:5000" + openAIClient := openai.NewClient() + + // Initialize the MCP Toolbox client. + toolboxClient, err := core.NewToolboxClient(toolboxURL) + if err != nil { + log.Fatalf("Failed to create Toolbox client: %v", err) + } + + // Load the tools using the MCP Toolbox SDK. + tools, err := toolboxClient.LoadToolset("my-toolset", ctx) + if err != nil { + log.Fatalf("Failed to load tool : %v\nMake sure your Toolbox server is running and the tool is configured.", err) + } + + openAITools := make([]openai.ChatCompletionToolParam, len(tools)) + toolsMap := make(map[string]*core.ToolboxTool, len(tools)) + + for i, tool := range tools { + // Convert the Toolbox tool into the openAI FunctionDeclaration format. + openAITools[i] = ConvertToOpenAITool(tool) + // Add tool to a map for lookup later + toolsMap[tool.Name()] = tool + + } + question := "Find hotels in Basel with Basel in it's name " + + params := openai.ChatCompletionNewParams{ + Messages: []openai.ChatCompletionMessageParamUnion{ + openai.UserMessage(question), + }, + Tools: openAITools, + Seed: openai.Int(0), + Model: openai.ChatModelGPT4o, + } + + // Make initial chat completion request + completion, err := openAIClient.Chat.Completions.New(ctx, params) + if err != nil { + panic(err) + } + + toolCalls := completion.Choices[0].Message.ToolCalls + + // Return early if there are no tool calls + if len(toolCalls) == 0 { + fmt.Printf("No function call") + return + } + +// If there was a function call, continue the conversation + params.Messages = append(params.Messages, completion.Choices[0].Message.ToParam()) + for _, toolCall := range toolCalls { + if toolCall.Function.Name == "search-hotels-by-name" { + // Extract the location from the function call arguments + var args map[string]interface{} + tool := toolsMap["search-hotels-by-name"] + err := json.Unmarshal([]byte(toolCall.Function.Arguments), &args) + if err != nil { + panic(err) + } + + result, err := tool.Invoke(ctx, args) + if err != nil { + log.Fatal("Could not invoke tool", err) + } + + params.Messages = append(params.Messages, openai.ToolMessage(result.(string), toolCall.ID)) + } + } + + completion, err = openAIClient.Chat.Completions.New(ctx, params) + if err != nil { + panic(err) + } + + fmt.Println(completion.Choices[0].Message.Content) +} +``` + +
diff --git a/docs/en/sdks/go-sdk/tbadk/_index.md b/docs/en/sdks/go-sdk/tbadk/_index.md new file mode 100644 index 0000000000..5d91e20c1c --- /dev/null +++ b/docs/en/sdks/go-sdk/tbadk/_index.md @@ -0,0 +1,683 @@ +--- +title: "ADK Package" +linkTitle: "ADK" +type: docs +weight: 1 +--- + +![MCP Toolbox Logo](https://raw.githubusercontent.com/googleapis/genai-toolbox/main/logo.png) + +# MCP Toolbox For Go ADK SDK + +[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +This SDK allows you to seamlessly integrate the functionalities of +[MCP Toolbox](https://github.com/googleapis/genai-toolbox) allowing you to load and +use tools defined in the service as standard Go structs within your ADK Go +applications. + +This simplifies integrating external functionalities (like APIs, databases, or +custom logic) managed by the Toolbox into your workflows, especially those +involving Large Language Models (LLMs). + +## Installation + +```bash +go get github.com/googleapis/mcp-toolbox-sdk-go +``` +This SDK is supported on Go version 1.24.4 and higher. + +{{< notice note >}} +While the SDK itself is synchronous, you can execute its functions within goroutines to achieve asynchronous behavior. +{{< /notice >}} + + +## Quickstart + +Here's a minimal example to get you started. Ensure your Toolbox service is +running and accessible. + +```go +package main + +import ( + "context" + "fmt" + "github.com/googleapis/mcp-toolbox-sdk-go/tbadk" +) + +func quickstart() string { + inputs := map[string]any{"location": "London"} + client, err := tbadk.NewToolboxClient("http://localhost:5000") + if err != nil { + return fmt.Sprintln("Could not start Toolbox Client", err) + } + tool, err := client.LoadTool("get_weather", ctx) + if err != nil { + return fmt.Sprintln("Could not load Toolbox Tool", err) + } + // pass the tool.Context as ctx into the Run() method + result, err := tool.Run(ctx, inputs) + if err != nil { + return fmt.Sprintln("Could not invoke tool", err) + } + return fmt.Sprintln(result["output"]) +} + +func main() { + fmt.Println(quickstart()) +} +``` + +## Usage + +Import and initialize a Toolbox client, pointing it to the URL of your running +Toolbox service. + +```go +import "github.com/googleapis/mcp-toolbox-sdk-go/tbadk" + +client, err := tbadk.NewToolboxClient("http://localhost:5000") +``` + +All interactions for loading and invoking tools happen through this client. + +{{< notice note >}} +For advanced use cases, you can provide an external custom `http.Client` +during initialization (e.g., `tbadk.NewToolboxClient(URL, core.WithHTTPClient(myClient)`). If you provide your own session, you are responsible for managing its lifecycle; +`ToolboxClient` *will not* close it. +{{< /notice >}} + +## Transport Protocols + +The SDK supports multiple transport protocols. By default, the client uses the latest supported version of the **Model Context Protocol (MCP)**. + +You can explicitly select a protocol using the `core.WithProtocol` option during client initialization. + +{{< notice note >}}* **Native Toolbox Transport**: This uses the service's native **REST over HTTP** API. +* **MCP Transports**: These options use the **Model Context Protocol over HTTP**. +{{< /notice >}} + +### Supported Protocols + +| Constant | Description | +| :--- | :--- | +| `core.MCP` | **(Default)** Alias for the latest supported MCP version (currently `v2025-06-18`). | +| `core.Toolbox` | The native Toolbox HTTP protocol. | +| `core.MCPv20251125` | MCP Protocol version 2025-11-25. | +| `core.MCPv20250618` | MCP Protocol version 2025-06-18. | +| `core.MCPv20250326` | MCP Protocol version 2025-03-26. | +| `core.MCPv20241105` | MCP Protocol version 2024-11-05. | + +### Example + +```go +import ( + "github.com/googleapis/mcp-toolbox-sdk-go/core" + "github.com/googleapis/mcp-toolbox-sdk-go/tbadk" +) + +// Initialize with the native Toolbox protocol +client, err := tbadk.NewToolboxClient( + "http://localhost:5000", + core.WithProtocol(core.Toolbox), +) + +// Initialize with the MCP Protocol 2025-03-26 +client, err := tbadk.NewToolboxClient( + "http://localhost:5000", + core.WithProtocol(core.MCPv20250326), +) + +``` + +## Loading Tools + +You can load tools individually or in groups (toolsets) as defined in your +Toolbox service configuration. Loading a toolset is convenient when working with +multiple related functions, while loading a single tool offers more granular +control. + +### Load a toolset + +A toolset is a collection of related tools. You can load all tools in a toolset +or a specific one: + +```go +// Load default toolset by providing an empty string as the name +tools, err := client.LoadToolset("", ctx) + +// Load a specific toolset +tools, err := client.LoadToolset("my-toolset", ctx) +``` + +`LoadToolset` returns a slice of the ToolboxTool structs (`[]ToolboxTool`). + + +### Load a single tool + +Loads a specific tool by its unique name. This provides fine-grained control. + +```go +tool, err = client.LoadTool("my-tool", ctx) +``` + +## Invoking Tools + +Once loaded, tools behave like Go structs. You invoke them using `Run` method +by passing arguments corresponding to the parameters defined in the tool's +configuration within the Toolbox service. + +```go +tool, err = client.LoadTool("my-tool", ctx) +inputs := map[string]any{"location": "London"} +// Pass the tool.Context as ctx to the Run() function +result, err := tool.Run(ctx, inputs) +``` + +{{< notice tip >}}For a more comprehensive guide on setting up the Toolbox service itself, which +you'll need running to use this SDK, please refer to the [Toolbox Quickstart +Guide](https://googleapis.github.io/genai-toolbox/getting-started/local_quickstart). +{{< /notice >}} + +## Client to Server Authentication + +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. + +This client-to-server authentication ensures that the Toolbox server can verify +the identity of the client making the request before any tool is loaded or +called. It is different from [Authenticating Tools](#authenticating-tools), +which deals with providing credentials for specific tools within an already +connected Toolbox session. + +### When is Client-to-Server Authentication Needed? + +You'll need this type of authentication if your Toolbox server is configured to +deny unauthenticated requests. For example: + +- Your Toolbox server is deployed on Cloud Run and configured to "Require authentication." +- Your server is behind an Identity-Aware Proxy (IAP) or a similar + authentication layer. +- You have custom authentication middleware on your self-hosted Toolbox server. + +Without proper client authentication in these scenarios, attempts to connect or +make calls (like `LoadTool`) will likely fail with `Unauthorized` errors. + +### How it works + +The `ToolboxClient` allows you to specify TokenSources that dynamically generate HTTP headers for +every request sent to the Toolbox server. The most common use case is to add an +Authorization header with a bearer token (e.g., a Google ID token). + +These header-generating functions are called just before each request, ensuring +that fresh credentials or header values can be used. + +### Configuration + +You can configure these dynamic headers as seen below: + + +```go +import ( + "github.com/googleapis/mcp-toolbox-sdk-go/core" + "github.com/googleapis/mcp-toolbox-sdk-go/tbadk" +) + +tokenProvider := func() string { + return "header3_value" +} + +staticTokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: "header2_value"}) +dynamicTokenSource := core.NewCustomTokenSource(tokenProvider) + +client, err := tbadk.NewToolboxClient( + "toolbox-url", + core.WithClientHeaderString("header1", "header1_value"), + core.WithClientHeaderTokenSource("header2", staticTokenSource), + core.WithClientHeaderTokenSource("header3", dynamicTokenSource), +) +``` + +### Authenticating with Google Cloud Servers + +For Toolbox servers hosted on Google Cloud (e.g., Cloud Run) and requiring +`Google ID token` authentication, the helper module +[auth_methods](/core/auth.go) provides utility functions. + +### Step by Step Guide for Cloud Run + +1. **Configure Permissions**: [Grant](https://cloud.google.com/run/docs/securing/managing-access#service-add-principals) the `roles/run.Runr` IAM role on the Cloud + Run service to the principal. This could be your `user account email` or a + `service account`. +2. **Configure Credentials** + - Local Development: Set up + [ADC](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment). + - Google Cloud Environments: When running within Google Cloud (e.g., Compute + Engine, GKE, another Cloud Run service, Cloud Functions), ADC is typically + configured automatically, using the environment's default service account. +3. **Connect to the Toolbox Server** + ```go + import ( + "github.com/googleapis/mcp-toolbox-sdk-go/core" + "github.com/googleapis/mcp-toolbox-sdk-go/tbadk" + "context" + ) + + ctx := context.Background() + + token, err := core.GetGoogleIDToken(ctx, URL) + + client, err := tbadk.NewToolboxClient( + URL, + core.WithClientHeaderString("Authorization", token), + ) + + // Now, you can use the client as usual. + ``` + +## Authenticating Tools + +{{< notice warning >}} **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. +{{< /notice >}} + +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. + +### When is Authentication Needed? + +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. + +### Supported Authentication Mechanisms + +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](https://googleapis.github.io/genai-toolbox/resources/tools/#authenticated-parameters). + +### Step 1: Configure Tools in Toolbox Service + +First, ensure the target tool(s) are configured correctly in the Toolbox service +to require authentication. Refer to the [Toolbox Service Documentation - +Authenticated +Parameters](https://googleapis.github.io/genai-toolbox/resources/tools/#authenticated-parameters) +for instructions. + +### Step 2: Configure SDK Client + +Your application needs a way to obtain the required Oauth2 token for the +authenticated user. The SDK requires you to provide a function capable of +retrieving this token *when the tool is invoked*. + +#### Provide an ID Token Retriever Function + +You must provide the SDK with a function that returns the +necessary token when called. The implementation depends on your application's +authentication flow (e.g., retrieving a stored token, initiating an OAuth flow). + +{{< notice info >}} +The name used when registering the getter function with the SDK (e.g., +`"my_api_token"`) must exactly match the `name` of the corresponding +`authServices` defined in the tool's configuration within the Toolbox service. +{{< /notice >}} + +```go +func getAuthToken() string { + // ... Logic to retrieve ID token (e.g., from local storage, OAuth flow) + // This example just returns a placeholder. Replace with your actual token retrieval. + return "YOUR_ID_TOKEN" // Placeholder +} +``` + +{{< notice 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. +{{< /notice >}} + +#### Option A: Add Default Authentication to a Client + +You can add default tool level authentication to a client. +Every tool / toolset loaded by the client will contain the auth token. + +```go + +ctx := context.Background() + +client, err := tbadk.NewToolboxClient("http://127.0.0.1:5000", + core.WithDefaultToolOptions( + core.WithAuthTokenString("my-auth-1", "auth-value"), + ), +) + +AuthTool, err := client.LoadTool("my-tool", ctx) +``` + +#### Option B: Add Authentication to a Loaded Tool + +You can add the token retriever function to a tool object *after* it has been +loaded. This modifies the specific tool instance. + +```go + +ctx := context.Background() + +client, err := tbadk.NewToolboxClient("http://127.0.0.1:5000") + +tool, err := client.LoadTool("my-tool", ctx) + +AuthTool, err := tool.ToolFrom( + core.WithAuthTokenSource("my-auth", headerTokenSource), + core.WithAuthTokenString("my-auth-1", "value"), + ) +``` + +#### Option C: Add Authentication While Loading Tools + +You can provide the token retriever(s) directly during the `LoadTool` or +`LoadToolset` calls. This applies the authentication configuration only to the +tools loaded in that specific call, without modifying the original tool objects +if they were loaded previously. + +```go +AuthTool, err := client.LoadTool("my-tool", ctx, core.WithAuthTokenString("my-auth-1", "value")) + +// or + +AuthTools, err := client.LoadToolset( + "my-toolset", + ctx, + core.WithAuthTokenString("my-auth-1", "value"), +) +``` + +{{< notice note >}} +Adding auth tokens during loading only affect the tools loaded within that call. +{{< /notice >}} + +### Complete Authentication Example + +```go +import "github.com/googleapis/mcp-toolbox-sdk-go/core" +import "fmt" + +func getAuthToken() string { + // ... Logic to retrieve ID token (e.g., from local storage, OAuth flow) + // This example just returns a placeholder. Replace with your actual token retrieval. + return "YOUR_ID_TOKEN" // Placeholder +} + +func main() { + ctx := context.Background() + inputs := map[string]any{"input": "some input"} + + dynamicTokenSource := core.NewCustomTokenSource(getAuthToken) + + client, err := tbadk.NewToolboxClient("http://127.0.0.1:5000") + tool, err := client.LoadTool("my-tool", ctx) + AuthTool, err := tool.ToolFrom(core.WithAuthTokenSource("my_auth", dynamicTokenSource)) + + result, err := AuthTool.Run(ctx, inputs) + + fmt.Println(result) +} +``` + +{{< notice note >}}An auth token getter for a specific name (e.g., "GOOGLE_ID") will replace any client header with the same name followed by "_token" (e.g.,"GOOGLE_ID_token"). +{{< /notice >}} + +## Binding Parameter Values + +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. + +### Why Bind Parameters? + +- **Protecting sensitive information:** API keys, secrets, etc. +- **Enforcing consistency:** Ensuring specific values for certain parameters. +- **Pre-filling known data:** Providing defaults or context. + +{{< notice info >}} +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. +{{< /notice >}} + +{{< notice note >}} +You do not need to modify the tool's configuration in the Toolbox service to bind parameter values using the SDK. +{{< /notice >}} + +#### Option A: Add Default Bound Parameters to a Client + +You can add default tool level bound parameters to a client. Every tool / toolset +loaded by the client will have the bound parameter. + +```go + +ctx := context.Background() + +client, err := tbadk.NewToolboxClient("http://127.0.0.1:5000", + core.WithDefaultToolOptions( + core.WithBindParamString("param1", "value"), + ), +) + +boundTool, err := client.LoadTool("my-tool", ctx) +``` + +### Option B: Binding Parameters to a Loaded Tool + +Bind values to a tool object *after* it has been loaded. This modifies the +specific tool instance. + +```go +client, err := tbadk.NewToolboxClient("http://127.0.0.1:5000") + +tool, err := client.LoadTool("my-tool", ctx) + +boundTool, err := tool.ToolFrom( + core.WithBindParamString("param1", "value"), + core.WithBindParamString("param2", "value") + ) +``` + +### Option C: Binding Parameters While Loading Tools + +Specify bound parameters directly when loading tools. This applies the binding +only to the tools loaded in that specific call. + +```go +boundTool, err := client.LoadTool("my-tool", ctx, core.WithBindParamString("param", "value")) + +// OR + +boundTool, err := client.LoadToolset("", ctx, core.WithBindParamString("param", "value")) +``` + +{{< notice note >}} +Bound values during loading only affect the tools loaded in that call. +{{< /notice >}} + +### Binding Dynamic Values + +Instead of a static value, you can bind a parameter to a synchronous or +asynchronous function. This function will be called *each time* the tool is +invoked to dynamically determine the parameter's value at runtime. +Functions with the return type (data_type, error) can be provided. + +```go +getDynamicValue := func() (string, error) { return "req-123", nil } + +dynamicBoundTool, err := tool.ToolFrom(core.WithBindParamStringFunc("param", getDynamicValue)) +``` + +{{< notice info >}} +You don't need to modify tool configurations to bind parameter values. +{{< /notice >}} + +## Using with ADK Go + +After altering the tool to your needs, type-assert the ToolboxTool and pass it to the LLM agent. + +### For a single tool + +```go + +toolboxtool, err = client.LoadTool("my-tool", ctx) + +// + +llmagent, err := llmagent.New(llmagent.Config{ + Name: "assistant", + Model: model, + Description: "Agent to answer questions.", + Tools: []tool.Tool{&toolboxtool}, +}) +``` + +### For a toolset + +```go +toolboxtools, err := client.LoadToolset("", ctx) + +// + +toolsList := make([]tool.Tool, len(toolboxtools)) + for i := range toolboxtools { + toolsList[i] = &toolboxtools[i] + } + +llmagent, err := llmagent.New(llmagent.Config{ + Name: "assistant", + Model: model, + Description: "Agent to answer questions.", + Tools: toolsList, +}) + +``` + +The reason we have to type assert it before passing it to ADK Go, is because it requires a generic `tool.Tool` interface. You can always convert it back to `ToolboxTool` format to access the specialized methods. + +# Using with Orchestration Frameworks + +To see how the MCP Toolbox Go SDK works with orchestration frameworks, check out these end-to-end examples given below. + +
+ADK Go + +```go +//This sample contains a complete example on how to integrate MCP Toolbox Go SDK with ADK Go using the tbadk package. +package main + +import ( + "context" + "fmt" + "log" + "os" + + "github.com/googleapis/mcp-toolbox-sdk-go/tbadk" + "google.golang.org/adk/agent" + "google.golang.org/adk/agent/llmagent" + "google.golang.org/adk/model/gemini" + "google.golang.org/adk/runner" + "google.golang.org/adk/session" + "google.golang.org/adk/tool" + "google.golang.org/genai" +) + +func main() { + genaiKey := os.Getenv("GEMINI_API_KEY") + toolboxURL := "http://localhost:5000" + ctx := context.Background() + + // Initialize MCP Toolbox client + toolboxClient, err := tbadk.NewToolboxClient(toolboxURL) + if err != nil { + log.Fatalf("Failed to create MCP Toolbox client: %v", err) + } + + toolsetName := "my-toolset" + toolset, err := toolboxClient.LoadToolset(toolsetName, ctx) + if err != nil { + log.Fatalf("Failed to load MCP toolset '%s': %v\nMake sure your Toolbox server is running.", toolsetName, err) + } + + // Create Gemini model + model, err := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{ + APIKey: genaiKey, + }) + if err != nil { + log.Fatalf("Failed to create model: %v", err) + } + + tools := make([]tool.Tool, len(toolset)) + for i := range toolset { + tools[i] = &toolset[i] + } + + llmagent, err := llmagent.New(llmagent.Config{ + Name: "hotel_assistant", + Model: model, + Description: "Agent to answer questions about hotels.", + Tools: tools, + }) + if err != nil { + log.Fatalf("Failed to create agent: %v", err) + } + + appName := "hotel_assistant" + userID := "user-123" + + sessionService := session.InMemoryService() + resp, err := sessionService.Create(ctx, &session.CreateRequest{ + AppName: appName, + UserID: userID, + }) + if err != nil { + log.Fatalf("Failed to create the session service: %v", err) + } + session := resp.Session + + r, err := runner.New(runner.Config{ + AppName: appName, + Agent: llmagent, + SessionService: sessionService, + }) + if err != nil { + log.Fatalf("Failed to create runner: %v", err) + } + + query := "Find hotels with Basel in its name." + + fmt.Println(query) + userMsg := genai.NewContentFromText(query, genai.RoleUser) + + streamingMode := agent.StreamingModeSSE + for event, err := range r.Run(ctx, userID, session.ID(), userMsg, agent.RunConfig{ + StreamingMode: streamingMode, + }) { + if err != nil { + fmt.Printf("\nAGENT_ERROR: %v\n", err) + } else { + if event.LLMResponse.Content != nil { + for _, p := range event.LLMResponse.Content.Parts { + if streamingMode != agent.StreamingModeSSE || event.LLMResponse.Partial { + fmt.Print(p.Text) + } + } + } + } + } + fmt.Println() +} +``` + +
\ No newline at end of file diff --git a/docs/en/sdks/go-sdk/tbgenkit/_index.md b/docs/en/sdks/go-sdk/tbgenkit/_index.md new file mode 100644 index 0000000000..dfaa3c09e1 --- /dev/null +++ b/docs/en/sdks/go-sdk/tbgenkit/_index.md @@ -0,0 +1,121 @@ +--- +title: "Genkit Package" +linkTitle: "Genkit" +type: docs +weight: 1 +--- + +![MCP Toolbox Logo](https://raw.githubusercontent.com/googleapis/genai-toolbox/main/logo.png) + +# MCP Toolbox For Go Genkit SDK + +[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +This package allows you to seamlessly integrate the functionalities of +[MCP Toolbox](https://github.com/googleapis/genai-toolbox) allowing you to load and +use tools defined in the service as standard Genkit Tools within your Genkit Go +applications. + +This simplifies integrating external functionalities (like APIs, databases, or +custom logic) managed by the Toolbox into your workflows, especially those +involving Large Language Models (LLMs). + +## Installation + +```bash +go get github.com/googleapis/mcp-toolbox-sdk-go +``` +This SDK is supported on Go version 1.24.4 and higher. + +## Quickstart + +For more information on how to load a `ToolboxTool`, see [the core package](https://github.com/googleapis/mcp-toolbox-sdk-go/tree/main/core) + +## Convert Toolbox Tool to a Genkit Tool + +```go +"github.com/googleapis/mcp-toolbox-sdk-go/tbgenkit" + +func main() { + // Assuming the toolbox tool is loaded + // Make sure to add error checks for debugging + ctx := context.Background() + g, err := genkit.Init(ctx) + + genkitTool, err := tbgenkit.ToGenkitTool(toolboxTool, g) + +} +``` + +# Using with Orchestration Frameworks + +To see how the MCP Toolbox Go SDK works with orchestration frameworks, check out these end-to-end examples given below. + +
+Genkit Go + +```go +//This sample contains a complete example on how to integrate MCP Toolbox Go SDK with Genkit Go using the tbgenkit package. +package main + +import ( + "context" + "fmt" + "log" + + "github.com/googleapis/mcp-toolbox-sdk-go/core" + "github.com/googleapis/mcp-toolbox-sdk-go/tbgenkit" + + "github.com/firebase/genkit/go/ai" + "github.com/firebase/genkit/go/genkit" + "github.com/firebase/genkit/go/plugins/googlegenai" +) + +func main() { + ctx := context.Background() + toolboxClient, err := core.NewToolboxClient("http://127.0.0.1:5000") + if err != nil { + log.Fatalf("Failed to create Toolbox client: %v", err) + } + + // Load the tools using the MCP Toolbox SDK. + tools, err := toolboxClient.LoadToolset("my-toolset", ctx) + if err != nil { + log.Fatalf("Failed to load tools: %v\nMake sure your Toolbox server is running and the tool is configured.", err) + } + + // Initialize genkit + g := genkit.Init(ctx, + genkit.WithPlugins(&googlegenai.GoogleAI{}), + genkit.WithDefaultModel("googleai/gemini-1.5-flash"), + ) + + // Convert your tool to a Genkit tool. + genkitTools := make([]ai.Tool, len(tools)) + for i, tool := range tools { + newTool, err := tbgenkit.ToGenkitTool(tool, g) + if err != nil { + log.Fatalf("Failed to convert tool: %v\n", err) + } + genkitTools[i] = newTool + } + + toolRefs := make([]ai.ToolRef, len(genkitTools)) + + for i, tool := range genkitTools { + toolRefs[i] = tool + } + + // Generate llm response using prompts and tools. + resp, err := genkit.Generate(ctx, g, + ai.WithPrompt("Find hotels in Basel with Basel in it's name."), + ai.WithTools(toolRefs...), + ) + if err != nil { + log.Fatalf("%v\n", err) + } + fmt.Println(resp.Text()) +} +``` + +
\ No newline at end of file