diff --git a/README.md b/README.md index ff2e0518..ec2f2080 100644 --- a/README.md +++ b/README.md @@ -14,83 +14,33 @@ applications. These SDKs allow you to load tools defined in Toolbox and use them as standard Python functions or objects 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. +For comprehensive guides and advanced configuration, visit the [Main Documentation Site](https://googleapis.github.io/genai-toolbox/). + -- [Overview](#overview) -- [Which Package Should I Use?](#which-package-should-i-use) - [Available Packages](#available-packages) -- [Getting Started](#getting-started) +- [Quick Start](#quick-start) - [Contributing](#contributing) - [License](#license) - [Support](#support) -## Overview - -The MCP Toolbox service provides a centralized way to manage and expose tools -(like API connectors, database query tools, etc.) for use by GenAI applications. - -These Python SDKs act as clients for that service. They handle the communication needed to: - -* Fetch tool definitions from your running Toolbox instance. -* Provide convenient Python objects or functions representing those tools. -* Invoke the tools (calling the underlying APIs/services configured in Toolbox). -* Handle authentication and parameter binding as needed. - -By using these SDKs, you can easily leverage your Toolbox-managed tools directly -within your Python applications or AI orchestration frameworks. - -## Which Package Should I Use? - -Choosing the right package depends on how you are building your application: - -* [`toolbox-adk`](https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main/packages/toolbox-adk): - Use this package if you are building your application using Google ADK (Agent Development Kit). - It provides tools that are directly compatible with the - Google ADK ecosystem (`BaseTool` / `BaseToolset` interface) handling authentication propagation, header management, and tool wrapping automatically. -* [`toolbox-core`](https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main/packages/toolbox-core): - Use this package if you are not using LangChain/LangGraph or any other - orchestration framework, or if you need a framework-agnostic way to interact - with Toolbox tools (e.g., for custom orchestration logic or direct use in - Python scripts). -* [`toolbox-langchain`](https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main/packages/toolbox-langchain): - Use this package if you are building your application using the LangChain or - LangGraph frameworks. It provides tools that are directly compatible with the - LangChain ecosystem (`BaseTool` interface), simplifying integration. -* [`toolbox-llamaindex`](https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main/packages/toolbox-llamaindex): - Use this package if you are building your application using the LlamaIndex framework. - It provides tools that are directly compatible with the - LlamaIndex ecosystem (`BaseTool` interface), simplifying integration. - ## Available Packages -This repository hosts the following Python packages. See the package-specific -README for detailed installation and usage instructions: +This repository hosts the following Python packages. See the package-specific READMEs or the docsite for detailed usage: -| Package | Target Use Case | Integration | Path | Details (README) | PyPI Status | -| :------ | :---------- | :---------- | :---------------------- | :---------- | :--------- -| `toolbox-adk` | Google ADK applications | Google ADK | `packages/toolbox-adk/` | 📄 [View README](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-adk/README.md) | ![pypi version](https://img.shields.io/pypi/v/toolbox-adk.svg) | -| `toolbox-core` | Framework-agnostic / Custom applications | Use directly / Custom | `packages/toolbox-core/` | 📄 [View README](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-core/README.md) | ![pypi version](https://img.shields.io/pypi/v/toolbox-core.svg) | -| `toolbox-langchain` | LangChain / LangGraph applications | LangChain / LangGraph | `packages/toolbox-langchain/` | 📄 [View README](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-langchain/README.md) | ![pypi version](https://img.shields.io/pypi/v/toolbox-langchain.svg) | -| `toolbox-llamaindex` | LlamaIndex applications | LlamaIndex | `packages/toolbox-llamaindex/` | 📄 [View README](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-llamaindex/README.md) | ![pypi version](https://img.shields.io/pypi/v/toolbox-llamaindex.svg) | +| Package | Target Use Case | Path | Documentation | +| :------ | :---------- | :--- | :---------- | +| `toolbox-core` | Framework-agnostic / Custom apps | `packages/toolbox-core/` | [Python Core Guide](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/) | +| `toolbox-adk` | Google ADK Integration | `packages/toolbox-adk/` | [ADK Package Guide](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/adk/) | +| `toolbox-langchain` | LangChain / LangGraph Integration | `packages/toolbox-langchain/` | [LangChain Guide](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/) | +| `toolbox-llamaindex` | LlamaIndex Integration | `packages/toolbox-llamaindex/` | [LlamaIndex Guide](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/) | +## Quick Start -## 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 main MCP Toolbox service running. Follow - the instructions here: [**Toolbox Getting Started - Guide**](https://github.com/googleapis/genai-toolbox?tab=readme-ov-file#getting-started) - +1. **Set up the Toolbox Service**: Ensure you have a running MCP Toolbox server. Follow the [Toolbox Server 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) and install it: ```bash # For the Google ADK @@ -109,19 +59,7 @@ To get started using Toolbox tools with an application, follow these general ste # For the LlamaIndex integration pip install toolbox-llamaindex ``` - -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. - -> [!TIP] -> For a complete, end-to-end example including setting up the service and using -> an SDK, see the full tutorial: [**Toolbox Quickstart -> Tutorial**](https://googleapis.github.io/genai-toolbox/getting-started/local_quickstart) +3. **Explore Tutorials**: Check out the [Python Quickstart Tutorial](https://googleapis.github.io/genai-toolbox/getting-started/local_quickstart/) for a full walkthrough. ## Contributing diff --git a/packages/toolbox-adk/README.md b/packages/toolbox-adk/README.md index bc9b3ea7..753ab67e 100644 --- a/packages/toolbox-adk/README.md +++ b/packages/toolbox-adk/README.md @@ -4,27 +4,12 @@ This package allows Google ADK (Agent Development Kit) agents to natively use tools from the [MCP Toolbox](https://github.com/googleapis/genai-toolbox). -It provides a seamless bridge between the `toolbox-core` SDK and the ADK's `BaseTool` / `BaseToolset` interfaces, handling authentication propagation, header management, and tool wrapping automatically. +For detailed guides, authentication examples, and advanced configuration, visit the [Python SDK ADK Guide](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/adk/). ## Table of Contents - [Installation](#installation) - [Usage](#usage) -- [Transport Protocols](#transport-protocols) - - [Supported Protocols](#supported-protocols) - - [Example](#example) -- [Authentication](#authentication) - - [Workload Identity (ADC)](#1-workload-identity-adc) - - [User Identity (OAuth2)](#2-user-identity-oauth2) - - [API Key](#3-api-key) - - [HTTP Bearer Token](#4-http-bearer-token) - - [Manual Google Credentials](#5-manual-google-credentials) - - [Toolbox Identity (No Auth)](#6-toolbox-identity-no-auth) - - [Native ADK Integration](#7-native-adk-integration) - - [Tool-Specific Authentication](#8-tool-specific-authentication) -- [Advanced Configuration](#advanced-configuration) - - [Additional Headers](#additional-headers) - - [Global Parameter Binding](#global-parameter-binding) ## Installation @@ -34,229 +19,11 @@ pip install toolbox-adk ## Usage -The primary entry point is the `ToolboxToolset`, which loads tools from a remote Toolbox server and adapts them for use with ADK agents. +The toolbox-adk package provides a seamless bridge to natively use MCP Toolbox tools within ADK agents. For detailed guides and advanced configuration, please visit the following sections on our [Documentation Site](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/adk/): -> [!NOTE] -> The `ToolboxToolset` in this package mirrors the `ToolboxToolset` in the [`adk-python`](https://github.com/google/adk-python) package. The `adk-python` version is a shim that delegates all functionality to this implementation. - -```python -from toolbox_adk import ToolboxToolset -from google.adk import Agent - -# Create the Toolset -toolset = ToolboxToolset( - server_url="http://127.0.0.1:5000" -) - -# Use in your ADK Agent -agent = Agent(tools=[toolset]) -``` - -## 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 `protocol` option during toolset 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. - -> [!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**. - -### Supported Protocols - -| Constant | Description | -| :--- | :--- | -| `Protocol.MCP` | **(Default)** Alias for the default MCP version (currently `2025-06-18`). | -| `Protocol.MCP_v20251125` | MCP Protocol version 2025-11-25. | -| `Protocol.MCP_v20250618` | MCP Protocol version 2025-06-18. | -| `Protocol.MCP_v20250326` | MCP Protocol version 2025-03-26. | -| `Protocol.MCP_v20241105` | MCP Protocol version 2024-11-05. | - -> [!WARNING] - -### Example - - -```python -from toolbox_adk import ToolboxToolset -from toolbox_core.protocol import Protocol - -toolset = ToolboxToolset( - server_url="http://127.0.0.1:5000", - protocol=Protocol.MCP -) -``` - -If you want to pin the MCP Version 2025-03-26: - -```python -from toolbox_adk import ToolboxToolset -from toolbox_core.protocol import Protocol - -toolset = ToolboxToolset( - server_url="http://127.0.0.1:5000", - protocol=Protocol.MCP_v20250326 -) -``` - -> [!TIP] -> By default, it uses **Toolbox Identity** (no authentication), which is suitable for local development. -> -> For production environments (Cloud Run, GKE) or accessing protected resources, see the [Authentication](#authentication) section for strategies like Workload Identity or OAuth2. - -## Authentication - -The `ToolboxToolset` requires credentials to authenticate with the Toolbox server. You can configure these credentials using the `CredentialStrategy` factory methods. - -The strategies handle two main types of authentication: -* **Client-to-Server**: Securing the connection to the Toolbox server (e.g., Workload Identity, API keys). -* **User Identity**: Authenticating the end-user for specific tools (e.g., 3-legged OAuth). - -### 1. Workload Identity (ADC) -*Recommended for Cloud Run, GKE, or local development with `gcloud auth login`.* - -Uses the agent's Application Default Credentials (ADC) to generate an OIDC token. This is the standard way for one service to authenticate to another on Google Cloud. - -```python -from toolbox_adk import CredentialStrategy, ToolboxToolset - -# target_audience: The URL of your Toolbox server -creds = CredentialStrategy.workload_identity(target_audience="https://my-toolbox-service.run.app") - -toolset = ToolboxToolset( - server_url="https://my-toolbox-service.run.app", - credentials=creds -) -``` - -### 2. User Identity (OAuth2) -*Recommended for tools that act on behalf of the user.* - -Configures the ADK-native interactive 3-legged OAuth flow to get consent and credentials from the end-user at runtime. This strategy is passed to the `ToolboxToolset` just like any other credential strategy. - -```python -from toolbox_adk import CredentialStrategy, ToolboxToolset - -creds = CredentialStrategy.user_identity( - client_id="YOUR_CLIENT_ID", - client_secret="YOUR_CLIENT_SECRET", - scopes=["https://www.googleapis.com/auth/cloud-platform"] -) - -# The toolset will now initiate OAuth flows when required by tools -toolset = ToolboxToolset( - server_url="...", - credentials=creds -) -``` - -### 3. API Key -*Use a static API key passed in a specific header (default: `X-API-Key`).* - -```python -from toolbox_adk import CredentialStrategy - -# Default header: X-API-Key -creds = CredentialStrategy.api_key(key="my-secret-key") - -# Custom header -creds = CredentialStrategy.api_key(key="my-secret-key", header_name="X-My-Header") -``` - -### 4. HTTP Bearer Token -*Manually supply a static bearer token.* - -```python -from toolbox_adk import CredentialStrategy - -creds = CredentialStrategy.manual_token(token="your-static-bearer-token") -``` - -### 5. Manual Google Credentials -*Use an existing `google.auth.credentials.Credentials` object.* - -```python -from toolbox_adk import CredentialStrategy -import google.auth - -creds_obj, _ = google.auth.default() -creds = CredentialStrategy.manual_credentials(credentials=creds_obj) -``` - -### 6. Toolbox Identity (No Auth) -*Use this if your Toolbox server does not require authentication (e.g., local development).* - -```python -from toolbox_adk import CredentialStrategy - -creds = CredentialStrategy.toolbox_identity() -``` - -### 7. Native ADK Integration -*Convert ADK-native `AuthConfig` or `AuthCredential` objects.* - -```python -from toolbox_adk import CredentialStrategy - -# From AuthConfig -creds = CredentialStrategy.from_adk_auth_config(auth_config) - -# From AuthCredential + AuthScheme -creds = CredentialStrategy.from_adk_credentials(auth_credential, scheme) -``` - -### 8. Tool-Specific Authentication -*Resolve authentication tokens dynamically for specific tools.* - -Some tools may define their own authentication requirements (e.g., Salesforce OAuth, GitHub PAT) via `authSources` in their schema. You can provide a mapping of getters to resolve these tokens at runtime. - -```python -async def get_salesforce_token(): - # Fetch token from secret manager or reliable source - return "sf-access-token" - -toolset = ToolboxToolset( - server_url="...", - auth_token_getters={ - "salesforce-auth": get_salesforce_token, # Async callable - "github-pat": lambda: "my-pat-token" # Sync callable or static lambda - } -) -``` - -## Advanced Configuration - -### Additional Headers - -You can inject custom headers into every request made to the Toolbox server. This is useful for passing tracing IDs, API keys, or other metadata. - -```python -toolset = ToolboxToolset( - server_url="...", - additional_headers={ - "X-Trace-ID": "12345", - "X-My-Header": lambda: get_dynamic_header_value() # Can be a callable - } -) -``` - -### Global Parameter Binding - -Bind values to tool parameters globally across all loaded tools. These values will be **fixed** and **hidden** from the LLM. - -* **Schema Hiding**: The bound parameters are removed from the tool schema sent to the model, simplifying the context window. -* **Auto-Injection**: The values are automatically injected into the tool arguments during execution. - -```python -toolset = ToolboxToolset( - server_url="...", - bound_params={ - # 'region' will be removed from the LLM schema and injected automatically - "region": "us-central1", - "api_key": lambda: get_api_key() # Can be a callable - } -) -``` +- [Transport Protocols](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/adk/#transport-protocols) +- [Authentication](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/adk/#authentication) +- [Advanced Configuration](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/adk/#advanced-configuration) ## Contributing diff --git a/packages/toolbox-core/README.md b/packages/toolbox-core/README.md index a3c9b474..ab2c04f4 100644 --- a/packages/toolbox-core/README.md +++ b/packages/toolbox-core/README.md @@ -6,13 +6,11 @@ [![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 -[Toolbox](https://github.com/googleapis/genai-toolbox) allowing you to load and +[MCP Toolbox](https://github.com/googleapis/genai-toolbox) allowing you to load and use tools defined in the service as standard Python functions 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). +For detailed guides, authentication examples, and advanced configuration, visit the [Python SDK Core Guide](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/). @@ -20,35 +18,6 @@ involving Large Language Models (LLMs). - [Installation](#installation) - [Quickstart](#quickstart) - [Usage](#usage) -- [Transport Protocols](#transport-protocols) - - [Supported Protocols](#supported-protocols) - - [Example](#example) -- [Loading Tools](#loading-tools) - - [Load a toolset](#load-a-toolset) - - [Load a single tool](#load-a-single-tool) -- [Invoking Tools](#invoking-tools) -- [Synchronous Usage](#synchronous-usage) -- [Use with LangGraph](#use-with-langgraph) -- [Client to Server Authentication](#client-to-server-authentication) - - [When is Client-to-Server Authentication Needed?](#when-is-client-to-server-authentication-needed) - - [How it works](#how-it-works) - - [Configuration](#configuration) - - [Authenticating with Google Cloud Servers](#authenticating-with-google-cloud-servers) - - [Step by Step Guide for Cloud Run](#step-by-step-guide-for-cloud-run) -- [Authenticating Tools](#authenticating-tools) - - [When is Authentication Needed?](#when-is-authentication-needed) - - [Supported Authentication Mechanisms](#supported-authentication-mechanisms) - - [Step 1: Configure Tools in Toolbox Service](#step-1-configure-tools-in-toolbox-service) - - [Step 2: Configure SDK Client](#step-2-configure-sdk-client) - - [Provide an ID Token Retriever Function](#provide-an-id-token-retriever-function) - - [Option A: Add Authentication to a Loaded Tool](#option-a-add-authentication-to-a-loaded-tool) - - [Option B: Add Authentication While Loading Tools](#option-b-add-authentication-while-loading-tools) - - [Complete Authentication Example](#complete-authentication-example) -- [Binding Parameter Values](#binding-parameter-values) - - [Why Bind Parameters?](#why-bind-parameters) - - [Option A: Binding Parameters to a Loaded Tool](#option-a-binding-parameters-to-a-loaded-tool) - - [Option B: Binding Parameters While Loading Tools](#option-b-binding-parameters-while-loading-tools) - - [Binding Dynamic Values](#binding-dynamic-values) - [Contributing](#contributing) - [License](#license) - [Support](#support) @@ -61,25 +30,6 @@ involving Large Language Models (LLMs). pip install toolbox-core ``` -> [!NOTE] -> -> - The primary `ToolboxClient` is asynchronous and requires using `await` for -> loading and invoking tools, as shown in most examples. -> - Asynchronous code needs to run within an event loop (e.g., using -> `asyncio.run()` or in an async framework). See the [Python `asyncio` -> documentation](https://docs.python.org/3/library/asyncio-task.html) for more -> details. -> - If you prefer synchronous execution, refer to the [Synchronous -> Usage](#synchronous-usage) section below. - -> [!IMPORTANT] -> -> The `ToolboxClient` (and its synchronous counterpart `ToolboxSyncClient`) -> interacts with network resources using an underlying HTTP client session. You -> should remember to use a context manager or explicitly call `close()` to clean -> up these resources. If you provide your own session, you'll need to close it -> in addition to calling `ToolboxClient.close()`. - ## Quickstart Here's a minimal example to get you started. Ensure your Toolbox service is @@ -100,523 +50,19 @@ if __name__ == "__main__": asyncio.run(main()) ``` -> [!TIP] -> For a complete, end-to-end example including setting up the service and using -> an SDK, see the full tutorial: [**Toolbox Quickstart -> Tutorial**](https://googleapis.github.io/genai-toolbox/getting-started/local_quickstart) - -> [!IMPORTANT] -> If you initialize `ToolboxClient` without providing an external session and -> cannot use `async with`, you must explicitly close the client using `await -> toolbox.close()` in a `finally` block. This ensures the internally created -> session is closed. -> -> ```py -> toolbox = ToolboxClient("http://127.0.0.1:5000") -> try: -> # ... use toolbox ... -> finally: -> await toolbox.close() -> ``` - ## Usage -Import and initialize a Toolbox client, pointing it to the URL of your running -Toolbox service. - -```py -from toolbox_core import ToolboxClient - -# Replace with your Toolbox service's URL -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: -``` - -All interactions for loading and invoking tools happen through this client. - -> [!NOTE] -> For advanced use cases, you can provide an external `aiohttp.ClientSession` -> during initialization (e.g., `ToolboxClient(url, session=my_session)`). If you -> provide your own session, you are responsible for managing its lifecycle; -> `ToolboxClient` *will not* close it. - -> [!IMPORTANT] -> 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. - -## 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 `protocol` 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. - -> [!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**. - -### Supported Protocols - -| Constant | Description | -| :--- | :--- | -| `Protocol.MCP` | **(Default)** Alias for the default MCP version (currently `2025-06-18`). | -| `Protocol.MCP_v20251125` | MCP Protocol version 2025-11-25. | -| `Protocol.MCP_v20250618` | MCP Protocol version 2025-06-18. | -| `Protocol.MCP_v20241105` | MCP Protocol version 2024-11-05. | - -> [!WARNING] - -### Example - - -```py -from toolbox_core import ToolboxClient -from toolbox_core.protocol import Protocol - -async with ToolboxClient("http://127.0.0.1:5000", protocol=Protocol.MCP) as toolbox: - # Use client - pass -``` - -If you want to pin the MCP Version 2025-03-26: - -```py -from toolbox_core import ToolboxClient -from toolbox_core.protocol import Protocol - -async with ToolboxClient("http://127.0.0.1:5000", protocol=Protocol.MCP_v20250326) as toolbox: - # Use client - pass -``` - -## 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: - -```py -# Load all tools -tools = await toolbox.load_toolset() - -# Load a specific toolset -tools = await toolbox.load_toolset("my-toolset") -``` - -### Load a single tool - -Loads a specific tool by its unique name. This provides fine-grained control. - -```py -tool = await toolbox.load_tool("my-tool") -``` - -## Invoking Tools - -Once loaded, tools behave like awaitable Python functions. You invoke them using -`await` and pass arguments corresponding to the parameters defined in the tool's -configuration within the Toolbox service. - -```py -tool = await toolbox.load_tool("my-tool") -result = await tool("foo", bar="baz") -``` - -> [!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). - -## Synchronous Usage - -By default, the `ToolboxClient` and the `ToolboxTool` objects it produces behave like asynchronous Python functions, requiring the use of `await`. - -If your application primarily uses synchronous code, or you prefer not to manage an asyncio event loop, you can use the synchronous alternatives provided: - -* `ToolboxSyncClient`: The synchronous counterpart to `ToolboxClient`. -* `ToolboxSyncTool`: The synchronous counterpart to `ToolboxTool`. - -The `ToolboxSyncClient` handles communication with the Toolbox service synchronously and produces `ToolboxSyncTool` instances when you load tools. You do not use the `await` keyword when interacting with these synchronous versions. - -```py -from toolbox_core import ToolboxSyncClient - -with ToolboxSyncClient("http://127.0.0.1:5000") as toolbox: - weather_tool = toolbox.load_tool("get_weather") - result = weather_tool(location="Paris") - print(result) -``` - -> [!TIP] -> While synchronous invocation is available for convenience, it's generally -> considered best practice to use asynchronous operations (like those provided -> by the default `ToolboxClient` and `ToolboxTool`) for an I/O-bound task like -> tool invocation. Asynchronous programming allows for cooperative multitasking, -> often leading to better performance and resource utilization, especially in -> applications handling concurrent requests. - -## Use with LangGraph - -The Toolbox Core SDK integrates smoothly with frameworks like LangGraph, -allowing you to incorporate tools managed by the Toolbox service into your -agentic workflows. - -> [!TIP] -> The loaded tools (both async `ToolboxTool` and sync `ToolboxSyncTool`) are -> callable and can often be used directly. However, to ensure parameter -> descriptions from Google-style docstrings are accurately parsed and made -> available to the LLM (via `bind_tools()`) and LangGraph internals, it's -> recommended to wrap the loaded tools using LangChain's -> [`StructuredTool`](https://python.langchain.com/api_reference/core/tools/langchain_core.tools.structured.StructuredTool.html). - -Here's a conceptual example adapting the [official LangGraph tool calling -guide](https://langchain-ai.github.io/langgraph/how-tos/tool-calling): - -```py -import asyncio -from typing import Annotated -from typing_extensions import TypedDict -from langchain_core.messages import HumanMessage, BaseMessage -from toolbox_core import ToolboxClient -from langchain_google_vertexai import ChatVertexAI -from langgraph.graph import StateGraph, START, END -from langgraph.prebuilt import ToolNode -from langchain.tools import StructuredTool -from langgraph.graph.message import add_messages - -class State(TypedDict): - messages: Annotated[list[BaseMessage], add_messages] - -async def main(): - async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tools = await toolbox.load_toolset() - wrapped_tools = [StructuredTool.from_function(tool, parse_docstring=True) for tool in tools] - model_with_tools = ChatVertexAI(model="gemini-3-flash-preview").bind_tools(wrapped_tools) - tool_node = ToolNode(wrapped_tools) - - def call_agent(state: State): - response = model_with_tools.invoke(state["messages"]) - return {"messages": [response]} - - def should_continue(state: State): - last_message = state["messages"][-1] - if last_message.tool_calls: - return "tools" - return END - - graph_builder = StateGraph(State) - - graph_builder.add_node("agent", call_agent) - graph_builder.add_node("tools", tool_node) - - graph_builder.add_edge(START, "agent") - graph_builder.add_conditional_edges( - "agent", - should_continue, - ) - graph_builder.add_edge("tools", "agent") - - app = graph_builder.compile() - - prompt = "What is the weather in London?" - inputs = {"messages": [HumanMessage(content=prompt)]} - - print(f"User: {prompt}\n") - print("--- Streaming Agent Steps ---") - - events = app.stream( - inputs, - stream_mode="values", - ) - - for event in events: - event["messages"][-1].pretty_print() - print("\n---\n") - -asyncio.run(main()) -``` - -## 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: +The core package provides a framework-agnostic way to interact with your Toolbox server. For detailed guides and advanced configuration, please visit the following sections on our [Documentation Site](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/): -- 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 `load_tool`) will likely fail with `Unauthorized` errors. - -### How it works - -The `ToolboxClient` (and `ToolboxSyncClient`) allows you to specify functions -(or coroutines for the async client) 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: - -```python -from toolbox_core import ToolboxClient - -async with ToolboxClient("toolbox-url", client_headers={"header1": header1_getter, "header2": header2_getter, ...}) as client: - # Use client - pass -``` - -### 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](src/toolbox_core/auth_methods.py) 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** - - ```python - from toolbox_core import auth_methods - - auth_token_provider = auth_methods.aget_google_id_token(URL) # can also use sync method - async with ToolboxClient( - URL, - client_headers={"Authorization": auth_token_provider}, - ) as client: - tools = await client.load_toolset() - - # Now, you can use the client as usual. - ``` - -## Authenticating Tools - -> [!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. - -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 (sync or async) 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). - -> [!IMPORTANT] -> 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. - -```py -async def get_auth_token(): - # ... 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 -``` - -> [!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. - -#### Option A: 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. - -```py -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tool = await toolbox.load_tool("my-tool") - - auth_tool = tool.add_auth_token_getter("my_auth", get_auth_token) # Single token - - # OR - - multi_auth_tool = tool.add_auth_token_getters({ - "my_auth_1": get_auth_token_1, - "my_auth_2": get_auth_token_2, - }) # Multiple tokens -``` - -#### Option B: Add Authentication While Loading Tools - -You can provide the token retriever(s) directly during the `load_tool` or -`load_toolset` 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. - -```py -auth_tool = await toolbox.load_tool(auth_token_getters={"my_auth": get_auth_token}) - -# OR - -auth_tools = await toolbox.load_toolset(auth_token_getters={"my_auth": get_auth_token}) -``` - -> [!NOTE] -> Adding auth tokens during loading only affect the tools loaded within that -> call. - -### Complete Authentication Example - -```py -import asyncio -from toolbox_core import ToolboxClient - -async def get_auth_token(): - # ... 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 - -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tool = await toolbox.load_tool("my-tool") - - auth_tool = tool.add_auth_token_getters({"my_auth": get_auth_token}) - result = auth_tool(input="some input") - print(result) -``` - -> [!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"). - -## 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. - -> [!IMPORTANT] -> 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. - -> [!NOTE] -> You do not need to modify the tool's configuration in the Toolbox service to -> bind parameter values using the SDK. - -### Option A: Binding Parameters to a Loaded Tool - -Bind values to a tool object *after* it has been loaded. This modifies the -specific tool instance. - -```py -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tool = await toolbox.load_tool("my-tool") - - bound_tool = tool.bind_param("param", "value") - - # OR - - bound_tool = tool.bind_params({"param": "value"}) -``` - -### Option B: 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. - -```py -bound_tool = await toolbox.load_tool("my-tool", bound_params={"param": "value"}) - -# OR - -bound_tools = await toolbox.load_toolset(bound_params={"param": "value"}) -``` - -> [!NOTE] -> Bound values during loading only affect the tools loaded in that call. - -### 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. - -```py -async def get_dynamic_value(): - # Logic to determine the value - return "dynamic_value" - -dynamic_bound_tool = tool.bind_param("param", get_dynamic_value) -``` +- [Transport Protocols](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/#transport-protocols) +- [Loading Tools](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/#loading-tools) +- [Invoking Tools](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/#invoking-tools) +- [Synchronous Usage](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/#synchronous-usage) +- [Use With Langraph](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/#use-with-langgraph) +- [Client to Server Authentication](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/#client-to-server-authentication) +- [Authenticating Tools](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/#authenticating-tools) +- [Binding Parameter Values](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/core/#parameter-binding) -> [!IMPORTANT] -> You don't need to modify tool configurations to bind parameter values. # Contributing diff --git a/packages/toolbox-langchain/README.md b/packages/toolbox-langchain/README.md index 7c38841c..47de9dbd 100644 --- a/packages/toolbox-langchain/README.md +++ b/packages/toolbox-langchain/README.md @@ -2,9 +2,11 @@ # MCP Toolbox LangChain SDK This SDK allows you to seamlessly integrate the functionalities of -[Toolbox](https://github.com/googleapis/genai-toolbox) into your LangChain LLM +[MCP Toolbox](https://github.com/googleapis/genai-toolbox) into your LangChain LLM applications, enabling advanced orchestration and interaction with GenAI models. +For detailed guides, authentication examples, and advanced configuration, visit the [Python SDK Langchain Guide](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/). + ## Table of Contents @@ -12,35 +14,9 @@ applications, enabling advanced orchestration and interaction with GenAI models. - [Installation](#installation) - [Quickstart](#quickstart) - [Usage](#usage) -- [Transport Protocols](#transport-protocols) - - [Supported Protocols](#supported-protocols) - - [Example](#example) -- [Loading Tools](#loading-tools) - - [Load a toolset](#load-a-toolset) - - [Load a single tool](#load-a-single-tool) -- [Use with LangChain](#use-with-langchain) -- [Use with LangGraph](#use-with-langgraph) - - [Represent Tools as Nodes](#represent-tools-as-nodes) - - [Connect Tools with LLM](#connect-tools-with-llm) -- [Manual usage](#manual-usage) -- [Client to Server Authentication](#client-to-server-authentication) - - [When is Client-to-Server Authentication Needed?](#when-is-client-to-server-authentication-needed) - - [How it works](#how-it-works) - - [Configuration](#configuration) - - [Authenticating with Google Cloud Servers](#authenticating-with-google-cloud-servers) - - [Step by Step Guide for Cloud Run](#step-by-step-guide-for-cloud-run) -- [Authenticating Tools](#authenticating-tools) - - [Supported Authentication Mechanisms](#supported-authentication-mechanisms) - - [Configure Tools](#configure-tools) - - [Configure SDK](#configure-sdk) - - [Add Authentication to a Tool](#add-authentication-to-a-tool) - - [Add Authentication While Loading](#add-authentication-while-loading) - - [Complete Example](#complete-example) -- [Binding Parameter Values](#binding-parameter-values) - - [Binding Parameters to a Tool](#binding-parameters-to-a-tool) - - [Binding Parameters While Loading](#binding-parameters-while-loading) - - [Binding Dynamic Values](#binding-dynamic-values) -- [Asynchronous Usage](#asynchronous-usage) +- [Contributing](#contributing) +- [License](#license) +- [Support](#support) @@ -76,412 +52,30 @@ async with ToolboxClient("http://127.0.0.1:5000") as toolbox: message.pretty_print() ``` -> [!TIP] -> For a complete, end-to-end example including setting up the service and using -> an SDK, see the full tutorial: [**Toolbox Quickstart -> Tutorial**](https://googleapis.github.io/genai-toolbox/getting-started/local_quickstart) - ## Usage -Import and initialize the toolbox client. - -```py -from toolbox_langchain import ToolboxClient - -# Replace with your Toolbox service's URL -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: -``` - -## 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 `protocol` 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. - -> [!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**. - -### Supported Protocols - -| Constant | Description | -| :--- | :--- | -| `Protocol.MCP` | **(Default)** Alias for the default MCP version (currently `2025-06-18`). | -| `Protocol.MCP_v20251125` | MCP Protocol version 2025-11-25. | -| `Protocol.MCP_v20250618` | MCP Protocol version 2025-06-18. | -| `Protocol.MCP_v20250326` | MCP Protocol version 2025-03-26. | -| `Protocol.MCP_v20241105` | MCP Protocol version 2024-11-05. | - -> [!WARNING] - -### Example - - -```py -from toolbox_langchain import ToolboxClient -from toolbox_core.protocol import Protocol - -async with ToolboxClient("http://127.0.0.1:5000", protocol=Protocol.MCP) as toolbox: - # Use client - pass -``` - -If you want to pin the MCP Version 2025-03-26: - -```py -from toolbox_langchain import ToolboxClient -from toolbox_core.protocol import Protocol - -async with ToolboxClient("http://127.0.0.1:5000", protocol=Protocol.MCP_v20250326) as toolbox: - # Use client - pass -``` - -## Loading Tools - -### Load a toolset - -A toolset is a collection of related tools. You can load all tools in a toolset -or a specific one: - -```py -# Load all tools -tools = toolbox.load_toolset() - -# Load a specific toolset -tools = toolbox.load_toolset("my-toolset") -``` - -### Load a single tool - -```py -tool = toolbox.load_tool("my-tool") -``` - -Loading individual tools gives you finer-grained control over which tools are -available to your LLM agent. - -## Use with LangChain +The toolbox-langchain package provids a dedicated integration to seamlessly load and use MCP Toolbox tools within the LangChain orchestration framework. For detailed guides and advanced configuration, please visit the following sections on our [Documentation Site](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain): -LangChain's agents can dynamically choose and execute tools based on the user -input. Include tools loaded from the Toolbox SDK in the agent's toolkit: +- [Transport Protocols](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/#transport-protocols) +- [Loading Tools](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/#loading-tools) +- [Use with Langchain](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/#use-with-langchain) +- [Use with Langraph](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/#use-with-langgraph) +- [Manual Usage](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/#manual-usage) +- [Client to Server Authentication](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/#client-to-server-authentication) +- [Authenticating Tools](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/#authenticating-tools) +- [Binding Parameter Values](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/#parameter-binding) +- [Asynchronous Usage](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/langchain/#asynchronous-usage) -```py -from langchain_google_vertexai import ChatVertexAI - -model = ChatVertexAI(model="gemini-3-flash-preview") - -# Initialize agent with tools -agent = model.bind_tools(tools) - -# Run the agent -result = agent.invoke("Do something with the tools") -``` +# Contributing -## Use with LangGraph +Contributions are welcome! Please refer to the [DEVELOPER.md](./DEVELOPER.md) +file for guidelines on how to set up a development environment and run tests. -Integrate the Toolbox SDK with LangGraph to use Toolbox service tools within a -graph-based workflow. Follow the [official -guide](https://langchain-ai.github.io/langgraph/) with minimal changes. - -### Represent Tools as Nodes - -Represent each tool as a LangGraph node, encapsulating the tool's execution within the node's functionality: - -```py -from toolbox_langchain import ToolboxClient -from langgraph.graph import StateGraph, MessagesState -from langgraph.prebuilt import ToolNode +# License -# Define the function that calls the model -def call_model(state: MessagesState): - messages = state['messages'] - response = model.invoke(messages) - return {"messages": [response]} # Return a list to add to existing messages +This project is licensed under the Apache License 2.0. See the +[LICENSE](https://github.com/googleapis/genai-toolbox/blob/main/LICENSE) file for details. -model = ChatVertexAI(model="gemini-3-flash-preview") -builder = StateGraph(MessagesState) -tool_node = ToolNode(tools) +# Support -builder.add_node("agent", call_model) -builder.add_node("tools", tool_node) -``` - -### Connect Tools with LLM - -Connect tool nodes with LLM nodes. The LLM decides which tool to use based on -input or context. Tool output can be fed back into the LLM: - -```py -from typing import Literal -from langgraph.graph import END, START -from langchain_core.messages import HumanMessage - -# Define the function that determines whether to continue or not -def should_continue(state: MessagesState) -> Literal["tools", END]: - messages = state['messages'] - last_message = messages[-1] - if last_message.tool_calls: - return "tools" # Route to "tools" node if LLM makes a tool call - return END # Otherwise, stop - -builder.add_edge(START, "agent") -builder.add_conditional_edges("agent", should_continue) -builder.add_edge("tools", 'agent') - -graph = builder.compile() - -graph.invoke({"messages": [HumanMessage(content="Do something with the tools")]}) -``` - -## Manual usage - -Execute a tool manually using the `invoke` method: - -```py -result = tools[0].invoke({"name": "Alice", "age": 30}) -``` - -This is useful for testing tools or when you need precise control over tool -execution outside of an agent framework. - -## 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 `load_tool`) will likely fail with `Unauthorized` errors. - -### How it works - -The `ToolboxClient` allows you to specify functions (or coroutines for the async -client) 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 follows: - -```python -from toolbox_langchain import ToolboxClient - -async with ToolboxClient( - "toolbox-url", - client_headers={"header1": header1_getter, "header2": header2_getter, ...} -) as client: -``` - -### 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](src/toolbox_core/auth_methods.py) 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** - - ```python - from toolbox_langchain import ToolboxClient - from toolbox_core import auth_methods - - auth_token_provider = auth_methods.aget_google_id_token(URL) # can also use sync method - async with ToolboxClient( - URL, - client_headers={"Authorization": auth_token_provider}, - ) as client: - tools = client.load_toolset() - - # Now, you can use the client as usual. - ``` - - -## Authenticating Tools - -> [!WARNING] -> Always use HTTPS to connect your application with the Toolbox service, -> especially when using tools with authentication configured. Using HTTP exposes -> your application to serious security risks. - -Some tools require user authentication to access sensitive data. - -### Supported Authentication Mechanisms -Toolbox currently supports authentication using the [OIDC -protocol](https://openid.net/specs/openid-connect-core-1_0.html) with [ID -tokens](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) (not -access tokens) for [Google OAuth -2.0](https://cloud.google.com/apigee/docs/api-platform/security/oauth/oauth-home). - -### Configure Tools - -Refer to [these -instructions](https://googleapis.github.io/genai-toolbox/resources/tools/#authenticated-parameters) on -configuring tools for authenticated parameters. - -### Configure SDK - -You need a method to retrieve an ID token from your authentication service: - -```py -async def get_auth_token(): - # ... 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 -``` - -#### Add Authentication to a Tool - -```py -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tools = toolbox.load_toolset() - - auth_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token) # Single token - - multi_auth_tool = tools[0].add_auth_token_getters({"auth_1": get_auth_1}, {"auth_2": get_auth_2}) # Multiple tokens - - # OR - - auth_tools = [tool.add_auth_token_getter("my_auth", get_auth_token) for tool in tools] -``` - -#### Add Authentication While Loading - -```py -auth_tool = toolbox.load_tool(auth_token_getters={"my_auth": get_auth_token}) - -auth_tools = toolbox.load_toolset(auth_token_getters={"my_auth": get_auth_token}) -``` - -> [!NOTE] -> Adding auth tokens during loading only affect the tools loaded within -> that call. - -### Complete Example - -```py -import asyncio -from toolbox_langchain import ToolboxClient - -async def get_auth_token(): - # ... 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 - -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tool = toolbox.load_tool("my-tool") - - auth_tool = tool.add_auth_token_getter("my_auth", get_auth_token) - result = auth_tool.invoke({"input": "some input"}) - print(result) -``` - -## Binding Parameter Values - -Predetermine values for tool parameters using the SDK. These values won't be -modified by the LLM. This is useful for: - -* **Protecting sensitive information:** API keys, secrets, etc. -* **Enforcing consistency:** Ensuring specific values for certain parameters. -* **Pre-filling known data:** Providing defaults or context. - -### Binding Parameters to a Tool - -```py -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tools = toolbox.load_toolset() - - bound_tool = tool[0].bind_param("param", "value") # Single param - - multi_bound_tool = tools[0].bind_params({"param1": "value1", "param2": "value2"}) # Multiple params - - # OR - - bound_tools = [tool.bind_param("param", "value") for tool in tools] -``` - -### Binding Parameters While Loading - -```py -bound_tool = toolbox.load_tool("my-tool", bound_params={"param": "value"}) - -bound_tools = toolbox.load_toolset(bound_params={"param": "value"}) -``` - -> [!NOTE] -> Bound values during loading only affect the tools loaded in that call. - -### Binding Dynamic Values - -Use a function to bind dynamic values: - -```py -def get_dynamic_value(): - # Logic to determine the value - return "dynamic_value" - -dynamic_bound_tool = tool.bind_param("param", get_dynamic_value) -``` - -> [!IMPORTANT] -> You don't need to modify tool configurations to bind parameter values. - -## Asynchronous Usage - -For better performance through [cooperative -multitasking](https://en.wikipedia.org/wiki/Cooperative_multitasking), you can -use the asynchronous interfaces of the `ToolboxClient`. - -> [!Note] -> Asynchronous interfaces like `aload_tool` and `aload_toolset` require an -> asynchronous environment. For guidance on running asynchronous Python -> programs, see [asyncio -> documentation](https://docs.python.org/3/library/asyncio-runner.html#running-an-asyncio-program). - -```py -import asyncio -from toolbox_langchain import ToolboxClient - -async def main(): - async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tool = await client.aload_tool("my-tool") - tools = await client.aload_toolset() - response = await tool.ainvoke() - -if __name__ == "__main__": - asyncio.run(main()) -``` +If you encounter issues or have questions, check the existing [GitHub Issues](https://github.com/googleapis/genai-toolbox/issues) for the main Toolbox project. \ No newline at end of file diff --git a/packages/toolbox-llamaindex/README.md b/packages/toolbox-llamaindex/README.md index eb26862b..ab58ec0c 100644 --- a/packages/toolbox-llamaindex/README.md +++ b/packages/toolbox-llamaindex/README.md @@ -2,9 +2,11 @@ # MCP Toolbox LlamaIndex SDK This SDK allows you to seamlessly integrate the functionalities of -[Toolbox](https://github.com/googleapis/genai-toolbox) into your LlamaIndex LLM +[MCP Toolbox](https://github.com/googleapis/genai-toolbox) into your LlamaIndex LLM applications, enabling advanced orchestration and interaction with GenAI models. +For detailed guides, authentication examples, and advanced configuration, visit the [Python SDK LlamaIndex Guide](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/). + ## Table of Contents @@ -12,33 +14,9 @@ applications, enabling advanced orchestration and interaction with GenAI models. - [Installation](#installation) - [Quickstart](#quickstart) - [Usage](#usage) -- [Transport Protocols](#transport-protocols) - - [Supported Protocols](#supported-protocols) - - [Example](#example) -- [Loading Tools](#loading-tools) - - [Load a toolset](#load-a-toolset) - - [Load a single tool](#load-a-single-tool) -- [Use with LlamaIndex](#use-with-llamaindex) - - [Maintain state](#maintain-state) -- [Manual usage](#manual-usage) -- [Client to Server Authentication](#client-to-server-authentication) - - [When is Client-to-Server Authentication Needed?](#when-is-client-to-server-authentication-needed) - - [How it works](#how-it-works) - - [Configuration](#configuration) - - [Authenticating with Google Cloud Servers](#authenticating-with-google-cloud-servers) - - [Step by Step Guide for Cloud Run](#step-by-step-guide-for-cloud-run) -- [Authenticating Tools](#authenticating-tools) - - [Supported Authentication Mechanisms](#supported-authentication-mechanisms) - - [Configure Tools](#configure-tools) - - [Configure SDK](#configure-sdk) - - [Add Authentication to a Tool](#add-authentication-to-a-tool) - - [Add Authentication While Loading](#add-authentication-while-loading) - - [Complete Example](#complete-example) -- [Binding Parameter Values](#binding-parameter-values) - - [Binding Parameters to a Tool](#binding-parameters-to-a-tool) - - [Binding Parameters While Loading](#binding-parameters-while-loading) - - [Binding Dynamic Values](#binding-dynamic-values) -- [Asynchronous Usage](#asynchronous-usage) +- [Contributing](#contributing) +- [License](#license) +- [Support](#support) @@ -80,386 +58,30 @@ async def run_agent(): asyncio.run(run_agent()) ``` -> [!TIP] -> For a complete, end-to-end example including setting up the service and using -> an SDK, see the full tutorial: [**Toolbox Quickstart -> Tutorial**](https://googleapis.github.io/genai-toolbox/getting-started/local_quickstart) - ## Usage -Import and initialize the toolbox client. - -```py -from toolbox_llamaindex import ToolboxClient - -# Replace with your Toolbox service's URL -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: -``` - -## 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 `protocol` 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. - -> [!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**. - -### Supported Protocols - -| Constant | Description | -| :--- | :--- | -| `Protocol.MCP` | **(Default)** Alias for the default MCP version (currently `2025-06-18`). | -| `Protocol.MCP_v20251125` | MCP Protocol version 2025-11-25. | -| `Protocol.MCP_v20250618` | MCP Protocol version 2025-06-18. | -| `Protocol.MCP_v20250326` | MCP Protocol version 2025-03-26. | -| `Protocol.MCP_v20241105` | MCP Protocol version 2024-11-05. | - -> [!WARNING] - -### Example - - -```py -from toolbox_llamaindex import ToolboxClient -from toolbox_core.protocol import Protocol - -async with ToolboxClient("http://127.0.0.1:5000", protocol=Protocol.MCP) as toolbox: - # Use client - pass -``` - -If you want to pin the MCP Version 2025-03-26: - -```py -from toolbox_llamaindex import ToolboxClient -from toolbox_core.protocol import Protocol - -async with ToolboxClient("http://127.0.0.1:5000", protocol=Protocol.MCP_v20250326) as toolbox: - # Use client - pass -``` +The toolbox-llamaindex package provides a dedicated integration to seamlessly load and use MCP Toolbox tools within the LlamaIndex orchestration framework ( source). For detailed guides and advanced configuration, please visit the following sections on our [Documentation Site](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/): -## Loading Tools -### Load a toolset +- [Transport Protocols](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/#transport-protocols) +- [Loading Tools](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/#loading-tools) +- [Use with LlamaIndex](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/#use-with-llamaindex) +- [Manual Usage](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/#manual-usage) +- [Client to Server Authentication](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/#client-to-server-authentication) +- [Authenticating Tools](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/#authenticating-tools) +- [Binding Parameter Values](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/#parameter-binding) +- [Asynchronous Usage](https://googleapis.github.io/genai-toolbox/sdks/python-sdk/llamaindex/#asynchronous-usage) -A toolset is a collection of related tools. You can load all tools in a toolset -or a specific one: +# Contributing -```py -# Load all tools -tools = toolbox.load_toolset() +Contributions are welcome! Please refer to the [DEVELOPER.md](./DEVELOPER.md) +file for guidelines on how to set up a development environment and run tests. -# Load a specific toolset -tools = toolbox.load_toolset("my-toolset") -``` - -### Load a single tool - -```py -tool = toolbox.load_tool("my-tool") -``` - -Loading individual tools gives you finer-grained control over which tools are -available to your LLM agent. - -## Use with LlamaIndex - -LlamaIndex's agents can dynamically choose and execute tools based on the user -input. Include tools loaded from the Toolbox SDK in the agent's toolkit: - -```py -from llama_index.llms.google_genai import GoogleGenAI -from llama_index.core.agent.workflow import AgentWorkflow - -vertex_model = GoogleGenAI( - model="gemini-3-flash-preview", - vertexai_config={"project": "project-id", "location": "us-central1"}, -) - -# Initialize agent with tools -agent = AgentWorkflow.from_tools_or_functions( - tools, - llm=vertex_model, - system_prompt="You are a helpful assistant.", -) - -# Query the agent -response = await agent.run(user_msg="Get some response from the agent.") -print(response) -``` - -### Maintain state - -To maintain state for the agent, add context as follows: - -```py -from llama_index.core.agent.workflow import AgentWorkflow -from llama_index.core.workflow import Context -from llama_index.llms.google_genai import GoogleGenAI - -vertex_model = GoogleGenAI( - model="gemini-3-flash-preview", - vertexai_config={"project": "project-id", "location": "us-central1"}, -) -agent = AgentWorkflow.from_tools_or_functions( - tools, - llm=vertex_model, - system_prompt="You are a helpful assistant", -) - -# Save memory in agent context -ctx = Context(agent) -response = await agent.run(user_msg="Give me some response.", ctx=ctx) -print(response) -``` - -## Manual usage - -Execute a tool manually using the `call` method: - -```py -result = tools[0].call(name="Alice", age=30) -``` - -This is useful for testing tools or when you need precise control over tool -execution outside of an agent framework. - -## 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 `load_tool`) will likely fail with `Unauthorized` errors. - -### How it works - -The `ToolboxClient` allows you to specify functions (or coroutines for the async -client) 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 follows: - -```python -from toolbox_llamaindex import ToolboxClient - -async with ToolboxClient( - "toolbox-url", - client_headers={"header1": header1_getter, "header2": header2_getter, ...} -) as client: -``` +# License -### Authenticating with Google Cloud Servers +This project is licensed under the Apache License 2.0. See the +[LICENSE](https://github.com/googleapis/genai-toolbox/blob/main/LICENSE) file for details. -For Toolbox servers hosted on Google Cloud (e.g., Cloud Run) and requiring -`Google ID token` authentication, the helper module -[auth_methods](src/toolbox_core/auth_methods.py) provides utility functions. +# Support -### 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** - - ```python - from toolbox_llamaindex import ToolboxClient - from toolbox_core import auth_methods - - auth_token_provider = auth_methods.aget_google_id_token(URL) - async with ToolboxClient( - URL, - client_headers={"Authorization": auth_token_provider}, - ) as client: - tools = await client.aload_toolset() - - # Now, you can use the client as usual. - ``` - -## Authenticating Tools - -> [!WARNING] -> Always use HTTPS to connect your application with the Toolbox service, -> especially when using tools with authentication configured. Using HTTP exposes -> your application to serious security risks. - -Some tools require user authentication to access sensitive data. - -### Supported Authentication Mechanisms -Toolbox currently supports authentication using the [OIDC -protocol](https://openid.net/specs/openid-connect-core-1_0.html) with [ID -tokens](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) (not -access tokens) for [Google OAuth -2.0](https://cloud.google.com/apigee/docs/api-platform/security/oauth/oauth-home). - -### Configure Tools - -Refer to [these -instructions](https://googleapis.github.io/genai-toolbox/resources/tools/#authenticated-parameters) on -configuring tools for authenticated parameters. - -### Configure SDK - -You need a method to retrieve an ID token from your authentication service: - -```py -async def get_auth_token(): - # ... 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 -``` - -#### Add Authentication to a Tool - -```py -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tools = toolbox.load_toolset() - - auth_tool = tools[0].add_auth_token_getter("my_auth", get_auth_token) # Single token - - multi_auth_tool = tools[0].add_auth_token_getters({"auth_1": get_auth_1}, {"auth_2": get_auth_2}) # Multiple tokens - - # OR - - auth_tools = [tool.add_auth_token_getter("my_auth", get_auth_token) for tool in tools] -``` - -#### Add Authentication While Loading - -```py -auth_tool = toolbox.load_tool(auth_token_getters={"my_auth": get_auth_token}) - -auth_tools = toolbox.load_toolset(auth_token_getters={"my_auth": get_auth_token}) -``` - -> [!NOTE] -> Adding auth tokens during loading only affect the tools loaded within -> that call. - -### Complete Example - -```py -import asyncio -from toolbox_llamaindex import ToolboxClient - -async def get_auth_token(): - # ... 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 - -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tool = toolbox.load_tool("my-tool") - - auth_tool = tool.add_auth_token_getter("my_auth", get_auth_token) - result = auth_tool.call(input="some input") - print(result) -``` - -## Binding Parameter Values - -Predetermine values for tool parameters using the SDK. These values won't be -modified by the LLM. This is useful for: - -* **Protecting sensitive information:** API keys, secrets, etc. -* **Enforcing consistency:** Ensuring specific values for certain parameters. -* **Pre-filling known data:** Providing defaults or context. - -### Binding Parameters to a Tool - -```py -async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tools = toolbox.load_toolset() - - bound_tool = tool[0].bind_param("param", "value") # Single param - - multi_bound_tool = tools[0].bind_params({"param1": "value1", "param2": "value2"}) # Multiple params - - # OR - - bound_tools = [tool.bind_param("param", "value") for tool in tools] -``` - -### Binding Parameters While Loading - -```py -bound_tool = toolbox.load_tool("my-tool", bound_params={"param": "value"}) - -bound_tools = toolbox.load_toolset(bound_params={"param": "value"}) -``` - -> [!NOTE] -> Bound values during loading only affect the tools loaded in that call. - -### Binding Dynamic Values - -Use a function to bind dynamic values: - -```py -def get_dynamic_value(): - # Logic to determine the value - return "dynamic_value" - -dynamic_bound_tool = tool.bind_param("param", get_dynamic_value) -``` - -> [!IMPORTANT] -> You don't need to modify tool configurations to bind parameter values. - -## Asynchronous Usage - -For better performance through [cooperative -multitasking](https://en.wikipedia.org/wiki/Cooperative_multitasking), you can -use the asynchronous interfaces of the `ToolboxClient`. - -> [!Note] -> Asynchronous interfaces like `aload_tool` and `aload_toolset` require an -> asynchronous environment. For guidance on running asynchronous Python -> programs, see [asyncio -> documentation](https://docs.python.org/3/library/asyncio-runner.html#running-an-asyncio-program). - -```py -import asyncio -from toolbox_llamaindex import ToolboxClient - -async def main(): - async with ToolboxClient("http://127.0.0.1:5000") as toolbox: - tool = await client.aload_tool("my-tool") - tools = await client.aload_toolset() - response = await tool.ainvoke() - -if __name__ == "__main__": - asyncio.run(main()) -``` +If you encounter issues or have questions, check the existing [GitHub Issues](https://github.com/googleapis/genai-toolbox/issues) for the main Toolbox project. \ No newline at end of file