- Notifications
You must be signed in to change notification settings - Fork32
feat: simplifyToolboxToolset lazy init and use private attributes#472
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Open
anubhav756 wants to merge18 commits intodocs/toolbox-adk-readmeChoose a base branch fromfeat/toolbox-adk-package
base:docs/toolbox-adk-readme
Could not load branches
Branch not found:{{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline, and old review comments may become outdated.
Uh oh!
There was an error while loading.Please reload this page.
Open
Changes fromall commits
Commits
Show all changes
18 commits Select commitHold shift + click to select a range
c7e6d4d chore(deps): update dependency langchain-core to v1.2.0 (#465)
renovate-botedb522d chore(deps): update actions/upload-artifact action to v6 (#466)
renovate-botba45b32 chore(deps): update python-nonmajor (#467)
renovate-bot475103f chore(deps): update dependency langchain-core to v1.2.2 (#469)
renovate-bot7da5271 feat(adk): Package scaffolding & setup
anubhav756b29323c chore(toolbox-adk): address PR #454 feedback (version, readme, metadata)
anubhav756e2e76e5 feat(adk): Implement core data classes
anubhav7560b89f9f fix: apply PR feedback for credentials (casing and types)
anubhav756757cd04 feat(adk): Implement client wrapper
anubhav756323af49 refactor(adk): rename APPLICATION_DEFAULT_CREDENTIALS to WORKLOAD_IDE…
anubhav7564f02037 refactor(adk): rename CredentialStrategy methods to snake_case
anubhav756e4e0457 feat(adk): Implement tool wrapper & auth getters
anubhav756a102b70 test(toolbox-adk): Implement parity integration tests
anubhav756e3b4dab feat(toolbox-adk): Add ADK credential factory methods
anubhav756e070de4 feat(toolbox-adk): Add ADK credential factory methods
anubhav7564260ed1 feat(toolbox-adk): Add ADK credential factory methods
anubhav7562560c29 feat: simplify ToolboxToolset lazy init and use private attributes
anubhav756ee00c24 fix: update tests for lazy ToolboxToolset and strict private attributes
anubhav756File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,224 @@ | ||
|  | ||
| # Toolbox ADK Integration | ||
| 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. | ||
| ## Installation | ||
| ```bash | ||
| 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. | ||
| > [!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. | ||
| This section describes how to configure and use the `ToolboxToolset`. | ||
| ### Creating the Toolset | ||
| Once you have configured your credentials, you can create an instance of `ToolboxToolset`. | ||
| ```python | ||
| from toolbox_adk import ToolboxToolset, CredentialStrategy | ||
| from google.adk.agents import Agent | ||
| # 1. Configure Authentication Strategy | ||
| # Use the agent's own identity (Workload Identity) | ||
| creds = CredentialStrategy.workload_identity(target_audience="https://my-toolbox-service-url") | ||
| # 2. Create the Toolset | ||
| toolset = ToolboxToolset( | ||
| server_url="https://my-toolbox-service-url", | ||
| toolset_name="my-toolset", # Optional: Load specific toolset | ||
| credentials=creds | ||
| ) | ||
| # 3. Use in your ADK Agent | ||
| agent = Agent(tools=[toolset]) | ||
| ``` | ||
| ## Authentication Strategies | ||
| The `toolbox-adk` package provides flexible authentication strategies to handle `Client-to-Server` authentication (securing the connection to the Toolbox server) and `User Identity` propagation (authenticating the user for specific tools). | ||
| Use the `CredentialStrategy` factory methods to create your configuration. | ||
| ### Workload Identity (Recommended for Cloud Run / GKE) | ||
| Uses the agent's environment credentials (ADC) to generate an OIDC ID token. This is the standard way for one service to authenticate to another on Google Cloud. | ||
| ```python | ||
| # target_audience should match 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 | ||
| ) | ||
| ``` | ||
| ### User Identity (3-Legged OAuth) | ||
| Propagates the end-user's identity to the Toolbox. This is used when the tools themselves need to act on behalf of the user (e.g., accessing the user's Drive or Calendar). | ||
| You can optionally specify a `header_name` if your Toolbox server or proxy expects the user token in a different header (e.g., `X-Looker-Token`). Defaults to `Authorization`. | ||
| ```python | ||
| creds = CredentialStrategy.user_identity( | ||
| client_id="YOUR_CLIENT_ID", | ||
| client_secret="YOUR_CLIENT_SECRET", | ||
| scopes=["https://www.googleapis.com/auth/drive"], | ||
| # Optional: Specify a custom header (default is Authorization) | ||
| # header_name="X-Looker-Token" | ||
| ) | ||
| ``` | ||
| ### Manual Token (Development / Testing) | ||
| Manually supply a token (e.g., a static API key or a temporary token). | ||
| ```python | ||
| creds = CredentialStrategy.manual_token(token="my-secret-token") | ||
| ``` | ||
| ### Manual Credentials Object | ||
| Uses a provided `google.auth` Credentials object directly. | ||
| ```python | ||
| from google.oauth2 import service_account | ||
| my_creds = service_account.Credentials.from_service_account_file('key.json') | ||
| creds = CredentialStrategy.manual_credentials(my_creds) | ||
| ``` | ||
| ### API Key | ||
| Use a static API key passed in a specific header (default: `X-API-Key`). | ||
| ```python | ||
| # 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") | ||
| ``` | ||
| ### Toolbox Identity (No Auth) | ||
| Use this if your Toolbox server does not require authentication (e.g., local development). | ||
| ```python | ||
| creds = CredentialStrategy.toolbox_identity() | ||
| ``` | ||
| ### Native ADK Integration | ||
| If you are using ADK's configuration system (`AuthConfig` objects), you can create the strategy directly from it. | ||
| ```python | ||
| # auth_config is an instance of google.adk.auth.auth_tool.AuthConfig | ||
| creds = CredentialStrategy.from_adk_auth_config(auth_config) | ||
| ``` | ||
| Or if you have the `AuthScheme` and `AuthCredential` objects separately: | ||
| ```python | ||
| # scheme is google.adk.auth.auth_tool.AuthScheme | ||
| # credential is google.adk.auth.auth_credential.AuthCredential | ||
| creds = CredentialStrategy.from_adk_credentials(auth_credential, scheme) | ||
| ``` | ||
| ## 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. | ||
| ```python | ||
| toolset = ToolboxToolset( | ||
| server_url="...", | ||
| bound_params={ | ||
| "region": "us-central1", | ||
| "api_key": lambda: get_api_key() # Can be a callable | ||
| } | ||
| ) | ||
| ``` | ||
| ### Auth Token Getters | ||
| 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 | ||
| } | ||
| ) | ||
| ``` | ||
| ### Usage with Hooks | ||
| You can attach `pre_hook` and `post_hook` functions to execute logic before and after every tool invocation. | ||
| > [!NOTE] | ||
| > The `pre_hook` can modify `context.arguments` to dynamically alter the inputs passed to the tool. | ||
| ```python | ||
| from toolbox_adk import ToolboxContext | ||
| async def log_start(context: ToolboxContext): | ||
| print(f"Starting tool with args: {context.arguments}") | ||
| # context.tool_context is the underlying ADK ToolContext | ||
| # Example: Inject or modify arguments | ||
| # context.arguments["user_id"] = "123" | ||
| async def log_end(context: ToolboxContext): | ||
| print("Finished tool execution") | ||
| # Inspect result or error | ||
| if context.error: | ||
| print(f"Tool failed: {context.error}") | ||
| toolset = ToolboxToolset( | ||
| server_url="...", | ||
| pre_hook=log_start, | ||
| post_hook=log_end | ||
| ) | ||
| ``` | ||
| ## Contributing | ||
| Contributions are welcome! Please refer to the `toolbox-core` [DEVELOPER.md](../toolbox-core/DEVELOPER.md) for general guidelines. | ||
| ## License | ||
| This project is licensed under the Apache License 2.0. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # Copyright 2025 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| steps: | ||
| - id: Install library requirements | ||
| name: 'python:${_VERSION}' | ||
| dir: 'packages/toolbox-adk' | ||
| args: | ||
| - install | ||
| - '-r' | ||
| - 'requirements.txt' | ||
| - '--user' | ||
| entrypoint: pip | ||
| - id: Install test requirements | ||
| name: 'python:${_VERSION}' | ||
| args: | ||
| - install | ||
| - '-e' | ||
| - 'packages/toolbox-adk[test]' | ||
| - '--user' | ||
| entrypoint: pip | ||
| - id: Run integration tests | ||
| name: 'python:${_VERSION}' | ||
| dir: 'packages/toolbox-adk' | ||
| env: | ||
| - TOOLBOX_URL=$_TOOLBOX_URL | ||
| - TOOLBOX_VERSION=$_TOOLBOX_VERSION | ||
| - GOOGLE_CLOUD_PROJECT=$PROJECT_ID | ||
| - TOOLBOX_MANIFEST_VERSION=${_TOOLBOX_MANIFEST_VERSION} | ||
| args: | ||
| - '-c' | ||
| - >- | ||
| python -m pytest --cov=src/toolbox_adk --cov-report=term --cov-fail-under=90 tests/ | ||
| entrypoint: /bin/bash | ||
| options: | ||
| logging: CLOUD_LOGGING_ONLY | ||
| substitutions: | ||
| _VERSION: '3.13' | ||
| # Default values (can be overridden by triggers) | ||
| _TOOLBOX_VERSION: '0.22.0' | ||
| _TOOLBOX_MANIFEST_VERSION: '34' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| [project] | ||
| name = "toolbox-adk" | ||
| dynamic = ["version"] | ||
| description = "Agent Development Kit Integration for MCP Toolbox" | ||
| readme = "README.md" | ||
| authors = [{name = "Google LLC", email = "googleapis-packages@google.com"}] | ||
| license = {file = "LICENSE"} | ||
| classifiers = [ | ||
| "Intended Audience :: Developers", | ||
| "License :: OSI Approved :: Apache Software License", | ||
| "Programming Language :: Python", | ||
| "Programming Language :: Python :: 3", | ||
| "Programming Language :: Python :: 3.10", | ||
| "Programming Language :: Python :: 3.11", | ||
| "Programming Language :: Python :: 3.12", | ||
| "Programming Language :: Python :: 3.13", | ||
| "Operating System :: OS Independent", | ||
| ] | ||
| requires-python = ">=3.10" | ||
| dependencies = [ | ||
| "toolbox-core>=0.5.4", | ||
| "google-auth>=2.43.0,<3.0.0", | ||
| "google-auth-oauthlib>=1.2.0,<2.0.0", | ||
| "google-adk>=1.20.0,<2.0.0", | ||
| "typing-extensions>=4.0.0" | ||
| ] | ||
| [project.urls] | ||
| Homepage = "https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-adk" | ||
| Repository = "https://github.com/googleapis/mcp-toolbox-sdk-python.git" | ||
| "Bug Tracker" = "https://github.com/googleapis/mcp-toolbox-sdk-python/issues" | ||
| Changelog = "https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-adk/CHANGELOG.md" | ||
| [project.optional-dependencies] | ||
| test = [ | ||
| "black[jupyter]==25.11.0", | ||
| "isort==7.0.0", | ||
| "mypy==1.19.0", | ||
| "pytest==9.0.1", | ||
| "pytest-asyncio==1.3.0", | ||
| "pytest-cov==7.0.0", | ||
| "pytest-mock==3.15.1" | ||
| ] | ||
| # Tells setuptools that packages are under the 'src' directory | ||
| [tool.setuptools] | ||
| package-dir = {"" = "src"} | ||
| [tool.setuptools.dynamic] | ||
| version = {attr = "toolbox_adk.version.__version__"} | ||
| [build-system] | ||
| requires = ["setuptools>=61.0"] | ||
| build-backend = "setuptools.build_meta" | ||
| [tool.black] | ||
| target-version = ['py310'] | ||
| [tool.isort] | ||
| profile = "black" | ||
| [tool.mypy] | ||
| python_version = "3.10" | ||
| warn_unused_configs = true | ||
| disallow_incomplete_defs = true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| -e ../toolbox-core | ||
| google-auth==2.43.0 | ||
| google-auth-oauthlib==1.2.1 | ||
| google-adk==1.20.0 | ||
| typing-extensions==4.12.2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Copyright 2025 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| from .client import ToolboxClient | ||
| from .credentials import CredentialConfig, CredentialStrategy, CredentialType | ||
| from .tool import ToolboxContext, ToolboxTool | ||
| from .toolset import ToolboxToolset | ||
| from .version import __version__ | ||
| __all__ = [ | ||
| "CredentialStrategy", | ||
| "CredentialConfig", | ||
| "CredentialType", | ||
| "ToolboxClient", | ||
| "ToolboxTool", | ||
| "ToolboxContext", | ||
| "ToolboxToolset", | ||
| ] |
Oops, something went wrong.
Uh oh!
There was an error while loading.Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.