This is page 3 of 33. Use http://codebase.md/googleapis/genai-toolbox?page={x} to view the full context. # Directory Structure ``` ├── .ci │ ├── continuous.release.cloudbuild.yaml │ ├── generate_release_table.sh │ ├── integration.cloudbuild.yaml │ ├── quickstart_test │ │ ├── go.integration.cloudbuild.yaml │ │ ├── js.integration.cloudbuild.yaml │ │ ├── py.integration.cloudbuild.yaml │ │ ├── run_go_tests.sh │ │ ├── run_js_tests.sh │ │ ├── run_py_tests.sh │ │ └── setup_hotels_sample.sql │ ├── test_with_coverage.sh │ └── versioned.release.cloudbuild.yaml ├── .github │ ├── auto-label.yaml │ ├── blunderbuss.yml │ ├── CODEOWNERS │ ├── header-checker-lint.yml │ ├── ISSUE_TEMPLATE │ │ ├── bug_report.yml │ │ ├── config.yml │ │ ├── feature_request.yml │ │ └── question.yml │ ├── label-sync.yml │ ├── labels.yaml │ ├── PULL_REQUEST_TEMPLATE.md │ ├── release-please.yml │ ├── renovate.json5 │ ├── sync-repo-settings.yaml │ └── workflows │ ├── cloud_build_failure_reporter.yml │ ├── deploy_dev_docs.yaml │ ├── deploy_previous_version_docs.yaml │ ├── deploy_versioned_docs.yaml │ ├── docs_deploy.yaml │ ├── docs_preview_clean.yaml │ ├── docs_preview_deploy.yaml │ ├── lint.yaml │ ├── schedule_reporter.yml │ ├── sync-labels.yaml │ └── tests.yaml ├── .gitignore ├── .gitmodules ├── .golangci.yaml ├── .hugo │ ├── archetypes │ │ └── default.md │ ├── assets │ │ ├── icons │ │ │ └── logo.svg │ │ └── scss │ │ ├── _styles_project.scss │ │ └── _variables_project.scss │ ├── go.mod │ ├── go.sum │ ├── hugo.toml │ ├── layouts │ │ ├── _default │ │ │ └── home.releases.releases │ │ ├── index.llms-full.txt │ │ ├── index.llms.txt │ │ ├── partials │ │ │ ├── hooks │ │ │ │ └── head-end.html │ │ │ ├── navbar-version-selector.html │ │ │ ├── page-meta-links.html │ │ │ └── td │ │ │ └── render-heading.html │ │ ├── robot.txt │ │ └── shortcodes │ │ ├── include.html │ │ ├── ipynb.html │ │ └── regionInclude.html │ ├── package-lock.json │ ├── package.json │ └── static │ ├── favicons │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ └── favicon.ico │ └── js │ └── w3.js ├── CHANGELOG.md ├── cmd │ ├── options_test.go │ ├── options.go │ ├── root_test.go │ ├── root.go │ └── version.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DEVELOPER.md ├── Dockerfile ├── docs │ └── en │ ├── _index.md │ ├── about │ │ ├── _index.md │ │ └── faq.md │ ├── concepts │ │ ├── _index.md │ │ └── telemetry │ │ ├── index.md │ │ ├── telemetry_flow.png │ │ └── telemetry_traces.png │ ├── getting-started │ │ ├── _index.md │ │ ├── colab_quickstart.ipynb │ │ ├── configure.md │ │ ├── introduction │ │ │ ├── _index.md │ │ │ └── architecture.png │ │ ├── local_quickstart_go.md │ │ ├── local_quickstart_js.md │ │ ├── local_quickstart.md │ │ ├── mcp_quickstart │ │ │ ├── _index.md │ │ │ ├── inspector_tools.png │ │ │ └── inspector.png │ │ └── quickstart │ │ ├── go │ │ │ ├── genAI │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ └── quickstart.go │ │ │ ├── genkit │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ └── quickstart.go │ │ │ ├── langchain │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ └── quickstart.go │ │ │ ├── openAI │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ └── quickstart.go │ │ │ └── quickstart_test.go │ │ ├── golden.txt │ │ ├── js │ │ │ ├── genAI │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ └── quickstart.js │ │ │ ├── genkit │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ └── quickstart.js │ │ │ ├── langchain │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ └── quickstart.js │ │ │ ├── llamaindex │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ └── quickstart.js │ │ │ └── quickstart.test.js │ │ ├── python │ │ │ ├── __init__.py │ │ │ ├── adk │ │ │ │ ├── quickstart.py │ │ │ │ └── requirements.txt │ │ │ ├── core │ │ │ │ ├── quickstart.py │ │ │ │ └── requirements.txt │ │ │ ├── langchain │ │ │ │ ├── quickstart.py │ │ │ │ └── requirements.txt │ │ │ ├── llamaindex │ │ │ │ ├── quickstart.py │ │ │ │ └── requirements.txt │ │ │ └── quickstart_test.py │ │ └── shared │ │ ├── cloud_setup.md │ │ ├── configure_toolbox.md │ │ └── database_setup.md │ ├── how-to │ │ ├── _index.md │ │ ├── connect_via_geminicli.md │ │ ├── connect_via_mcp.md │ │ ├── connect-ide │ │ │ ├── _index.md │ │ │ ├── alloydb_pg_admin_mcp.md │ │ │ ├── alloydb_pg_mcp.md │ │ │ ├── bigquery_mcp.md │ │ │ ├── cloud_sql_mssql_admin_mcp.md │ │ │ ├── cloud_sql_mssql_mcp.md │ │ │ ├── cloud_sql_mysql_admin_mcp.md │ │ │ ├── cloud_sql_mysql_mcp.md │ │ │ ├── cloud_sql_pg_admin_mcp.md │ │ │ ├── cloud_sql_pg_mcp.md │ │ │ ├── firestore_mcp.md │ │ │ ├── looker_mcp.md │ │ │ ├── mssql_mcp.md │ │ │ ├── mysql_mcp.md │ │ │ ├── neo4j_mcp.md │ │ │ ├── postgres_mcp.md │ │ │ ├── spanner_mcp.md │ │ │ └── sqlite_mcp.md │ │ ├── deploy_docker.md │ │ ├── deploy_gke.md │ │ ├── deploy_toolbox.md │ │ ├── export_telemetry.md │ │ └── toolbox-ui │ │ ├── edit-headers.gif │ │ ├── edit-headers.png │ │ ├── index.md │ │ ├── optional-param-checked.png │ │ ├── optional-param-unchecked.png │ │ ├── run-tool.gif │ │ ├── tools.png │ │ └── toolsets.png │ ├── reference │ │ ├── _index.md │ │ ├── cli.md │ │ └── prebuilt-tools.md │ ├── resources │ │ ├── _index.md │ │ ├── authServices │ │ │ ├── _index.md │ │ │ └── google.md │ │ ├── sources │ │ │ ├── _index.md │ │ │ ├── alloydb-admin.md │ │ │ ├── alloydb-pg.md │ │ │ ├── bigquery.md │ │ │ ├── bigtable.md │ │ │ ├── cassandra.md │ │ │ ├── clickhouse.md │ │ │ ├── cloud-monitoring.md │ │ │ ├── cloud-sql-admin.md │ │ │ ├── cloud-sql-mssql.md │ │ │ ├── cloud-sql-mysql.md │ │ │ ├── cloud-sql-pg.md │ │ │ ├── couchbase.md │ │ │ ├── dataplex.md │ │ │ ├── dgraph.md │ │ │ ├── firebird.md │ │ │ ├── firestore.md │ │ │ ├── http.md │ │ │ ├── looker.md │ │ │ ├── mongodb.md │ │ │ ├── mssql.md │ │ │ ├── mysql.md │ │ │ ├── neo4j.md │ │ │ ├── oceanbase.md │ │ │ ├── oracle.md │ │ │ ├── postgres.md │ │ │ ├── redis.md │ │ │ ├── spanner.md │ │ │ ├── sqlite.md │ │ │ ├── tidb.md │ │ │ ├── trino.md │ │ │ ├── valkey.md │ │ │ └── yugabytedb.md │ │ └── tools │ │ ├── _index.md │ │ ├── alloydb │ │ │ ├── _index.md │ │ │ ├── alloydb-create-cluster.md │ │ │ ├── alloydb-create-instance.md │ │ │ ├── alloydb-create-user.md │ │ │ ├── alloydb-get-cluster.md │ │ │ ├── alloydb-get-instance.md │ │ │ ├── alloydb-get-user.md │ │ │ ├── alloydb-list-clusters.md │ │ │ ├── alloydb-list-instances.md │ │ │ ├── alloydb-list-users.md │ │ │ └── alloydb-wait-for-operation.md │ │ ├── alloydbainl │ │ │ ├── _index.md │ │ │ └── alloydb-ai-nl.md │ │ ├── bigquery │ │ │ ├── _index.md │ │ │ ├── bigquery-analyze-contribution.md │ │ │ ├── bigquery-conversational-analytics.md │ │ │ ├── bigquery-execute-sql.md │ │ │ ├── bigquery-forecast.md │ │ │ ├── bigquery-get-dataset-info.md │ │ │ ├── bigquery-get-table-info.md │ │ │ ├── bigquery-list-dataset-ids.md │ │ │ ├── bigquery-list-table-ids.md │ │ │ ├── bigquery-search-catalog.md │ │ │ └── bigquery-sql.md │ │ ├── bigtable │ │ │ ├── _index.md │ │ │ └── bigtable-sql.md │ │ ├── cassandra │ │ │ ├── _index.md │ │ │ └── cassandra-cql.md │ │ ├── clickhouse │ │ │ ├── _index.md │ │ │ ├── clickhouse-execute-sql.md │ │ │ ├── clickhouse-list-databases.md │ │ │ ├── clickhouse-list-tables.md │ │ │ └── clickhouse-sql.md │ │ ├── cloudmonitoring │ │ │ ├── _index.md │ │ │ └── cloud-monitoring-query-prometheus.md │ │ ├── cloudsql │ │ │ ├── _index.md │ │ │ ├── cloudsqlcreatedatabase.md │ │ │ ├── cloudsqlcreateusers.md │ │ │ ├── cloudsqlgetinstances.md │ │ │ ├── cloudsqllistdatabases.md │ │ │ ├── cloudsqllistinstances.md │ │ │ ├── cloudsqlmssqlcreateinstance.md │ │ │ ├── cloudsqlmysqlcreateinstance.md │ │ │ ├── cloudsqlpgcreateinstances.md │ │ │ └── cloudsqlwaitforoperation.md │ │ ├── couchbase │ │ │ ├── _index.md │ │ │ └── couchbase-sql.md │ │ ├── dataform │ │ │ ├── _index.md │ │ │ └── dataform-compile-local.md │ │ ├── dataplex │ │ │ ├── _index.md │ │ │ ├── dataplex-lookup-entry.md │ │ │ ├── dataplex-search-aspect-types.md │ │ │ └── dataplex-search-entries.md │ │ ├── dgraph │ │ │ ├── _index.md │ │ │ └── dgraph-dql.md │ │ ├── firebird │ │ │ ├── _index.md │ │ │ ├── firebird-execute-sql.md │ │ │ └── firebird-sql.md │ │ ├── firestore │ │ │ ├── _index.md │ │ │ ├── firestore-add-documents.md │ │ │ ├── firestore-delete-documents.md │ │ │ ├── firestore-get-documents.md │ │ │ ├── firestore-get-rules.md │ │ │ ├── firestore-list-collections.md │ │ │ ├── firestore-query-collection.md │ │ │ ├── firestore-query.md │ │ │ ├── firestore-update-document.md │ │ │ └── firestore-validate-rules.md │ │ ├── http │ │ │ ├── _index.md │ │ │ └── http.md │ │ ├── looker │ │ │ ├── _index.md │ │ │ ├── looker-add-dashboard-element.md │ │ │ ├── looker-conversational-analytics.md │ │ │ ├── looker-get-dashboards.md │ │ │ ├── looker-get-dimensions.md │ │ │ ├── looker-get-explores.md │ │ │ ├── looker-get-filters.md │ │ │ ├── looker-get-looks.md │ │ │ ├── looker-get-measures.md │ │ │ ├── looker-get-models.md │ │ │ ├── looker-get-parameters.md │ │ │ ├── looker-health-analyze.md │ │ │ ├── looker-health-pulse.md │ │ │ ├── looker-health-vacuum.md │ │ │ ├── looker-make-dashboard.md │ │ │ ├── looker-make-look.md │ │ │ ├── looker-query-sql.md │ │ │ ├── looker-query-url.md │ │ │ ├── looker-query.md │ │ │ └── looker-run-look.md │ │ ├── mongodb │ │ │ ├── _index.md │ │ │ ├── mongodb-aggregate.md │ │ │ ├── mongodb-delete-many.md │ │ │ ├── mongodb-delete-one.md │ │ │ ├── mongodb-find-one.md │ │ │ ├── mongodb-find.md │ │ │ ├── mongodb-insert-many.md │ │ │ ├── mongodb-insert-one.md │ │ │ ├── mongodb-update-many.md │ │ │ └── mongodb-update-one.md │ │ ├── mssql │ │ │ ├── _index.md │ │ │ ├── mssql-execute-sql.md │ │ │ ├── mssql-list-tables.md │ │ │ └── mssql-sql.md │ │ ├── mysql │ │ │ ├── _index.md │ │ │ ├── mysql-execute-sql.md │ │ │ ├── mysql-list-active-queries.md │ │ │ ├── mysql-list-table-fragmentation.md │ │ │ ├── mysql-list-tables-missing-unique-indexes.md │ │ │ ├── mysql-list-tables.md │ │ │ └── mysql-sql.md │ │ ├── neo4j │ │ │ ├── _index.md │ │ │ ├── neo4j-cypher.md │ │ │ ├── neo4j-execute-cypher.md │ │ │ └── neo4j-schema.md │ │ ├── oceanbase │ │ │ ├── _index.md │ │ │ ├── oceanbase-execute-sql.md │ │ │ └── oceanbase-sql.md │ │ ├── oracle │ │ │ ├── _index.md │ │ │ ├── oracle-execute-sql.md │ │ │ └── oracle-sql.md │ │ ├── postgres │ │ │ ├── _index.md │ │ │ ├── postgres-execute-sql.md │ │ │ ├── postgres-list-active-queries.md │ │ │ ├── postgres-list-available-extensions.md │ │ │ ├── postgres-list-installed-extensions.md │ │ │ ├── postgres-list-tables.md │ │ │ └── postgres-sql.md │ │ ├── redis │ │ │ ├── _index.md │ │ │ └── redis.md │ │ ├── spanner │ │ │ ├── _index.md │ │ │ ├── spanner-execute-sql.md │ │ │ ├── spanner-list-tables.md │ │ │ └── spanner-sql.md │ │ ├── sqlite │ │ │ ├── _index.md │ │ │ ├── sqlite-execute-sql.md │ │ │ └── sqlite-sql.md │ │ ├── tidb │ │ │ ├── _index.md │ │ │ ├── tidb-execute-sql.md │ │ │ └── tidb-sql.md │ │ ├── trino │ │ │ ├── _index.md │ │ │ ├── trino-execute-sql.md │ │ │ └── trino-sql.md │ │ ├── utility │ │ │ ├── _index.md │ │ │ └── wait.md │ │ ├── valkey │ │ │ ├── _index.md │ │ │ └── valkey.md │ │ └── yuagbytedb │ │ ├── _index.md │ │ └── yugabytedb-sql.md │ ├── samples │ │ ├── _index.md │ │ ├── alloydb │ │ │ ├── _index.md │ │ │ ├── ai-nl │ │ │ │ ├── alloydb_ai_nl.ipynb │ │ │ │ └── index.md │ │ │ └── mcp_quickstart.md │ │ ├── bigquery │ │ │ ├── _index.md │ │ │ ├── colab_quickstart_bigquery.ipynb │ │ │ ├── local_quickstart.md │ │ │ └── mcp_quickstart │ │ │ ├── _index.md │ │ │ ├── inspector_tools.png │ │ │ └── inspector.png │ │ └── looker │ │ ├── _index.md │ │ ├── looker_gemini_oauth │ │ │ ├── _index.md │ │ │ ├── authenticated.png │ │ │ ├── authorize.png │ │ │ └── registration.png │ │ ├── looker_gemini.md │ │ └── looker_mcp_inspector │ │ ├── _index.md │ │ ├── inspector_tools.png │ │ └── inspector.png │ └── sdks │ ├── _index.md │ ├── go-sdk.md │ ├── js-sdk.md │ └── python-sdk.md ├── go.mod ├── go.sum ├── internal │ ├── auth │ │ ├── auth.go │ │ └── google │ │ └── google.go │ ├── log │ │ ├── handler.go │ │ ├── log_test.go │ │ ├── log.go │ │ └── logger.go │ ├── prebuiltconfigs │ │ ├── prebuiltconfigs_test.go │ │ ├── prebuiltconfigs.go │ │ └── tools │ │ ├── alloydb-postgres-admin.yaml │ │ ├── alloydb-postgres-observability.yaml │ │ ├── alloydb-postgres.yaml │ │ ├── bigquery.yaml │ │ ├── clickhouse.yaml │ │ ├── cloud-sql-mssql-admin.yaml │ │ ├── cloud-sql-mssql-observability.yaml │ │ ├── cloud-sql-mssql.yaml │ │ ├── cloud-sql-mysql-admin.yaml │ │ ├── cloud-sql-mysql-observability.yaml │ │ ├── cloud-sql-mysql.yaml │ │ ├── cloud-sql-postgres-admin.yaml │ │ ├── cloud-sql-postgres-observability.yaml │ │ ├── cloud-sql-postgres.yaml │ │ ├── dataplex.yaml │ │ ├── firestore.yaml │ │ ├── looker-conversational-analytics.yaml │ │ ├── looker.yaml │ │ ├── mssql.yaml │ │ ├── mysql.yaml │ │ ├── neo4j.yaml │ │ ├── oceanbase.yaml │ │ ├── postgres.yaml │ │ ├── spanner-postgres.yaml │ │ ├── spanner.yaml │ │ └── sqlite.yaml │ ├── server │ │ ├── api_test.go │ │ ├── api.go │ │ ├── common_test.go │ │ ├── config.go │ │ ├── mcp │ │ │ ├── jsonrpc │ │ │ │ ├── jsonrpc_test.go │ │ │ │ └── jsonrpc.go │ │ │ ├── mcp.go │ │ │ ├── util │ │ │ │ └── lifecycle.go │ │ │ ├── v20241105 │ │ │ │ ├── method.go │ │ │ │ └── types.go │ │ │ ├── v20250326 │ │ │ │ ├── method.go │ │ │ │ └── types.go │ │ │ └── v20250618 │ │ │ ├── method.go │ │ │ └── types.go │ │ ├── mcp_test.go │ │ ├── mcp.go │ │ ├── server_test.go │ │ ├── server.go │ │ ├── static │ │ │ ├── assets │ │ │ │ └── mcptoolboxlogo.png │ │ │ ├── css │ │ │ │ └── style.css │ │ │ ├── index.html │ │ │ ├── js │ │ │ │ ├── auth.js │ │ │ │ ├── loadTools.js │ │ │ │ ├── mainContent.js │ │ │ │ ├── navbar.js │ │ │ │ ├── runTool.js │ │ │ │ ├── toolDisplay.js │ │ │ │ ├── tools.js │ │ │ │ └── toolsets.js │ │ │ ├── tools.html │ │ │ └── toolsets.html │ │ ├── web_test.go │ │ └── web.go │ ├── sources │ │ ├── alloydbadmin │ │ │ ├── alloydbadmin_test.go │ │ │ └── alloydbadmin.go │ │ ├── alloydbpg │ │ │ ├── alloydb_pg_test.go │ │ │ └── alloydb_pg.go │ │ ├── bigquery │ │ │ ├── bigquery_test.go │ │ │ └── bigquery.go │ │ ├── bigtable │ │ │ ├── bigtable_test.go │ │ │ └── bigtable.go │ │ ├── cassandra │ │ │ ├── cassandra_test.go │ │ │ └── cassandra.go │ │ ├── clickhouse │ │ │ ├── clickhouse_test.go │ │ │ └── clickhouse.go │ │ ├── cloudmonitoring │ │ │ ├── cloud_monitoring_test.go │ │ │ └── cloud_monitoring.go │ │ ├── cloudsqladmin │ │ │ ├── cloud_sql_admin_test.go │ │ │ └── cloud_sql_admin.go │ │ ├── cloudsqlmssql │ │ │ ├── cloud_sql_mssql_test.go │ │ │ └── cloud_sql_mssql.go │ │ ├── cloudsqlmysql │ │ │ ├── cloud_sql_mysql_test.go │ │ │ └── cloud_sql_mysql.go │ │ ├── cloudsqlpg │ │ │ ├── cloud_sql_pg_test.go │ │ │ └── cloud_sql_pg.go │ │ ├── couchbase │ │ │ ├── couchbase_test.go │ │ │ └── couchbase.go │ │ ├── dataplex │ │ │ ├── dataplex_test.go │ │ │ └── dataplex.go │ │ ├── dgraph │ │ │ ├── dgraph_test.go │ │ │ └── dgraph.go │ │ ├── dialect.go │ │ ├── firebird │ │ │ ├── firebird_test.go │ │ │ └── firebird.go │ │ ├── firestore │ │ │ ├── firestore_test.go │ │ │ └── firestore.go │ │ ├── http │ │ │ ├── http_test.go │ │ │ └── http.go │ │ ├── ip_type.go │ │ ├── looker │ │ │ ├── looker_test.go │ │ │ └── looker.go │ │ ├── mongodb │ │ │ ├── mongodb_test.go │ │ │ └── mongodb.go │ │ ├── mssql │ │ │ ├── mssql_test.go │ │ │ └── mssql.go │ │ ├── mysql │ │ │ ├── mysql_test.go │ │ │ └── mysql.go │ │ ├── neo4j │ │ │ ├── neo4j_test.go │ │ │ └── neo4j.go │ │ ├── oceanbase │ │ │ ├── oceanbase_test.go │ │ │ └── oceanbase.go │ │ ├── oracle │ │ │ └── oracle.go │ │ ├── postgres │ │ │ ├── postgres_test.go │ │ │ └── postgres.go │ │ ├── redis │ │ │ ├── redis_test.go │ │ │ └── redis.go │ │ ├── sources.go │ │ ├── spanner │ │ │ ├── spanner_test.go │ │ │ └── spanner.go │ │ ├── sqlite │ │ │ ├── sqlite_test.go │ │ │ └── sqlite.go │ │ ├── tidb │ │ │ ├── tidb_test.go │ │ │ └── tidb.go │ │ ├── trino │ │ │ ├── trino_test.go │ │ │ └── trino.go │ │ ├── util.go │ │ ├── valkey │ │ │ ├── valkey_test.go │ │ │ └── valkey.go │ │ └── yugabytedb │ │ ├── yugabytedb_test.go │ │ └── yugabytedb.go │ ├── telemetry │ │ ├── instrumentation.go │ │ └── telemetry.go │ ├── testutils │ │ └── testutils.go │ ├── tools │ │ ├── alloydb │ │ │ ├── alloydbcreatecluster │ │ │ │ ├── alloydbcreatecluster_test.go │ │ │ │ └── alloydbcreatecluster.go │ │ │ ├── alloydbcreateinstance │ │ │ │ ├── alloydbcreateinstance_test.go │ │ │ │ └── alloydbcreateinstance.go │ │ │ ├── alloydbcreateuser │ │ │ │ ├── alloydbcreateuser_test.go │ │ │ │ └── alloydbcreateuser.go │ │ │ ├── alloydbgetcluster │ │ │ │ ├── alloydbgetcluster_test.go │ │ │ │ └── alloydbgetcluster.go │ │ │ ├── alloydbgetinstance │ │ │ │ ├── alloydbgetinstance_test.go │ │ │ │ └── alloydbgetinstance.go │ │ │ ├── alloydbgetuser │ │ │ │ ├── alloydbgetuser_test.go │ │ │ │ └── alloydbgetuser.go │ │ │ ├── alloydblistclusters │ │ │ │ ├── alloydblistclusters_test.go │ │ │ │ └── alloydblistclusters.go │ │ │ ├── alloydblistinstances │ │ │ │ ├── alloydblistinstances_test.go │ │ │ │ └── alloydblistinstances.go │ │ │ ├── alloydblistusers │ │ │ │ ├── alloydblistusers_test.go │ │ │ │ └── alloydblistusers.go │ │ │ └── alloydbwaitforoperation │ │ │ ├── alloydbwaitforoperation_test.go │ │ │ └── alloydbwaitforoperation.go │ │ ├── alloydbainl │ │ │ ├── alloydbainl_test.go │ │ │ └── alloydbainl.go │ │ ├── bigquery │ │ │ ├── bigqueryanalyzecontribution │ │ │ │ ├── bigqueryanalyzecontribution_test.go │ │ │ │ └── bigqueryanalyzecontribution.go │ │ │ ├── bigquerycommon │ │ │ │ ├── table_name_parser_test.go │ │ │ │ ├── table_name_parser.go │ │ │ │ └── util.go │ │ │ ├── bigqueryconversationalanalytics │ │ │ │ ├── bigqueryconversationalanalytics_test.go │ │ │ │ └── bigqueryconversationalanalytics.go │ │ │ ├── bigqueryexecutesql │ │ │ │ ├── bigqueryexecutesql_test.go │ │ │ │ └── bigqueryexecutesql.go │ │ │ ├── bigqueryforecast │ │ │ │ ├── bigqueryforecast_test.go │ │ │ │ └── bigqueryforecast.go │ │ │ ├── bigquerygetdatasetinfo │ │ │ │ ├── bigquerygetdatasetinfo_test.go │ │ │ │ └── bigquerygetdatasetinfo.go │ │ │ ├── bigquerygettableinfo │ │ │ │ ├── bigquerygettableinfo_test.go │ │ │ │ └── bigquerygettableinfo.go │ │ │ ├── bigquerylistdatasetids │ │ │ │ ├── bigquerylistdatasetids_test.go │ │ │ │ └── bigquerylistdatasetids.go │ │ │ ├── bigquerylisttableids │ │ │ │ ├── bigquerylisttableids_test.go │ │ │ │ └── bigquerylisttableids.go │ │ │ ├── bigquerysearchcatalog │ │ │ │ ├── bigquerysearchcatalog_test.go │ │ │ │ └── bigquerysearchcatalog.go │ │ │ └── bigquerysql │ │ │ ├── bigquerysql_test.go │ │ │ └── bigquerysql.go │ │ ├── bigtable │ │ │ ├── bigtable_test.go │ │ │ └── bigtable.go │ │ ├── cassandra │ │ │ └── cassandracql │ │ │ ├── cassandracql_test.go │ │ │ └── cassandracql.go │ │ ├── clickhouse │ │ │ ├── clickhouseexecutesql │ │ │ │ ├── clickhouseexecutesql_test.go │ │ │ │ └── clickhouseexecutesql.go │ │ │ ├── clickhouselistdatabases │ │ │ │ ├── clickhouselistdatabases_test.go │ │ │ │ └── clickhouselistdatabases.go │ │ │ ├── clickhouselisttables │ │ │ │ ├── clickhouselisttables_test.go │ │ │ │ └── clickhouselisttables.go │ │ │ └── clickhousesql │ │ │ ├── clickhousesql_test.go │ │ │ └── clickhousesql.go │ │ ├── cloudmonitoring │ │ │ ├── cloudmonitoring_test.go │ │ │ └── cloudmonitoring.go │ │ ├── cloudsql │ │ │ ├── cloudsqlcreatedatabase │ │ │ │ ├── cloudsqlcreatedatabase_test.go │ │ │ │ └── cloudsqlcreatedatabase.go │ │ │ ├── cloudsqlcreateusers │ │ │ │ ├── cloudsqlcreateusers_test.go │ │ │ │ └── cloudsqlcreateusers.go │ │ │ ├── cloudsqlgetinstances │ │ │ │ ├── cloudsqlgetinstances_test.go │ │ │ │ └── cloudsqlgetinstances.go │ │ │ ├── cloudsqllistdatabases │ │ │ │ ├── cloudsqllistdatabases_test.go │ │ │ │ └── cloudsqllistdatabases.go │ │ │ ├── cloudsqllistinstances │ │ │ │ ├── cloudsqllistinstances_test.go │ │ │ │ └── cloudsqllistinstances.go │ │ │ └── cloudsqlwaitforoperation │ │ │ ├── cloudsqlwaitforoperation_test.go │ │ │ └── cloudsqlwaitforoperation.go │ │ ├── cloudsqlmssql │ │ │ └── cloudsqlmssqlcreateinstance │ │ │ ├── cloudsqlmssqlcreateinstance_test.go │ │ │ └── cloudsqlmssqlcreateinstance.go │ │ ├── cloudsqlmysql │ │ │ └── cloudsqlmysqlcreateinstance │ │ │ ├── cloudsqlmysqlcreateinstance_test.go │ │ │ └── cloudsqlmysqlcreateinstance.go │ │ ├── cloudsqlpg │ │ │ └── cloudsqlpgcreateinstances │ │ │ ├── cloudsqlpgcreateinstances_test.go │ │ │ └── cloudsqlpgcreateinstances.go │ │ ├── common_test.go │ │ ├── common.go │ │ ├── couchbase │ │ │ ├── couchbase_test.go │ │ │ └── couchbase.go │ │ ├── dataform │ │ │ └── dataformcompilelocal │ │ │ ├── dataformcompilelocal_test.go │ │ │ └── dataformcompilelocal.go │ │ ├── dataplex │ │ │ ├── dataplexlookupentry │ │ │ │ ├── dataplexlookupentry_test.go │ │ │ │ └── dataplexlookupentry.go │ │ │ ├── dataplexsearchaspecttypes │ │ │ │ ├── dataplexsearchaspecttypes_test.go │ │ │ │ └── dataplexsearchaspecttypes.go │ │ │ └── dataplexsearchentries │ │ │ ├── dataplexsearchentries_test.go │ │ │ └── dataplexsearchentries.go │ │ ├── dgraph │ │ │ ├── dgraph_test.go │ │ │ └── dgraph.go │ │ ├── firebird │ │ │ ├── firebirdexecutesql │ │ │ │ ├── firebirdexecutesql_test.go │ │ │ │ └── firebirdexecutesql.go │ │ │ └── firebirdsql │ │ │ ├── firebirdsql_test.go │ │ │ └── firebirdsql.go │ │ ├── firestore │ │ │ ├── firestoreadddocuments │ │ │ │ ├── firestoreadddocuments_test.go │ │ │ │ └── firestoreadddocuments.go │ │ │ ├── firestoredeletedocuments │ │ │ │ ├── firestoredeletedocuments_test.go │ │ │ │ └── firestoredeletedocuments.go │ │ │ ├── firestoregetdocuments │ │ │ │ ├── firestoregetdocuments_test.go │ │ │ │ └── firestoregetdocuments.go │ │ │ ├── firestoregetrules │ │ │ │ ├── firestoregetrules_test.go │ │ │ │ └── firestoregetrules.go │ │ │ ├── firestorelistcollections │ │ │ │ ├── firestorelistcollections_test.go │ │ │ │ └── firestorelistcollections.go │ │ │ ├── firestorequery │ │ │ │ ├── firestorequery_test.go │ │ │ │ └── firestorequery.go │ │ │ ├── firestorequerycollection │ │ │ │ ├── firestorequerycollection_test.go │ │ │ │ └── firestorequerycollection.go │ │ │ ├── firestoreupdatedocument │ │ │ │ ├── firestoreupdatedocument_test.go │ │ │ │ └── firestoreupdatedocument.go │ │ │ ├── firestorevalidaterules │ │ │ │ ├── firestorevalidaterules_test.go │ │ │ │ └── firestorevalidaterules.go │ │ │ └── util │ │ │ ├── converter_test.go │ │ │ ├── converter.go │ │ │ ├── validator_test.go │ │ │ └── validator.go │ │ ├── http │ │ │ ├── http_test.go │ │ │ └── http.go │ │ ├── http_method.go │ │ ├── looker │ │ │ ├── lookeradddashboardelement │ │ │ │ ├── lookeradddashboardelement_test.go │ │ │ │ └── lookeradddashboardelement.go │ │ │ ├── lookercommon │ │ │ │ ├── lookercommon_test.go │ │ │ │ └── lookercommon.go │ │ │ ├── lookerconversationalanalytics │ │ │ │ ├── lookerconversationalanalytics_test.go │ │ │ │ └── lookerconversationalanalytics.go │ │ │ ├── lookergetdashboards │ │ │ │ ├── lookergetdashboards_test.go │ │ │ │ └── lookergetdashboards.go │ │ │ ├── lookergetdimensions │ │ │ │ ├── lookergetdimensions_test.go │ │ │ │ └── lookergetdimensions.go │ │ │ ├── lookergetexplores │ │ │ │ ├── lookergetexplores_test.go │ │ │ │ └── lookergetexplores.go │ │ │ ├── lookergetfilters │ │ │ │ ├── lookergetfilters_test.go │ │ │ │ └── lookergetfilters.go │ │ │ ├── lookergetlooks │ │ │ │ ├── lookergetlooks_test.go │ │ │ │ └── lookergetlooks.go │ │ │ ├── lookergetmeasures │ │ │ │ ├── lookergetmeasures_test.go │ │ │ │ └── lookergetmeasures.go │ │ │ ├── lookergetmodels │ │ │ │ ├── lookergetmodels_test.go │ │ │ │ └── lookergetmodels.go │ │ │ ├── lookergetparameters │ │ │ │ ├── lookergetparameters_test.go │ │ │ │ └── lookergetparameters.go │ │ │ ├── lookerhealthanalyze │ │ │ │ ├── lookerhealthanalyze_test.go │ │ │ │ └── lookerhealthanalyze.go │ │ │ ├── lookerhealthpulse │ │ │ │ ├── lookerhealthpulse_test.go │ │ │ │ └── lookerhealthpulse.go │ │ │ ├── lookerhealthvacuum │ │ │ │ ├── lookerhealthvacuum_test.go │ │ │ │ └── lookerhealthvacuum.go │ │ │ ├── lookermakedashboard │ │ │ │ ├── lookermakedashboard_test.go │ │ │ │ └── lookermakedashboard.go │ │ │ ├── lookermakelook │ │ │ │ ├── lookermakelook_test.go │ │ │ │ └── lookermakelook.go │ │ │ ├── lookerquery │ │ │ │ ├── lookerquery_test.go │ │ │ │ └── lookerquery.go │ │ │ ├── lookerquerysql │ │ │ │ ├── lookerquerysql_test.go │ │ │ │ └── lookerquerysql.go │ │ │ ├── lookerqueryurl │ │ │ │ ├── lookerqueryurl_test.go │ │ │ │ └── lookerqueryurl.go │ │ │ └── lookerrunlook │ │ │ ├── lookerrunlook_test.go │ │ │ └── lookerrunlook.go │ │ ├── mongodb │ │ │ ├── mongodbaggregate │ │ │ │ ├── mongodbaggregate_test.go │ │ │ │ └── mongodbaggregate.go │ │ │ ├── mongodbdeletemany │ │ │ │ ├── mongodbdeletemany_test.go │ │ │ │ └── mongodbdeletemany.go │ │ │ ├── mongodbdeleteone │ │ │ │ ├── mongodbdeleteone_test.go │ │ │ │ └── mongodbdeleteone.go │ │ │ ├── mongodbfind │ │ │ │ ├── mongodbfind_test.go │ │ │ │ └── mongodbfind.go │ │ │ ├── mongodbfindone │ │ │ │ ├── mongodbfindone_test.go │ │ │ │ └── mongodbfindone.go │ │ │ ├── mongodbinsertmany │ │ │ │ ├── mongodbinsertmany_test.go │ │ │ │ └── mongodbinsertmany.go │ │ │ ├── mongodbinsertone │ │ │ │ ├── mongodbinsertone_test.go │ │ │ │ └── mongodbinsertone.go │ │ │ ├── mongodbupdatemany │ │ │ │ ├── mongodbupdatemany_test.go │ │ │ │ └── mongodbupdatemany.go │ │ │ └── mongodbupdateone │ │ │ ├── mongodbupdateone_test.go │ │ │ └── mongodbupdateone.go │ │ ├── mssql │ │ │ ├── mssqlexecutesql │ │ │ │ ├── mssqlexecutesql_test.go │ │ │ │ └── mssqlexecutesql.go │ │ │ ├── mssqllisttables │ │ │ │ ├── mssqllisttables_test.go │ │ │ │ └── mssqllisttables.go │ │ │ └── mssqlsql │ │ │ ├── mssqlsql_test.go │ │ │ └── mssqlsql.go │ │ ├── mysql │ │ │ ├── mysqlcommon │ │ │ │ └── mysqlcommon.go │ │ │ ├── mysqlexecutesql │ │ │ │ ├── mysqlexecutesql_test.go │ │ │ │ └── mysqlexecutesql.go │ │ │ ├── mysqllistactivequeries │ │ │ │ ├── mysqllistactivequeries_test.go │ │ │ │ └── mysqllistactivequeries.go │ │ │ ├── mysqllisttablefragmentation │ │ │ │ ├── mysqllisttablefragmentation_test.go │ │ │ │ └── mysqllisttablefragmentation.go │ │ │ ├── mysqllisttables │ │ │ │ ├── mysqllisttables_test.go │ │ │ │ └── mysqllisttables.go │ │ │ ├── mysqllisttablesmissinguniqueindexes │ │ │ │ ├── mysqllisttablesmissinguniqueindexes_test.go │ │ │ │ └── mysqllisttablesmissinguniqueindexes.go │ │ │ └── mysqlsql │ │ │ ├── mysqlsql_test.go │ │ │ └── mysqlsql.go │ │ ├── neo4j │ │ │ ├── neo4jcypher │ │ │ │ ├── neo4jcypher_test.go │ │ │ │ └── neo4jcypher.go │ │ │ ├── neo4jexecutecypher │ │ │ │ ├── classifier │ │ │ │ │ ├── classifier_test.go │ │ │ │ │ └── classifier.go │ │ │ │ ├── neo4jexecutecypher_test.go │ │ │ │ └── neo4jexecutecypher.go │ │ │ └── neo4jschema │ │ │ ├── cache │ │ │ │ ├── cache_test.go │ │ │ │ └── cache.go │ │ │ ├── helpers │ │ │ │ ├── helpers_test.go │ │ │ │ └── helpers.go │ │ │ ├── neo4jschema_test.go │ │ │ ├── neo4jschema.go │ │ │ └── types │ │ │ └── types.go │ │ ├── oceanbase │ │ │ ├── oceanbaseexecutesql │ │ │ │ ├── oceanbaseexecutesql_test.go │ │ │ │ └── oceanbaseexecutesql.go │ │ │ └── oceanbasesql │ │ │ ├── oceanbasesql_test.go │ │ │ └── oceanbasesql.go │ │ ├── oracle │ │ │ ├── oracleexecutesql │ │ │ │ └── oracleexecutesql.go │ │ │ └── oraclesql │ │ │ └── oraclesql.go │ │ ├── parameters_test.go │ │ ├── parameters.go │ │ ├── postgres │ │ │ ├── postgresexecutesql │ │ │ │ ├── postgresexecutesql_test.go │ │ │ │ └── postgresexecutesql.go │ │ │ ├── postgreslistactivequeries │ │ │ │ ├── postgreslistactivequeries_test.go │ │ │ │ └── postgreslistactivequeries.go │ │ │ ├── postgreslistavailableextensions │ │ │ │ ├── postgreslistavailableextensions_test.go │ │ │ │ └── postgreslistavailableextensions.go │ │ │ ├── postgreslistinstalledextensions │ │ │ │ ├── postgreslistinstalledextensions_test.go │ │ │ │ └── postgreslistinstalledextensions.go │ │ │ ├── postgreslisttables │ │ │ │ ├── postgreslisttables_test.go │ │ │ │ └── postgreslisttables.go │ │ │ └── postgressql │ │ │ ├── postgressql_test.go │ │ │ └── postgressql.go │ │ ├── redis │ │ │ ├── redis_test.go │ │ │ └── redis.go │ │ ├── spanner │ │ │ ├── spannerexecutesql │ │ │ │ ├── spannerexecutesql_test.go │ │ │ │ └── spannerexecutesql.go │ │ │ ├── spannerlisttables │ │ │ │ ├── spannerlisttables_test.go │ │ │ │ └── spannerlisttables.go │ │ │ └── spannersql │ │ │ ├── spanner_test.go │ │ │ └── spannersql.go │ │ ├── sqlite │ │ │ ├── sqliteexecutesql │ │ │ │ ├── sqliteexecutesql_test.go │ │ │ │ └── sqliteexecutesql.go │ │ │ └── sqlitesql │ │ │ ├── sqlitesql_test.go │ │ │ └── sqlitesql.go │ │ ├── tidb │ │ │ ├── tidbexecutesql │ │ │ │ ├── tidbexecutesql_test.go │ │ │ │ └── tidbexecutesql.go │ │ │ └── tidbsql │ │ │ ├── tidbsql_test.go │ │ │ └── tidbsql.go │ │ ├── tools_test.go │ │ ├── tools.go │ │ ├── toolsets.go │ │ ├── trino │ │ │ ├── trinoexecutesql │ │ │ │ ├── trinoexecutesql_test.go │ │ │ │ └── trinoexecutesql.go │ │ │ └── trinosql │ │ │ ├── trinosql_test.go │ │ │ └── trinosql.go │ │ ├── utility │ │ │ └── wait │ │ │ ├── wait_test.go │ │ │ └── wait.go │ │ ├── valkey │ │ │ ├── valkey_test.go │ │ │ └── valkey.go │ │ └── yugabytedbsql │ │ ├── yugabytedbsql_test.go │ │ └── yugabytedbsql.go │ └── util │ └── util.go ├── LICENSE ├── logo.png ├── main.go ├── README.md └── tests ├── alloydb │ ├── alloydb_integration_test.go │ └── alloydb_wait_for_operation_test.go ├── alloydbainl │ └── alloydb_ai_nl_integration_test.go ├── alloydbpg │ └── alloydb_pg_integration_test.go ├── auth.go ├── bigquery │ └── bigquery_integration_test.go ├── bigtable │ └── bigtable_integration_test.go ├── cassandra │ └── cassandra_integration_test.go ├── clickhouse │ └── clickhouse_integration_test.go ├── cloudmonitoring │ └── cloud_monitoring_integration_test.go ├── cloudsql │ ├── cloud_sql_create_database_test.go │ ├── cloud_sql_create_users_test.go │ ├── cloud_sql_get_instances_test.go │ ├── cloud_sql_list_databases_test.go │ ├── cloudsql_list_instances_test.go │ └── cloudsql_wait_for_operation_test.go ├── cloudsqlmssql │ ├── cloud_sql_mssql_create_instance_integration_test.go │ └── cloud_sql_mssql_integration_test.go ├── cloudsqlmysql │ ├── cloud_sql_mysql_create_instance_integration_test.go │ └── cloud_sql_mysql_integration_test.go ├── cloudsqlpg │ ├── cloud_sql_pg_create_instances_test.go │ └── cloud_sql_pg_integration_test.go ├── common.go ├── couchbase │ └── couchbase_integration_test.go ├── dataform │ └── dataform_integration_test.go ├── dataplex │ └── dataplex_integration_test.go ├── dgraph │ └── dgraph_integration_test.go ├── firebird │ └── firebird_integration_test.go ├── firestore │ └── firestore_integration_test.go ├── http │ └── http_integration_test.go ├── looker │ └── looker_integration_test.go ├── mongodb │ └── mongodb_integration_test.go ├── mssql │ └── mssql_integration_test.go ├── mysql │ └── mysql_integration_test.go ├── neo4j │ └── neo4j_integration_test.go ├── oceanbase │ └── oceanbase_integration_test.go ├── option.go ├── oracle │ └── oracle_integration_test.go ├── postgres │ └── postgres_integration_test.go ├── redis │ └── redis_test.go ├── server.go ├── source.go ├── spanner │ └── spanner_integration_test.go ├── sqlite │ └── sqlite_integration_test.go ├── tidb │ └── tidb_integration_test.go ├── tool.go ├── trino │ └── trino_integration_test.go ├── utility │ └── wait_integration_test.go ├── valkey │ └── valkey_test.go └── yugabytedb └── yugabytedb_integration_test.go ``` # Files -------------------------------------------------------------------------------- /docs/en/resources/tools/alloydb/alloydb-list-instances.md: -------------------------------------------------------------------------------- ```markdown --- title: alloydb-list-instances type: docs weight: 1 description: "The \"alloydb-list-instances\" tool lists the AlloyDB instances for a given project, cluster and location.\n" aliases: [/resources/tools/alloydb-list-instances] --- ## About The `alloydb-list-instances` tool retrieves AlloyDB instance information for all or specified clusters and locations in a given project. It is compatible with [alloydb-admin](../../sources/alloydb-admin.md) source. `alloydb-list-instances` tool lists the detailed information of AlloyDB instances (instance name, type, IP address, state, configuration, etc) for a given project, cluster and location. The tool takes the following input parameters: | Parameter | Type | Description | Required | | :--------- | :----- | :--------------------------------------------------------------------------------------------------------- | :------- | | `project` | string | The GCP project ID to list instances for. | Yes | | `cluster` | string | The ID of the cluster to list instances from. Use '-' to get results for all clusters. Default: `-`. | No | | `location` | string | The location of the cluster (e.g., 'us-central1'). Use '-' to get results for all locations. Default: `-`. | No | ## Example ```yaml tools: list_instances: kind: alloydb-list-instances source: alloydb-admin-source description: Use this tool to list all AlloyDB instances for a given project, cluster and location. ``` ## Reference | **field** | **type** | **required** | **description** | | ----------- | :------: | :----------: | ---------------------------------------------------- | | kind | string | true | Must be alloydb-list-instances. | | source | string | true | The name of an `alloydb-admin` source. | | description | string | false | Description of the tool that is passed to the agent. | ``` -------------------------------------------------------------------------------- /internal/tools/mssql/mssqllisttables/mssqllisttables_test.go: -------------------------------------------------------------------------------- ```go // 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. package mssqllisttables_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" mssqllisttables "github.com/googleapis/genai-toolbox/internal/tools/mssql/mssqllisttables" ) func TestParseFromYamlmssqlListTables(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: mssql-list-tables source: my-mssql-instance description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "example_tool": mssqllisttables.Config{ Name: "example_tool", Kind: "mssql-list-tables", Source: "my-mssql-instance", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /internal/tools/mysql/mysqllistactivequeries/mysqllistactivequeries_test.go: -------------------------------------------------------------------------------- ```go // 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. package mysqllistactivequeries_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" "github.com/googleapis/genai-toolbox/internal/tools/mysql/mysqllistactivequeries" ) func TestParseFromYamlExecuteSql(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: mysql-list-active-queries source: my-instance description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "example_tool": mysqllistactivequeries.Config{ Name: "example_tool", Kind: "mysql-list-active-queries", Source: "my-instance", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /docs/en/getting-started/quickstart/python/llamaindex/quickstart.py: -------------------------------------------------------------------------------- ```python import asyncio import os from llama_index.core.agent.workflow import AgentWorkflow from llama_index.core.workflow import Context # TODO(developer): replace this with another import if needed from llama_index.llms.google_genai import GoogleGenAI # from llama_index.llms.anthropic import Anthropic from toolbox_llamaindex import ToolboxClient project = os.environ.get("GCP_PROJECT") or "project-id" prompt = """ You're a helpful hotel assistant. You handle hotel searching, booking and cancellations. When the user searches for a hotel, mention it's name, id, location and price tier. Always mention hotel ids while performing any searches. This is very important for any operations. For any bookings or cancellations, please provide the appropriate confirmation. Be sure to update checkin or checkout dates if mentioned by the user. Don't ask for confirmations from the user. """ queries = [ "Find hotels in Basel with Basel in its name.", "Can you book the Hilton Basel for me?", "Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.", "My check in dates would be from April 10, 2024 to April 19, 2024.", ] async def main(): # TODO(developer): replace this with another model if needed llm = GoogleGenAI( model="gemini-2.0-flash-001", vertexai_config={"project": project, "location": "us-central1"}, ) # llm = GoogleGenAI( # api_key=os.getenv("GOOGLE_API_KEY"), # model="gemini-2.0-flash-001", # ) # llm = Anthropic( # model="claude-3-7-sonnet-latest", # api_key=os.getenv("ANTHROPIC_API_KEY") # ) # Load the tools from the Toolbox server async with ToolboxClient("http://127.0.0.1:5000") as client: tools = await client.aload_toolset() agent = AgentWorkflow.from_tools_or_functions( tools, llm=llm, system_prompt=prompt, ) ctx = Context(agent) for query in queries: response = await agent.run(user_msg=query, ctx=ctx) print(f"---- {query} ----") print(str(response)) asyncio.run(main()) ``` -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.yml: -------------------------------------------------------------------------------- ```yaml # 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 # # https://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. name: 💬 Question description: Questions on how something works or the best way to do something? title: "<brief summary of the question>" labels: ["type: question"] body: - type: markdown attributes: value: | Thanks for helping us improve! 🙏 Please provide as much information as possible about your question. - id: preamble type: checkboxes attributes: label: Prerequisites description: | Please run through the following list and make sure you've tried the usual "quick fixes": options: - label: "Search the [current open issues](https://github.com/googleapis/genai-toolbox/issues)" required: true - type: textarea id: question attributes: label: Question description: "What's your question? Please provide as much relevant information as possible to reduce turnaround time. Include information like what environment, language, or framework you are using." placeholder: "Example: How do I connect using private IP with the AlloyDB source?" validations: required: true - type: textarea id: code attributes: label: Code description: "Please paste any useful application code that might be relevant to your question. (if your code is in a public repo, feel free to paste a link!)" - type: textarea id: additional-details attributes: label: Additional Details description: "Any other information you want us to know that might be helpful in answering your question? (link issues, PRs, descriptions, or screenshots)." ``` -------------------------------------------------------------------------------- /internal/tools/mysql/mysqllisttablefragmentation/mysqllisttablefragmentation_test.go: -------------------------------------------------------------------------------- ```go // 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. package mysqllisttablefragmentation_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" "github.com/googleapis/genai-toolbox/internal/tools/mysql/mysqllisttablefragmentation" ) func TestParseFromYamlExecuteSql(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: mysql-list-table-fragmentation source: my-instance description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "example_tool": mysqllisttablefragmentation.Config{ Name: "example_tool", Kind: "mysql-list-table-fragmentation", Source: "my-instance", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /internal/tools/postgres/postgreslisttables/postgreslisttables_test.go: -------------------------------------------------------------------------------- ```go // 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. package postgreslisttables_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" postgreslisttables "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgreslisttables" ) func TestParseFromYamlPostgresListTables(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: postgres-list-tables source: my-postgres-instance description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "example_tool": postgreslisttables.Config{ Name: "example_tool", Kind: "postgres-list-tables", Source: "my-postgres-instance", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /docs/en/getting-started/quickstart/python/quickstart_test.py: -------------------------------------------------------------------------------- ```python # 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. import os import pytest from pathlib import Path import asyncio import sys import importlib.util ORCH_NAME = os.environ.get("ORCH_NAME") module_path = f"python.{ORCH_NAME}.quickstart" quickstart = importlib.import_module(module_path) @pytest.fixture(scope="module") def golden_keywords(): """Loads expected keywords from the golden.txt file.""" golden_file_path = Path("../golden.txt") if not golden_file_path.exists(): pytest.fail(f"Golden file not found: {golden_file_path}") try: with open(golden_file_path, 'r') as f: return [line.strip() for line in f.readlines() if line.strip()] except Exception as e: pytest.fail(f"Could not read golden.txt: {e}") # --- Execution Tests --- class TestExecution: """Test framework execution and output validation.""" @pytest.fixture(scope="function") def script_output(self, capsys): """Run the quickstart function and return its output.""" asyncio.run(quickstart.main()) return capsys.readouterr() def test_script_runs_without_errors(self, script_output): """Test that the script runs and produces no stderr.""" assert script_output.err == "", f"Script produced stderr: {script_output.err}" def test_keywords_in_output(self, script_output, golden_keywords): """Test that expected keywords are present in the script's output.""" output = script_output.out missing_keywords = [kw for kw in golden_keywords if kw not in output] assert not missing_keywords, f"Missing keywords in output: {missing_keywords}" ``` -------------------------------------------------------------------------------- /internal/tools/oceanbase/oceanbaseexecutesql/oceanbaseexecutesql_test.go: -------------------------------------------------------------------------------- ```go // 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. package oceanbaseexecutesql_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" "github.com/googleapis/genai-toolbox/internal/tools/oceanbase/oceanbaseexecutesql" ) // Test parsing OceanBase Execute SQL tool config from YAML. func TestParseFromYamlExecuteSql(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: oceanbase-execute-sql source: my-instance description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "example_tool": oceanbaseexecutesql.Config{ Name: "example_tool", Kind: "oceanbase-execute-sql", Source: "my-instance", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /docs/en/getting-started/quickstart/js/quickstart.test.js: -------------------------------------------------------------------------------- ```javascript // 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. import { describe, test, before, after } from "node:test"; import assert from "node:assert/strict"; import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; const ORCH_NAME = process.env.ORCH_NAME; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const orchDir = path.join(__dirname, ORCH_NAME); const quickstartPath = path.join(orchDir, "quickstart.js"); const { main: runAgent } = await import(quickstartPath); const GOLDEN_FILE_PATH = path.resolve(__dirname, "../golden.txt"); describe(`${ORCH_NAME} Quickstart Agent`, () => { let capturedOutput = []; let originalLog; before(() => { originalLog = console.log; console.log = (msg) => { capturedOutput.push(msg); }; }); after(() => { console.log = originalLog; }); test("outputContainsRequiredKeywords", async () => { capturedOutput = []; await runAgent(); const actualOutput = capturedOutput.join("\n"); assert.ok( actualOutput.length > 0, "Assertion Failed: Script ran successfully but produced no output." ); const goldenFile = fs.readFileSync(GOLDEN_FILE_PATH, "utf8"); const keywords = goldenFile.split("\n").filter((kw) => kw.trim() !== ""); const missingKeywords = []; for (const keyword of keywords) { if (!actualOutput.toLowerCase().includes(keyword.toLowerCase())) { missingKeywords.push(keyword); } } assert.ok( missingKeywords.length === 0, `Assertion Failed: The following keywords were missing from the output: [${missingKeywords.join(", ")}]` ); }); }); ``` -------------------------------------------------------------------------------- /internal/tools/mysql/mysqllisttablesmissinguniqueindexes/mysqllisttablesmissinguniqueindexes_test.go: -------------------------------------------------------------------------------- ```go // 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. package mysqllisttablesmissinguniqueindexes_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" "github.com/googleapis/genai-toolbox/internal/tools/mysql/mysqllisttablesmissinguniqueindexes" ) func TestParseFromYamlExecuteSql(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: mysql-list-tables-missing-unique-indexes source: my-instance description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "example_tool": mysqllisttablesmissinguniqueindexes.Config{ Name: "example_tool", Kind: "mysql-list-tables-missing-unique-indexes", Source: "my-instance", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /internal/auth/google/google.go: -------------------------------------------------------------------------------- ```go // Copyright 2024 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. package google import ( "context" "fmt" "net/http" "github.com/googleapis/genai-toolbox/internal/auth" "google.golang.org/api/idtoken" ) const AuthServiceKind string = "google" // validate interface var _ auth.AuthServiceConfig = Config{} // Auth service configuration type Config struct { Name string `yaml:"name" validate:"required"` Kind string `yaml:"kind" validate:"required"` ClientID string `yaml:"clientId" validate:"required"` } // Returns the auth service kind func (cfg Config) AuthServiceConfigKind() string { return AuthServiceKind } // Initialize a Google auth service func (cfg Config) Initialize() (auth.AuthService, error) { a := &AuthService{ Name: cfg.Name, Kind: AuthServiceKind, ClientID: cfg.ClientID, } return a, nil } var _ auth.AuthService = AuthService{} // struct used to store auth service info type AuthService struct { Name string `yaml:"name"` Kind string `yaml:"kind"` ClientID string `yaml:"clientId"` } // Returns the auth service kind func (a AuthService) AuthServiceKind() string { return AuthServiceKind } // Returns the name of the auth service func (a AuthService) GetName() string { return a.Name } // Verifies Google ID token and return claims func (a AuthService) GetClaimsFromHeader(ctx context.Context, h http.Header) (map[string]any, error) { if token := h.Get(a.Name + "_token"); token != "" { payload, err := idtoken.Validate(ctx, token, a.ClientID) if err != nil { return nil, fmt.Errorf("Google ID token verification failure: %w", err) //nolint:staticcheck } return payload.Claims, nil } return nil, nil } ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydbwaitforoperation/alloydbwaitforoperation_test.go: -------------------------------------------------------------------------------- ```go // 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. package alloydbwaitforoperation_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" alloydbwaitforoperation "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbwaitforoperation" ) func TestParseFromYaml(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: wait-for-thing: kind: alloydb-wait-for-operation source: some-source description: some description delay: 1s maxDelay: 5s multiplier: 1.5 maxRetries: 5 `, want: server.ToolConfigs{ "wait-for-thing": alloydbwaitforoperation.Config{ Name: "wait-for-thing", Kind: "alloydb-wait-for-operation", Source: "some-source", Description: "some description", AuthRequired: []string{}, Delay: "1s", MaxDelay: "5s", Multiplier: 1.5, MaxRetries: 5, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /internal/server/static/js/navbar.js: -------------------------------------------------------------------------------- ```javascript // 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. /** * Renders the navigation bar HTML content into the specified container element. * @param {string} containerId The ID of the DOM element to inject the navbar into. * @param {string | null} activePath The active tab from the navbar. */ function renderNavbar(containerId, activePath) { const navbarContainer = document.getElementById(containerId); if (!navbarContainer) { console.error(`Navbar container with ID "${containerId}" not found.`); return; } const navbarHTML = ` <nav class="left-nav"> <div class="nav-logo"> <img src="/ui/assets/mcptoolboxlogo.png" alt="App Logo"> </div> <ul> <!--<li><a href="/ui/sources">Sources</a></li>--> <!--<li><a href="/ui/authservices">Auth Services</a></li>--> <li><a href="/ui/tools">Tools</a></li> <li><a href="/ui/toolsets">Toolsets</a></li> </ul> </nav> `; navbarContainer.innerHTML = navbarHTML; const logoImage = navbarContainer.querySelector('.nav-logo img'); if (logoImage) { logoImage.addEventListener('click', () => { window.location.href = '/ui/'; }); } if (activePath) { const navLinks = navbarContainer.querySelectorAll('.left-nav ul li a'); navLinks.forEach(link => { const linkPath = new URL(link.href).pathname; if (linkPath === activePath) { link.classList.add('active'); } else { link.classList.remove('active'); } }); } } ``` -------------------------------------------------------------------------------- /internal/tools/cloudsql/cloudsqlwaitforoperation/cloudsqlwaitforoperation_test.go: -------------------------------------------------------------------------------- ```go // 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. package cloudsqlwaitforoperation_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" cloudsqlwaitforoperation "github.com/googleapis/genai-toolbox/internal/tools/cloudsql/cloudsqlwaitforoperation" ) func TestParseFromYaml(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: wait-for-thing: kind: cloud-sql-wait-for-operation source: some-source description: some description delay: 1s maxDelay: 5s multiplier: 1.5 maxRetries: 5 `, want: server.ToolConfigs{ "wait-for-thing": cloudsqlwaitforoperation.Config{ Name: "wait-for-thing", Kind: "cloud-sql-wait-for-operation", Source: "some-source", Description: "some description", AuthRequired: []string{}, Delay: "1s", MaxDelay: "5s", Multiplier: 1.5, MaxRetries: 5, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/looker/looker-make-look.md: -------------------------------------------------------------------------------- ```markdown --- title: "looker-make-look" type: docs weight: 1 description: > "looker-make-look" generates a Looker look in the users personal folder in Looker aliases: - /resources/tools/looker-make-look --- ## About The `looker-make-look` creates a saved Look in the user's Looker personal folder. It's compatible with the following sources: - [looker](../../sources/looker.md) `looker-make-look` takes eleven parameters: 1. the `model` 2. the `explore` 3. the `fields` list 4. an optional set of `filters` 5. an optional set of `pivots` 6. an optional set of `sorts` 7. an optional `limit` 8. an optional `tz` 9. an optional `vis_config` 10. the `title` 11. an optional `description` ## Example ```yaml tools: make_look: kind: looker-make-look source: looker-source description: | make_look Tool This tool creates a new look in Looker, using the query parameters and the vis_config specified. Most of the parameters are the same as the query_url tool. In addition, there is a title and a description that must be provided. The newly created look will be created in the user's personal folder in looker. The look name must be unique. The result is a json document with a link to the newly created look. ``` ## Reference | **field** | **type** | **required** | **description** | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| | kind | string | true | Must be "looker-make-look" | | source | string | true | Name of the source the SQL should execute on. | | description | string | true | Description of the tool that is passed to the LLM. | ``` -------------------------------------------------------------------------------- /internal/server/static/js/toolsets.js: -------------------------------------------------------------------------------- ```javascript // 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. import { loadTools } from "./loadTools.js"; document.addEventListener('DOMContentLoaded', () => { const searchInput = document.getElementById('toolset-search-input'); const searchButton = document.getElementById('toolset-search-button'); const secondNavContent = document.getElementById('secondary-panel-content'); const toolDisplayArea = document.getElementById('tool-display-area'); if (!searchInput || !searchButton || !secondNavContent || !toolDisplayArea) { console.error('Required DOM elements not found.'); return; } // Event listener for search button click searchButton.addEventListener('click', () => { toolDisplayArea.innerHTML = ''; const toolsetName = searchInput.value.trim(); if (toolsetName) { loadTools(secondNavContent, toolDisplayArea, toolsetName) } else { secondNavContent.innerHTML = '<p>Please enter a toolset name to see available tools. <br><br>To view the default toolset that consists of all tools, please select the "Tools" tab.</p>'; } }); // Event listener for Enter key in search input searchInput.addEventListener('keypress', (event) => { toolDisplayArea.innerHTML = ''; if (event.key === 'Enter') { const toolsetName = searchInput.value.trim(); if (toolsetName) { loadTools(secondNavContent, toolDisplayArea, toolsetName); } else { secondNavContent.innerHTML = '<p>Please enter a toolset name to see available tools. <br><br>To view the default toolset that consists of all tools, please select the "Tools" tab.</p>'; } } }); }) ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/looker/looker-add-dashboard-element.md: -------------------------------------------------------------------------------- ```markdown --- title: "looker-add-dashboard-element" type: docs weight: 1 description: > "looker-add-dashboard-element" creates a dashboard element in the given dashboard. aliases: - /resources/tools/looker-add-dashboard-element --- ## About The `looker-add-dashboard-element` creates a dashboard element in the given dashboard. It's compatible with the following sources: - [looker](../../sources/looker.md) `looker-add-dashboard-element` takes eleven parameters: 1. the `model` 2. the `explore` 3. the `fields` list 4. an optional set of `filters` 5. an optional set of `pivots` 6. an optional set of `sorts` 7. an optional `limit` 8. an optional `tz` 9. an optional `vis_config` 10. the `title` 11. the `dashboard_id` ## Example ```yaml tools: add_dashboard_element: kind: looker-add-dashboard-element source: looker-source description: | add_dashboard_element Tool This tool creates a new tile in a Looker dashboard using the query parameters and the vis_config specified. Most of the parameters are the same as the query_url tool. In addition, there is a title that may be provided. The dashboard_id must be specified. That is obtained from calling make_dashboard. This tool can be called many times for one dashboard_id and the resulting tiles will be added in order. ``` ## Reference | **field** | **type** | **required** | **description** | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| | kind | string | true | Must be "looker-add-dashboard-element" | | source | string | true | Name of the source the SQL should execute on. | | description | string | true | Description of the tool that is passed to the LLM. | ``` -------------------------------------------------------------------------------- /docs/en/getting-started/quickstart/js/langchain/quickstart.js: -------------------------------------------------------------------------------- ```javascript import { ChatGoogleGenerativeAI } from "@langchain/google-genai"; import { ToolboxClient } from "@toolbox-sdk/core"; import { tool } from "@langchain/core/tools"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { MemorySaver } from "@langchain/langgraph"; const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || 'your-api-key'; // Replace it with your API key const prompt = ` You're a helpful hotel assistant. You handle hotel searching, booking, and cancellations. When the user searches for a hotel, mention its name, id, location and price tier. Always mention hotel ids while performing any searches. This is very important for any operations. For any bookings or cancellations, please provide the appropriate confirmation. Be sure to update checkin or checkout dates if mentioned by the user. Don't ask for confirmations from the user. `; const queries = [ "Find hotels in Basel with Basel in its name.", "Can you book the Hilton Basel for me?", "Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.", "My check in dates would be from April 10, 2024 to April 19, 2024.", ]; export async function main() { const model = new ChatGoogleGenerativeAI({ model: "gemini-2.0-flash", }); const client = new ToolboxClient("http://127.0.0.1:5000"); const toolboxTools = await client.loadToolset("my-toolset"); // Define the basics of the tool: name, description, schema and core logic const getTool = (toolboxTool) => tool(toolboxTool, { name: toolboxTool.getName(), description: toolboxTool.getDescription(), schema: toolboxTool.getParamSchema() }); const tools = toolboxTools.map(getTool); const agent = createReactAgent({ llm: model, tools: tools, checkpointer: new MemorySaver(), systemPrompt: prompt, }); const langGraphConfig = { configurable: { thread_id: "test-thread", }, }; for (const query of queries) { const agentOutput = await agent.invoke( { messages: [ { role: "user", content: query, }, ], verbose: true, }, langGraphConfig ); const response = agentOutput.messages[agentOutput.messages.length - 1].content; console.log(response); } } main(); ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/cloudsql/cloudsqlwaitforoperation.md: -------------------------------------------------------------------------------- ```markdown --- title: "cloud-sql-wait-for-operation" type: docs weight: 10 description: > Wait for a long-running Cloud SQL operation to complete. --- The `cloud-sql-wait-for-operation` tool is a utility tool that waits for a long-running Cloud SQL operation to complete. It does this by polling the Cloud SQL Admin API operation status endpoint until the operation is finished, using exponential backoff. ## Example ```yaml tools: cloudsql-operations-get: kind: cloud-sql-wait-for-operation source: my-cloud-sql-source description: "This will poll on operations API until the operation is done. For checking operation status we need projectId and operationId. Once instance is created give follow up steps on how to use the variables to bring data plane MCP server up in local and remote setup." delay: 1s maxDelay: 4m multiplier: 2 maxRetries: 10 ``` ## Reference | **field** | **type** | **required** | **description** | | ----------- | :------: | :----------: | ---------------------------------------------------------------------------------------------------------------- | | kind | string | true | Must be "cloud-sql-wait-for-operation". | | source | string | true | The name of a `cloud-sql-admin` source to use for authentication. | | description | string | false | A description of the tool. | | delay | duration | false | The initial delay between polling requests (e.g., `3s`). Defaults to 3 seconds. | | maxDelay | duration | false | The maximum delay between polling requests (e.g., `4m`). Defaults to 4 minutes. | | multiplier | float | false | The multiplier for the polling delay. The delay is multiplied by this value after each request. Defaults to 2.0. | | maxRetries | int | false | The maximum number of polling attempts before giving up. Defaults to 10. | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/bigquery/bigquery-list-table-ids.md: -------------------------------------------------------------------------------- ```markdown --- title: "bigquery-list-table-ids" type: docs weight: 1 description: > A "bigquery-list-table-ids" tool returns table IDs in a given BigQuery dataset. aliases: - /resources/tools/bigquery-list-table-ids --- ## About A `bigquery-list-table-ids` tool returns table IDs in a given BigQuery dataset. It's compatible with the following sources: - [bigquery](../../sources/bigquery.md) `bigquery-list-table-ids` accepts the following parameters: - **`dataset`** (required): Specifies the dataset from which to list table IDs. - **`project`** (optional): Defines the Google Cloud project ID. If not provided, the tool defaults to the project from the source configuration. The tool's behavior regarding these parameters is influenced by the `allowedDatasets` restriction on the `bigquery` source: - **Without `allowedDatasets` restriction:** The tool can list tables from any dataset specified by the `dataset` and `project` parameters. - **With `allowedDatasets` restriction:** Before listing tables, the tool verifies that the requested dataset is in the allowed list. If it is not, the request is denied. If only one dataset is specified in the `allowedDatasets` list, it will be used as the default value for the `dataset` parameter. ## Example ```yaml tools: bigquery_list_table_ids: kind: bigquery-list-table-ids source: my-bigquery-source description: Use this tool to get table metadata. ``` ## Reference | **field** | **type** | **required** | **description** | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| | kind | string | true | Must be "bigquery-list-table-ids". | | source | string | true | Name of the source the SQL should execute on. | | description | string | true | Description of the tool that is passed to the LLM. | ``` -------------------------------------------------------------------------------- /internal/tools/redis/redis_test.go: -------------------------------------------------------------------------------- ```go // Copyright 2024 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. package redis_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/redis" ) func TestParseFromYamlRedis(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: redis_tool: kind: redis source: my-redis-instance description: some description commands: - [SET, greeting, "hello, {{.name}}"] - [GET, id] parameters: - name: name type: string description: user name `, want: server.ToolConfigs{ "redis_tool": redis.Config{ Name: "redis_tool", Kind: "redis", Source: "my-redis-instance", Description: "some description", AuthRequired: []string{}, Commands: [][]string{{"SET", "greeting", "hello, {{.name}}"}, {"GET", "id"}}, Parameters: []tools.Parameter{ tools.NewStringParameter("name", "user name"), }, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- ```yaml # 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 # # https://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. name: ✨ Feature Request description: Suggest an idea for new or improved behavior. title: "<brief summary of the proposed feature>" labels: ["type: feature request"] type: feature body: - type: markdown attributes: value: | Thanks for helping us improve! 🙏 Please answer these questions and provide as much information as possible about your feature request. - id: preamble type: checkboxes attributes: label: Prerequisites description: | Please run through the following list and make sure you've tried the usual "quick fixes": options: - label: "Search the [current open issues](https://github.com/googleapis/genai-toolbox/issues)" required: true - type: textarea id: use-case attributes: label: What are you trying to do that currently feels hard or impossible? description: "A clear and concise description of what the end goal for the feature should be -- avoid generalizing and try to provide a specific use-case." validations: required: true - type: textarea id: suggested-solution attributes: label: Suggested Solution(s) description: "If you have a suggestion for how this use-case can be solved, please feel free to include it." - type: textarea id: alternatives-considered attributes: label: Alternatives Considered description: "Are there any workaround or third party tools to replicate this behavior? Why would adding this feature be preferred over them?" - type: textarea id: additional-details attributes: label: Additional Details description: "Any additional information we should know? Please reference it here (issues, PRs, descriptions, or screenshots)" ``` -------------------------------------------------------------------------------- /internal/tools/valkey/valkey_test.go: -------------------------------------------------------------------------------- ```go // Copyright 2024 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. package valkey_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/valkey" ) func TestParseFromYamlvalkey(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: valkey_tool: kind: valkey source: my-valkey-instance description: some description commands: - [SET, greeting, "hello, {{.name}}"] - [GET, id] parameters: - name: name type: string description: user name `, want: server.ToolConfigs{ "valkey_tool": valkey.Config{ Name: "valkey_tool", Kind: "valkey", Source: "my-valkey-instance", Description: "some description", AuthRequired: []string{}, Commands: [][]string{{"SET", "greeting", "hello, {{.name}}"}, {"GET", "id"}}, Parameters: []tools.Parameter{ tools.NewStringParameter("name", "user name"), }, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/looker/looker-get-looks.md: -------------------------------------------------------------------------------- ```markdown --- title: "looker-get-looks" type: docs weight: 1 description: > "looker-get-looks" searches for saved Looks in a Looker source. aliases: - /resources/tools/looker-get-looks --- ## About The `looker-get-looks` tool searches for a saved Look by name or description. It's compatible with the following sources: - [looker](../../sources/looker.md) `looker-get-looks` takes four parameters, the `title`, `desc`, `limit` and `offset`. Title and description use SQL style wildcards and are case insensitive. Limit and offset are used to page through a larger set of matches and default to 100 and 0. ## Example ```yaml tools: get_looks: kind: looker-get-looks source: looker-source description: | get_looks Tool This tool is used to search for saved looks in a Looker instance. String search params use case-insensitive matching. String search params can contain % and '_' as SQL LIKE pattern match wildcard expressions. example="dan%" will match "danger" and "Danzig" but not "David" example="D_m%" will match "Damage" and "dump". Most search params can accept "IS NULL" and "NOT NULL" as special expressions to match or exclude (respectively) rows where the column is null. The limit and offset are used to paginate the results. The result of the get_looks tool is a list of json objects. ``` ## Reference | **field** | **type** | **required** | **description** | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| | kind | string | true | Must be "looker-get-looks" | | source | string | true | Name of the source the SQL should execute on. | | description | string | true | Description of the tool that is passed to the LLM. | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/clickhouse/clickhouse-list-tables.md: -------------------------------------------------------------------------------- ```markdown --- title: "clickhouse-list-tables" type: docs weight: 4 description: > A "clickhouse-list-tables" tool lists all tables in a specific ClickHouse database. aliases: - /resources/tools/clickhouse-list-tables --- ## About A `clickhouse-list-tables` tool lists all available tables in a specified ClickHouse database. It's compatible with the [clickhouse](../../sources/clickhouse.md) source. This tool executes the `SHOW TABLES FROM <database>` command and returns a list of all tables in the specified database that are accessible to the configured user, making it useful for schema exploration and table discovery tasks. ## Example ```yaml tools: list_clickhouse_tables: kind: clickhouse-list-tables source: my-clickhouse-instance description: List all tables in a specific ClickHouse database ``` ## Parameters | **parameter** | **type** | **required** | **description** | |---------------|:--------:|:------------:|---------------------------------------------| | database | string | true | The database to list tables from. | ## Return Value The tool returns an array of objects, where each object contains: - `name`: The name of the table - `database`: The database the table belongs to Example response: ```json [ {"name": "users", "database": "analytics"}, {"name": "events", "database": "analytics"}, {"name": "products", "database": "analytics"}, {"name": "orders", "database": "analytics"} ] ``` ## Reference | **field** | **type** | **required** | **description** | |--------------------|:------------------:|:------------:|-----------------------------------------------------------| | kind | string | true | Must be "clickhouse-list-tables". | | source | string | true | Name of the ClickHouse source to list tables from. | | description | string | true | Description of the tool that is passed to the LLM. | | authRequired | array of string | false | Authentication services required to use this tool. | | parameters | array of Parameter | false | Parameters for the tool (see Parameters section above). | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/mongodb/mongodb-insert-one.md: -------------------------------------------------------------------------------- ```markdown --- title: "mongodb-insert-one" type: docs weight: 1 description: > A "mongodb-insert-one" tool inserts a single new document into a MongoDB collection. aliases: - /resources/tools/mongodb-insert-one --- ## About The `mongodb-insert-one` tool inserts a **single new document** into a specified MongoDB collection. This tool takes one required parameter named `data`, which must be a string containing the JSON object you want to insert. Upon successful insertion, the tool returns the unique `_id` of the newly created document. This tool is compatible with the following source kind: * [`mongodb`](../../sources/mongodb.md) ## Example Here is an example configuration for a tool that adds a new user to a `users` collection. ```yaml tools: create_new_user: kind: mongodb-insert-one source: my-mongo-source description: Creates a new user record in the database. database: user_data collection: users canonical: false ``` An LLM would call this tool by providing the document as a JSON string in the `data` parameter, like this: `tool_code: create_new_user(data='{"email": "[email protected]", "name": "Jane Doe", "status": "active"}')` ## Reference | **field** | **type** | **required** | **description** | |:------------|:---------|:-------------|:---------------------------------------------------------------------------------------------------| | kind | string | true | Must be `mongodb-insert-one`. | | source | string | true | The name of the `mongodb` source to use. | | description | string | true | A description of the tool that is passed to the LLM. | | database | string | true | The name of the MongoDB database containing the collection. | | collection | string | true | The name of the MongoDB collection into which the document will be inserted. | | canonical | bool | true | Determines if the data string is parsed using MongoDB's Canonical or Relaxed Extended JSON format. | ``` -------------------------------------------------------------------------------- /docs/en/resources/sources/firebird.md: -------------------------------------------------------------------------------- ```markdown --- title: "Firebird" type: docs weight: 1 description: > Firebird is a powerful, cross-platform, and open-source relational database. --- ## About [Firebird][fb-docs] is a relational database management system offering many ANSI SQL standard features that runs on Linux, Windows, and a variety of Unix platforms. It is known for its small footprint, powerful features, and easy maintenance. [fb-docs]: https://firebirdsql.org/ ## Available Tools - [`firebird-sql`](../tools/firebird/firebird-sql.md) Execute SQL queries as prepared statements in Firebird. - [`firebird-execute-sql`](../tools/firebird/firebird-execute-sql.md) Run parameterized SQL statements in Firebird. ## Requirements ### Database User This source uses standard authentication. You will need to [create a Firebird user][fb-users] to login to the database with. [fb-users]: https://www.firebirdsql.org/refdocs/langrefupd25-security-sql-user-mgmt.html#langrefupd25-security-create-user ## Example ```yaml sources: my_firebird_db: kind: firebird host: "localhost" port: 3050 database: "/path/to/your/database.fdb" user: ${FIREBIRD_USER} password: ${FIREBIRD_PASS} ``` {{< notice tip >}} Use environment variable replacement with the format ${ENV_NAME} instead of hardcoding your secrets into the configuration file. {{< /notice >}} ## Reference | **field** | **type** | **required** | **description** | |-----------|:--------:|:------------:|------------------------------------------------------------------------------| | kind | string | true | Must be "firebird". | | host | string | true | IP address to connect to (e.g. "127.0.0.1") | | port | string | true | Port to connect to (e.g. "3050") | | database | string | true | Path to the Firebird database file (e.g. "/var/lib/firebird/data/test.fdb"). | | user | string | true | Name of the Firebird user to connect as (e.g. "SYSDBA"). | | password | string | true | Password of the Firebird user (e.g. "masterkey"). | ``` -------------------------------------------------------------------------------- /internal/tools/oceanbase/oceanbasesql/oceanbasesql_test.go: -------------------------------------------------------------------------------- ```go // 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. package oceanbasesql_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/oceanbase/oceanbasesql" ) // Test parsing OceanBase SQL tool config from YAML. func TestParseFromYamlOceanBaseSql(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: oceanbase-sql source: my-instance description: some description statement: select * from t where id = ? parameters: - name: id type: string description: id param `, want: server.ToolConfigs{ "example_tool": oceanbasesql.Config{ Name: "example_tool", Kind: "oceanbase-sql", Source: "my-instance", Description: "some description", Statement: "select * from t where id = ?", AuthRequired: []string{}, Parameters: []tools.Parameter{ tools.NewStringParameter("id", "id param"), }, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /docs/en/getting-started/local_quickstart_go.md: -------------------------------------------------------------------------------- ```markdown --- title: "Go Quickstart (Local)" type: docs weight: 4 description: > How to get started running Toolbox locally with [Go](https://github.com/googleapis/mcp-toolbox-sdk-go), PostgreSQL, and orchestration frameworks such as [LangChain Go](https://tmc.github.io/langchaingo/docs/), [GenkitGo](https://genkit.dev/go/docs/get-started-go/), [Go GenAI](https://github.com/googleapis/go-genai) and [OpenAI Go](https://github.com/openai/openai-go). --- ## Before you begin This guide assumes you have already done the following: 1. Installed [Go (v1.24.2 or higher)]. 1. Installed [PostgreSQL 16+ and the `psql` client][install-postgres]. [Go (v1.24.2 or higher)]: https://go.dev/doc/install [install-postgres]: https://www.postgresql.org/download/ ### Cloud Setup (Optional) {{< regionInclude "quickstart/shared/cloud_setup.md" "cloud_setup" >}} ## Step 1: Set up your database {{< regionInclude "quickstart/shared/database_setup.md" "database_setup" >}} ## Step 2: Install and configure Toolbox {{< regionInclude "quickstart/shared/configure_toolbox.md" "configure_toolbox" >}} ## Step 3: Connect your agent to Toolbox In this section, we will write and run an agent that will load the Tools from Toolbox. 1. Initialize a go module: ```bash go mod init main ``` 1. In a new terminal, install the [SDK](https://pkg.go.dev/github.com/googleapis/mcp-toolbox-sdk-go). ```bash go get github.com/googleapis/mcp-toolbox-sdk-go ``` 1. Create a new file named `hotelagent.go` and copy the following code to create an agent: {{< tabpane persist=header >}} {{< tab header="LangChain Go" lang="go" >}} {{< include "quickstart/go/langchain/quickstart.go" >}} {{< /tab >}} {{< tab header="Genkit Go" lang="go" >}} {{< include "quickstart/go/genkit/quickstart.go" >}} {{< /tab >}} {{< tab header="Go GenAI" lang="go" >}} {{< include "quickstart/go/genAI/quickstart.go" >}} {{< /tab >}} {{< tab header="OpenAI Go" lang="go" >}} {{< include "quickstart/go/openAI/quickstart.go" >}} {{< /tab >}} {{< /tabpane >}} 1. Ensure all dependencies are installed: ```sh go mod tidy ``` 1. Run your agent, and observe the results: ```sh go run hotelagent.go ``` {{< notice info >}} For more information, visit the [Go SDK repo](https://github.com/googleapis/mcp-toolbox-sdk-go). {{</ notice >}} ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/bigquery/bigquery-get-table-info.md: -------------------------------------------------------------------------------- ```markdown --- title: "bigquery-get-table-info" type: docs weight: 1 description: > A "bigquery-get-table-info" tool retrieves metadata for a BigQuery table. aliases: - /resources/tools/bigquery-get-table-info --- ## About A `bigquery-get-table-info` tool retrieves metadata for a BigQuery table. It's compatible with the following sources: - [bigquery](../../sources/bigquery.md) `bigquery-get-table-info` accepts the following parameters: - **`table`** (required): The name of the table for which to retrieve metadata. - **`dataset`** (required): The dataset containing the specified table. - **`project`** (optional): The Google Cloud project ID. If not provided, the tool defaults to the project from the source configuration. The tool's behavior regarding these parameters is influenced by the `allowedDatasets` restriction on the `bigquery` source: - **Without `allowedDatasets` restriction:** The tool can retrieve metadata for any table specified by the `table`, `dataset`, and `project` parameters. - **With `allowedDatasets` restriction:** Before retrieving metadata, the tool verifies that the requested dataset is in the allowed list. If it is not, the request is denied. If only one dataset is specified in the `allowedDatasets` list, it will be used as the default value for the `dataset` parameter. ## Example ```yaml tools: bigquery_get_table_info: kind: bigquery-get-table-info source: my-bigquery-source description: Use this tool to get table metadata. ``` ## Reference | **field** | **type** | **required** | **description** | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| | kind | string | true | Must be "bigquery-get-table-info". | | source | string | true | Name of the source the SQL should execute on. | | description | string | true | Description of the tool that is passed to the LLM. | ``` -------------------------------------------------------------------------------- /docs/en/getting-started/quickstart/go/quickstart_test.go: -------------------------------------------------------------------------------- ```go // 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. package main import ( "bytes" "os" "os/exec" "path/filepath" "strings" "testing" ) func TestQuickstartSample(t *testing.T) { framework := os.Getenv("ORCH_NAME") if framework == "" { t.Skip("Skipping test: ORCH_NAME environment variable is not set.") } t.Logf("--- Testing: %s ---", framework) if framework == "openAI" { if os.Getenv("OPENAI_API_KEY") == "" { t.Skip("Skipping test: OPENAI_API_KEY environment variable is not set for openAI framework.") } } else { if os.Getenv("GOOGLE_API_KEY") == "" { t.Skipf("Skipping test for %s: GOOGLE_API_KEY environment variable is not set.", framework) } } sampleDir := filepath.Join(".", framework) if _, err := os.Stat(sampleDir); os.IsNotExist(err) { t.Fatalf("Test setup failed: directory for framework '%s' not found.", framework) } cmd := exec.Command("go", "run", ".") cmd.Dir = sampleDir var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() actualOutput := stdout.String() if err != nil { t.Fatalf("Script execution failed with error: %v\n--- STDERR ---\n%s", err, stderr.String()) } if len(actualOutput) == 0 { t.Fatal("Script ran successfully but produced no output.") } goldenFile, err := os.ReadFile("../golden.txt") if err != nil { t.Fatalf("Could not read golden.txt to check for keywords: %v", err) } keywords := strings.Split(string(goldenFile), "\n") var missingKeywords []string outputLower := strings.ToLower(actualOutput) for _, keyword := range keywords { kw := strings.TrimSpace(keyword) if kw != "" && !strings.Contains(outputLower, strings.ToLower(kw)) { missingKeywords = append(missingKeywords, kw) } } if len(missingKeywords) > 0 { t.Fatalf("FAIL: The following keywords were missing from the output: [%s]", strings.Join(missingKeywords, ", ")) } } ``` -------------------------------------------------------------------------------- /docs/en/getting-started/configure.md: -------------------------------------------------------------------------------- ```markdown --- title: "Configuration" type: docs weight: 6 description: > How to configure Toolbox's tools.yaml file. --- The primary way to configure Toolbox is through the `tools.yaml` file. If you have multiple files, you can tell toolbox which to load with the `--tools-file tools.yaml` flag. You can find more detailed reference documentation to all resource types in the [Resources](../resources/). ### Using Environment Variables To avoid hardcoding certain secret fields like passwords, usernames, API keys etc., you could use environment variables instead with the format `${ENV_NAME}`. ```yaml user: ${USER_NAME} password: ${PASSWORD} ``` A default value can be specified like `${ENV_NAME:default}`. ```yaml port: ${DB_PORT:3306} ``` ### Sources The `sources` section of your `tools.yaml` defines what data sources your Toolbox should have access to. Most tools will have at least one source to execute against. ```yaml sources: my-pg-source: kind: postgres host: 127.0.0.1 port: 5432 database: toolbox_db user: ${USER_NAME} password: ${PASSWORD} ``` For more details on configuring different types of sources, see the [Sources](../resources/sources/). ### Tools The `tools` section of your `tools.yaml` defines the actions your agent can take: what kind of tool it is, which source(s) it affects, what parameters it uses, etc. ```yaml tools: search-hotels-by-name: kind: postgres-sql source: my-pg-source description: Search for hotels based on name. parameters: - name: name type: string description: The name of the hotel. statement: SELECT * FROM hotels WHERE name ILIKE '%' || $1 || '%'; ``` For more details on configuring different types of tools, see the [Tools](../resources/tools/). ### Toolsets The `toolsets` section of your `tools.yaml` allows you to define groups of tools that you want to be able to load together. This can be useful for defining different sets for different agents or different applications. ```yaml toolsets: my_first_toolset: - my_first_tool - my_second_tool my_second_toolset: - my_second_tool - my_third_tool ``` You can load toolsets by name: ```python # This will load all tools all_tools = client.load_toolset() # This will only load the tools listed in 'my_second_toolset' my_second_toolset = client.load_toolset("my_second_toolset") ``` ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/looker/looker-get-dashboards.md: -------------------------------------------------------------------------------- ```markdown --- title: "looker-get-dashboards" type: docs weight: 1 description: > "looker-get-dashboards" tool searches for a saved Dashboard by name or description. aliases: - /resources/tools/looker-get-dashboards --- ## About The `looker-get-dashboards` tool searches for a saved Dashboard by name or description. It's compatible with the following sources: - [looker](../../sources/looker.md) `looker-get-dashboards` takes four parameters, the `title`, `desc`, `limit` and `offset`. Title and description use SQL style wildcards and are case insensitive. Limit and offset are used to page through a larger set of matches and default to 100 and 0. ## Example ```yaml tools: get_dashboards: kind: looker-get-dashboards source: looker-source description: | get_dashboards Tool This tool is used to search for saved dashboards in a Looker instance. String search params use case-insensitive matching. String search params can contain % and '_' as SQL LIKE pattern match wildcard expressions. example="dan%" will match "danger" and "Danzig" but not "David" example="D_m%" will match "Damage" and "dump". Most search params can accept "IS NULL" and "NOT NULL" as special expressions to match or exclude (respectively) rows where the column is null. The limit and offset are used to paginate the results. The result of the get_dashboards tool is a list of json objects. ``` ## Reference | **field** | **type** | **required** | **description** | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| | kind | string | true | Must be "looker-get-dashboards" | | source | string | true | Name of the source the SQL should execute on. | | description | string | true | Description of the tool that is passed to the LLM. | ``` -------------------------------------------------------------------------------- /internal/prebuiltconfigs/tools/bigquery.yaml: -------------------------------------------------------------------------------- ```yaml # 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. sources: bigquery-source: kind: "bigquery" project: ${BIGQUERY_PROJECT} location: ${BIGQUERY_LOCATION:} useClientOAuth: ${BIGQUERY_USE_CLIENT_OAUTH:false} tools: analyze_contribution: kind: bigquery-analyze-contribution source: bigquery-source description: Use this tool to analyze the contribution about changes to key metrics in multi-dimensional data. ask_data_insights: kind: bigquery-conversational-analytics source: bigquery-source description: | Use this tool to perform data analysis, get insights, or answer complex questions about the contents of specific BigQuery tables. execute_sql: kind: bigquery-execute-sql source: bigquery-source description: Use this tool to execute sql statement. forecast: kind: bigquery-forecast source: bigquery-source description: Use this tool to forecast time series data. get_dataset_info: kind: bigquery-get-dataset-info source: bigquery-source description: Use this tool to get dataset metadata. get_table_info: kind: bigquery-get-table-info source: bigquery-source description: Use this tool to get table metadata. list_dataset_ids: kind: bigquery-list-dataset-ids source: bigquery-source description: Use this tool to list datasets. list_table_ids: kind: bigquery-list-table-ids source: bigquery-source description: Use this tool to list tables. search_catalog: kind: bigquery-search-catalog source: bigquery-source description: Use this tool to find tables, views, models, routines or connections. toolsets: bigquery_database_tools: - analyze_contribution - ask_data_insights - execute_sql - forecast - get_dataset_info - get_table_info - list_dataset_ids - list_table_ids - search_catalog ``` -------------------------------------------------------------------------------- /.github/workflows/docs_deploy.yaml: -------------------------------------------------------------------------------- ```yaml # 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. name: "docs" permissions: contents: write on: push: branches: - main paths: - 'docs/**' - 'github/workflows/docs**' - '.hugo/**' # Allow triggering manually. workflow_dispatch: jobs: deploy: runs-on: ubuntu-24.04 defaults: run: working-directory: .hugo concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod - name: Setup Hugo uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3 with: hugo-version: "0.145.0" extended: true - name: Setup Node uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5 with: node-version: "22" - name: Cache dependencies uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - run: npm ci - run: hugo --minify env: HUGO_BASEURL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/ HUGO_RELATIVEURLS: false - name: Deploy uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: .hugo/public # Do not delete previews on each production deploy. # CSS or JS changes will require manual clean-up. keep_files: true commit_message: "deploy: ${{ github.event.head_commit.message }}" ``` -------------------------------------------------------------------------------- /docs/en/resources/sources/sqlite.md: -------------------------------------------------------------------------------- ```markdown --- title: "SQLite" linkTitle: "SQLite" type: docs weight: 1 description: > SQLite is a C-language library that implements a small, fast, self-contained, high-reliability, full-featured, SQL database engine. --- ## About [SQLite](https://sqlite.org/) is a software library that provides a relational database management system. The lite in SQLite means lightweight in terms of setup, database administration, and required resources. SQLite has the following notable characteristics: - Self-contained with no external dependencies - Serverless - the SQLite library accesses its storage files directly - Single database file that can be easily copied or moved - Zero-configuration - no setup or administration needed - Transactional with ACID properties ## Available Tools - [`sqlite-sql`](../tools/sqlite/sqlite-sql.md) Run SQL queries against a local SQLite database. - [`sqlite-execute-sql`](../tools/sqlite/sqlite-execute-sql.md) Run parameterized SQL statements in SQlite. ### Pre-built Configurations - [SQLite using MCP](../../how-to/connect-ide/sqlite_mcp.md) Connect your IDE to SQlite using Toolbox. ## Requirements ### Database File You need a SQLite database file. This can be: - An existing database file - A path where a new database file should be created - `:memory:` for an in-memory database ## Example ```yaml sources: my-sqlite-db: kind: "sqlite" database: "/path/to/database.db" ``` For an in-memory database: ```yaml sources: my-sqlite-memory-db: kind: "sqlite" database: ":memory:" ``` ## Reference ### Configuration Fields | **field** | **type** | **required** | **description** | |-----------|:--------:|:------------:|---------------------------------------------------------------------------------------------------------------------| | kind | string | true | Must be "sqlite". | | database | string | true | Path to SQLite database file, or ":memory:" for an in-memory database. | ### Connection Properties SQLite connections are configured with these defaults for optimal performance: - `MaxOpenConns`: 1 (SQLite only supports one writer at a time) - `MaxIdleConns`: 1 ``` -------------------------------------------------------------------------------- /docs/en/getting-started/quickstart/js/llamaindex/quickstart.js: -------------------------------------------------------------------------------- ```javascript import { gemini, GEMINI_MODEL } from "@llamaindex/google"; import { agent } from "@llamaindex/workflow"; import { createMemory, staticBlock, tool } from "llamaindex"; import { ToolboxClient } from "@toolbox-sdk/core"; const TOOLBOX_URL = "http://127.0.0.1:5000"; // Update if needed const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || 'your-api-key'; // Replace it with your API key const prompt = ` You're a helpful hotel assistant. You handle hotel searching, booking and cancellations. When the user searches for a hotel, mention its name, id, location and price tier. Always mention hotel ids while performing any searches — this is very important for operations. For any bookings or cancellations, please provide the appropriate confirmation. Update check-in or check-out dates if mentioned by the user. Don't ask for confirmations from the user. `; const queries = [ "Find hotels in Basel with Basel in its name.", "Can you book the Hilton Basel for me?", "Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.", "My check in dates would be from April 10, 2024 to April 19, 2024.", ]; export async function main() { // Connect to MCP Toolbox const client = new ToolboxClient(TOOLBOX_URL); const toolboxTools = await client.loadToolset("my-toolset"); const tools = toolboxTools.map((toolboxTool) => { return tool({ name: toolboxTool.getName(), description: toolboxTool.getDescription(), parameters: toolboxTool.getParamSchema(), execute: toolboxTool, }); }); // Initialize LLM const llm = gemini({ model: GEMINI_MODEL.GEMINI_2_0_FLASH, apiKey: GOOGLE_API_KEY, }); const memory = createMemory({ memoryBlocks: [ staticBlock({ content: prompt, }), ], }); // Create the Agent const myAgent = agent({ tools: tools, llm, memory, systemPrompt: prompt, }); for (const query of queries) { const result = await myAgent.run(query); const output = result.data.result; console.log(`\nUser: ${query}`); if (typeof output === "string") { console.log(output.trim()); } else if (typeof output === "object" && "text" in output) { console.log(output.text.trim()); } else { console.log(JSON.stringify(output)); } } //You may observe some extra logs during execution due to the run method provided by Llama. console.log("Agent run finished."); } main(); ``` -------------------------------------------------------------------------------- /internal/tools/neo4j/neo4jcypher/neo4jcypher_test.go: -------------------------------------------------------------------------------- ```go // Copyright 2024 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. package neo4jcypher import ( "testing" "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" "github.com/googleapis/genai-toolbox/internal/tools" ) func TestParseFromYamlNeo4j(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: neo4j-cypher source: my-neo4j-instance description: some tool description authRequired: - my-google-auth-service - other-auth-service statement: | MATCH (c:Country) WHERE c.name = $country RETURN c.id as id; parameters: - name: country type: string description: country parameter description `, want: server.ToolConfigs{ "example_tool": Config{ Name: "example_tool", Kind: "neo4j-cypher", Source: "my-neo4j-instance", Description: "some tool description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, Statement: "MATCH (c:Country) WHERE c.name = $country RETURN c.id as id;\n", Parameters: []tools.Parameter{ tools.NewStringParameter("country", "country parameter description"), }, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err = yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /tests/source.go: -------------------------------------------------------------------------------- ```go // 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. // Package tests contains end to end tests meant to verify the Toolbox Server // works as expected when executed as a binary. package tests import ( "context" "fmt" "regexp" "strings" "testing" "time" "cloud.google.com/go/cloudsqlconn" "github.com/googleapis/genai-toolbox/internal/testutils" ) // RunSourceConnection test for source connection func RunSourceConnectionTest(t *testing.T, sourceConfig map[string]any, toolKind string) error { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() var args []string // Write config into a file and pass it to command toolsFile := map[string]any{ "sources": map[string]any{ "my-instance": sourceConfig, }, "tools": map[string]any{ "my-simple-tool": map[string]any{ "kind": toolKind, "source": "my-instance", "description": "Simple tool to test end to end functionality.", "statement": "SELECT 1;", }, }, } cmd, cleanup, err := StartCmd(ctx, toolsFile, args...) if err != nil { return fmt.Errorf("command initialization returned an error: %s", err) } defer cleanup() waitCtx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() out, err := testutils.WaitForString(waitCtx, regexp.MustCompile(`Server ready to serve`), cmd.Out) if err != nil { t.Logf("toolbox command logs: \n%s", out) return fmt.Errorf("toolbox didn't start successfully: %s", err) } return nil } // GetCloudSQLDialOpts returns cloud sql connector's dial option for ip type. func GetCloudSQLDialOpts(ipType string) ([]cloudsqlconn.DialOption, error) { switch strings.ToLower(ipType) { case "private": return []cloudsqlconn.DialOption{cloudsqlconn.WithPrivateIP()}, nil case "public": return []cloudsqlconn.DialOption{cloudsqlconn.WithPublicIP()}, nil default: return nil, fmt.Errorf("invalid ipType %s", ipType) } } ``` -------------------------------------------------------------------------------- /docs/en/how-to/connect_via_geminicli.md: -------------------------------------------------------------------------------- ```markdown --- title: Connect via Gemini CLI Extensions type: docs weight: 2 description: "Connect to Toolbox via Gemini CLI Extensions." --- ## Gemini CLI Extensions [Gemini CLI][gemini-cli] is an open-source AI agent designed to assist with development workflows by assisting with coding, debugging, data exploration, and content creation. Its mission is to provide an agentic interface for interacting with database and analytics services and popular open-source databases. ### How extensions work Gemini CLI is highly extensible, allowing for the addition of new tools and capabilities through extensions. You can load the extensions from a GitHub URL, a local directory, or a configurable registry. They provide new tools, slash commands, and prompts to assist with your workflow. Use the Gemini CLI Extensions to load prebuilt or custom tools to interact with your databases. [gemini-cli]: https://google-gemini.github.io/gemini-cli/ Below are a list of Gemini CLI Extensions powered by MCP Toolbox: * [alloydb](https://github.com/gemini-cli-extensions/alloydb) * [alloydb-observability](https://github.com/gemini-cli-extensions/alloydb-observability) * [bigquery-conversational-analytics](https://github.com/gemini-cli-extensions/bigquery-conversational-analytics) * [bigquery-data-analytics](https://github.com/gemini-cli-extensions/bigquery-data-analytics) * [cloud-sql-mysql](https://github.com/gemini-cli-extensions/cloud-sql-mysql) * [cloud-sql-mysql-observability](https://github.com/gemini-cli-extensions/cloud-sql-mysql-observability) * [cloud-sql-postgresql](https://github.com/gemini-cli-extensions/cloud-sql-postgresql) * [cloud-sql-postgresql-observability](https://github.com/gemini-cli-extensions/cloud-sql-postgresql-observability) * [cloud-sql-sqlserver](https://github.com/gemini-cli-extensions/cloud-sql-sqlserver) * [cloud-sql-sqlserver-observability](https://github.com/gemini-cli-extensions/cloud-sql-sqlserver-observability) * [dataplex](https://github.com/gemini-cli-extensions/dataplex) * [firestore-native](https://github.com/gemini-cli-extensions/firestore-native) * [looker](https://github.com/gemini-cli-extensions/looker) * [mcp-toolbox](https://github.com/gemini-cli-extensions/mcp-toolbox) * [mysql](https://github.com/gemini-cli-extensions/mysql) * [postgres](https://github.com/gemini-cli-extensions/postgres) * [spanner](https://github.com/gemini-cli-extensions/spanner) * [sql-server](https://github.com/gemini-cli-extensions/sql-server) ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/looker/looker-get-dimensions.md: -------------------------------------------------------------------------------- ```markdown --- title: "looker-get-dimensions" type: docs weight: 1 description: > A "looker-get-dimensions" tool returns all the dimensions from a given explore in a given model in the source. aliases: - /resources/tools/looker-get-dimensions --- ## About A `looker-get-dimensions` tool returns all the dimensions from a given explore in a given model in the source. It's compatible with the following sources: - [looker](../../sources/looker.md) `looker-get-dimensions` accepts two parameters, the `model` and the `explore`. ## Example ```yaml tools: get_dimensions: kind: looker-get-dimensions source: looker-source description: | The get_dimensions tool retrieves the list of dimensions defined in an explore. It takes two parameters, the model_name looked up from get_models and the explore_name looked up from get_explores. If this returns a suggestions field for a dimension, the contents of suggestions can be used as filters for this field. If this returns a suggest_explore and suggest_dimension, a query against that explore and dimension can be used to find valid filters for this field. ``` The response is a json array with the following elements: ```json { "name": "field name", "description": "field description", "type": "field type", "label": "field label", "label_short": "field short label", "tags": ["tags", ...], "synonyms": ["synonyms", ...], "suggestions": ["suggestion", ...], "suggest_explore": "explore", "suggest_dimension": "dimension" } ``` ## Reference | **field** | **type** | **required** | **description** | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| | kind | string | true | Must be "looker-get-dimensions". | | source | string | true | Name of the source the SQL should execute on. | | description | string | true | Description of the tool that is passed to the LLM. | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/mysql/mysql-list-tables.md: -------------------------------------------------------------------------------- ```markdown --- title: "mysql-list-tables" type: docs weight: 1 description: > The "mysql-list-tables" tool lists schema information for all or specified tables in a MySQL database. aliases: - /resources/tools/mysql-list-tables --- ## About The `mysql-list-tables` tool retrieves schema information for all or specified tables in a MySQL database. It is compatible with any of the following sources: - [cloud-sql-mysql](../../sources/cloud-sql-mysql.md) - [mysql](../../sources/mysql.md) `mysql-list-tables` lists detailed schema information (object type, columns, constraints, indexes, triggers, owner, comment) as JSON for user-created tables (ordinary or partitioned). Filters by a comma-separated list of names. If names are omitted, it lists all tables in user schemas. The output format can be set to `simple` which will return only the table names or `detailed` which is the default. The tool takes the following input parameters: | Parameter | Type | Description | Required | |:----------------|:-------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------| | `table_names` | string | Filters by a comma-separated list of names. By default, it lists all tables in user schemas. Default: `""` | No | | `output_format` | string | Indicate the output format of table schema. `simple` will return only the table names, `detailed` will return the full table information. Default: `detailed`. | No | ## Example ```yaml tools: mysql_list_tables: kind: mysql-list-tables source: mysql-source description: Use this tool to retrieve schema information for all or specified tables. Output format can be simple (only table names) or detailed. ``` ## Reference | **field** | **type** | **required** | **description** | |-------------|:--------:|:------------:|------------------------------------------------------| | kind | string | true | Must be "mysql-list-tables". | | source | string | true | Name of the source the SQL should execute on. | | description | string | true | Description of the tool that is passed to the agent. | ``` -------------------------------------------------------------------------------- /internal/tools/spanner/spannerexecutesql/spannerexecutesql_test.go: -------------------------------------------------------------------------------- ```go // Copyright 2024 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. package spannerexecutesql_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" "github.com/googleapis/genai-toolbox/internal/tools/spanner/spannerexecutesql" ) func TestParseFromYamlExecuteSql(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: spanner-execute-sql source: my-spanner-instance description: some description `, want: server.ToolConfigs{ "example_tool": spannerexecutesql.Config{ Name: "example_tool", Kind: "spanner-execute-sql", Source: "my-spanner-instance", Description: "some description", AuthRequired: []string{}, ReadOnly: false, }, }, }, { desc: "read only set to true", in: ` tools: example_tool: kind: spanner-execute-sql source: my-spanner-instance description: some description readOnly: true `, want: server.ToolConfigs{ "example_tool": spannerexecutesql.Config{ Name: "example_tool", Kind: "spanner-execute-sql", Source: "my-spanner-instance", Description: "some description", AuthRequired: []string{}, ReadOnly: true, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/mongodb/mongodb-insert-many.md: -------------------------------------------------------------------------------- ```markdown --- title: "mongodb-insert-many" type: docs weight: 1 description: > A "mongodb-insert-many" tool inserts multiple new documents into a MongoDB collection. aliases: - /resources/tools/mongodb-insert-many --- ## About The `mongodb-insert-many` tool inserts **multiple new documents** into a specified MongoDB collection in a single bulk operation. This is highly efficient for adding large amounts of data at once. This tool takes one required parameter named `data`. This `data` parameter must be a string containing a **JSON array of document objects**. Upon successful insertion, the tool returns a JSON array containing the unique `_id` of **each** new document that was created. This tool is compatible with the following source kind: * [`mongodb`](../../sources/mongodb.md) --- ## Example Here is an example configuration for a tool that logs multiple events at once. ```yaml tools: log_batch_events: kind: mongodb-insert-many source: my-mongo-source description: Inserts a batch of event logs into the database. database: logging collection: events canonical: true ``` An LLM would call this tool by providing an array of documents as a JSON string in the `data` parameter, like this: `tool_code: log_batch_events(data='[{"event": "login", "user": "user1"}, {"event": "click", "user": "user2"}, {"event": "logout", "user": "user1"}]')` --- ## Reference | **field** | **type** | **required** | **description** | |:------------|:---------|:-------------|:---------------------------------------------------------------------------------------------------| | kind | string | true | Must be `mongodb-insert-many`. | | source | string | true | The name of the `mongodb` source to use. | | description | string | true | A description of the tool that is passed to the LLM. | | database | string | true | The name of the MongoDB database containing the collection. | | collection | string | true | The name of the MongoDB collection into which the documents will be inserted. | | canonical | bool | true | Determines if the data string is parsed using MongoDB's Canonical or Relaxed Extended JSON format. | ``` -------------------------------------------------------------------------------- /internal/sources/sources.go: -------------------------------------------------------------------------------- ```go // Copyright 2024 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. package sources import ( "context" "fmt" "github.com/goccy/go-yaml" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) // SourceConfigFactory defines the function signature for creating a SourceConfig. type SourceConfigFactory func(ctx context.Context, name string, decoder *yaml.Decoder) (SourceConfig, error) var sourceRegistry = make(map[string]SourceConfigFactory) // Register registers a new source kind with its factory. // It returns false if the kind is already registered. func Register(kind string, factory SourceConfigFactory) bool { if _, exists := sourceRegistry[kind]; exists { // Source with this kind already exists, do not overwrite. return false } sourceRegistry[kind] = factory return true } // DecodeConfig decodes a source configuration using the registered factory for the given kind. func DecodeConfig(ctx context.Context, kind string, name string, decoder *yaml.Decoder) (SourceConfig, error) { factory, found := sourceRegistry[kind] if !found { return nil, fmt.Errorf("unknown source kind: %q", kind) } sourceConfig, err := factory(ctx, name, decoder) if err != nil { return nil, fmt.Errorf("unable to parse source %q as %q: %w", name, kind, err) } return sourceConfig, err } // SourceConfig is the interface for configuring a source. type SourceConfig interface { SourceConfigKind() string Initialize(ctx context.Context, tracer trace.Tracer) (Source, error) } // Source is the interface for the source itself. type Source interface { SourceKind() string } // InitConnectionSpan adds a span for database pool connection initialization func InitConnectionSpan(ctx context.Context, tracer trace.Tracer, sourceKind, sourceName string) (context.Context, trace.Span) { ctx, span := tracer.Start( ctx, "toolbox/server/source/connect", trace.WithAttributes(attribute.String("source_kind", sourceKind)), trace.WithAttributes(attribute.String("source_name", sourceName)), ) return ctx, span } ``` -------------------------------------------------------------------------------- /docs/en/getting-started/quickstart/python/adk/quickstart.py: -------------------------------------------------------------------------------- ```python from google.adk.agents import Agent from google.adk.runners import Runner from google.adk.sessions import InMemorySessionService from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService from google.genai import types from toolbox_core import ToolboxSyncClient import asyncio import os # TODO(developer): replace this with your Google API key api_key = os.environ.get("GOOGLE_API_KEY") or "your-api-key" # Set your API key here os.environ["GOOGLE_API_KEY"] = api_key async def main(): with ToolboxSyncClient("http://127.0.0.1:5000") as toolbox_client: prompt = """ You're a helpful hotel assistant. You handle hotel searching, booking and cancellations. When the user searches for a hotel, mention it's name, id, location and price tier. Always mention hotel ids while performing any searches. This is very important for any operations. For any bookings or cancellations, please provide the appropriate confirmation. Be sure to update checkin or checkout dates if mentioned by the user. Don't ask for confirmations from the user. """ root_agent = Agent( model='gemini-2.0-flash-001', name='hotel_agent', description='A helpful AI assistant.', instruction=prompt, tools=toolbox_client.load_toolset("my-toolset"), ) session_service = InMemorySessionService() artifacts_service = InMemoryArtifactService() session = await session_service.create_session( state={}, app_name='hotel_agent', user_id='123' ) runner = Runner( app_name='hotel_agent', agent=root_agent, artifact_service=artifacts_service, session_service=session_service, ) queries = [ "Find hotels in Basel with Basel in its name.", "Can you book the Hilton Basel for me?", "Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.", "My check in dates would be from April 10, 2024 to April 19, 2024.", ] for query in queries: content = types.Content(role='user', parts=[types.Part(text=query)]) events = runner.run(session_id=session.id, user_id='123', new_message=content) responses = ( part.text for event in events for part in event.content.parts if part.text is not None ) for text in responses: print(text) asyncio.run(main()) ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydbgetuser/alloydbgetuser_test.go: -------------------------------------------------------------------------------- ```go // 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. package alloydbgetuser_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" alloydbgetuser "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbgetuser" ) func TestParseFromYaml(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: get-my-user: kind: alloydb-get-user source: my-alloydb-admin-source description: some description `, want: server.ToolConfigs{ "get-my-user": alloydbgetuser.Config{ Name: "get-my-user", Kind: "alloydb-get-user", Source: "my-alloydb-admin-source", Description: "some description", AuthRequired: []string{}, }, }, }, { desc: "with auth required", in: ` tools: get-my-user-auth: kind: alloydb-get-user source: my-alloydb-admin-source description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "get-my-user-auth": alloydbgetuser.Config{ Name: "get-my-user-auth", Kind: "alloydb-get-user", Source: "my-alloydb-admin-source", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /docs/en/resources/sources/http.md: -------------------------------------------------------------------------------- ```markdown --- title: "HTTP" linkTitle: "HTTP" type: docs weight: 1 description: > The HTTP source enables the Toolbox to retrieve data from a remote server using HTTP requests. --- ## About The HTTP Source allows Toolbox to retrieve data from arbitrary HTTP endpoints. This enables Generative AI applications to access data from web APIs and other HTTP-accessible resources. ## Available Tools - [`http`](../tools/http/http.md) Make HTTP requests to REST APIs or other web services. ## Example ```yaml sources: my-http-source: kind: http baseUrl: https://api.example.com/data timeout: 10s # default to 30s headers: Authorization: Bearer ${API_KEY} Content-Type: application/json queryParams: param1: value1 param2: value2 # disableSslVerification: false ``` {{< notice tip >}} Use environment variable replacement with the format ${ENV_NAME} instead of hardcoding your secrets into the configuration file. {{< /notice >}} ## Reference | **field** | **type** | **required** | **description** | |------------------------|:-----------------:|:------------:|------------------------------------------------------------------------------------------------------------------------------------| | kind | string | true | Must be "http". | | baseUrl | string | true | The base URL for the HTTP requests (e.g., `https://api.example.com`). | | timeout | string | false | The timeout for HTTP requests (e.g., "5s", "1m", refer to [ParseDuration][parse-duration-doc] for more examples). Defaults to 30s. | | headers | map[string]string | false | Default headers to include in the HTTP requests. | | queryParams | map[string]string | false | Default query parameters to include in the HTTP requests. | | disableSslVerification | bool | false | Disable SSL certificate verification. This should only be used for local development. Defaults to `false`. | [parse-duration-doc]: https://pkg.go.dev/time#ParseDuration ``` -------------------------------------------------------------------------------- /.github/workflows/deploy_dev_docs.yaml: -------------------------------------------------------------------------------- ```yaml # 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. name: "Deploy In-development docs" permissions: contents: write on: push: branches: - main paths: - 'docs/**' - 'github/workflows/docs**' - '.hugo/**' # Allow triggering manually. workflow_dispatch: jobs: deploy: runs-on: ubuntu-24.04 defaults: run: working-directory: .hugo # This shared concurrency group ensures only one docs deployment runs at a time. concurrency: group: docs-deployment cancel-in-progress: false steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod - name: Setup Hugo uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3 with: hugo-version: "0.145.0" extended: true - name: Setup Node uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: "22" - name: Cache dependencies uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} restore-keys: | ${{ runner.os }}-node- - run: npm ci - run: hugo --minify env: HUGO_BASEURL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/dev HUGO_RELATIVEURLS: false - name: Create Staging Directory run: | mkdir staging mv public staging/dev mv staging/dev/releases.releases staging/releases.releases - name: Deploy uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./.hugo/staging publish_branch: versioned-gh-pages keep_files: true commit_message: "deploy: ${{ github.event.head_commit.message }}" ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/dataplex/dataplex-search-entries.md: -------------------------------------------------------------------------------- ```markdown --- title: "dataplex-search-entries" type: docs weight: 1 description: > A "dataplex-search-entries" tool allows to search for entries based on the provided query. aliases: - /resources/tools/dataplex-search-entries --- ## About A `dataplex-search-entries` tool returns all entries in Dataplex Catalog (e.g. tables, views, models) that matches given user query. It's compatible with the following sources: - [dataplex](../../sources/dataplex.md) `dataplex-search-entries` takes a required `query` parameter based on which entries are filtered and returned to the user. It also optionally accepts following parameters: - `pageSize` - Number of results in the search page. Defaults to `5`. - `orderBy` - Specifies the ordering of results. Supported values are: relevance (default), last_modified_timestamp, last_modified_timestamp asc. ## Requirements ### IAM Permissions Dataplex uses [Identity and Access Management (IAM)][iam-overview] to control user and group access to Dataplex resources. Toolbox will use your [Application Default Credentials (ADC)][adc] to authorize and authenticate when interacting with [Dataplex][dataplex-docs]. In addition to [setting the ADC for your server][set-adc], you need to ensure the IAM identity has been given the correct IAM permissions for the tasks you intend to perform. See [Dataplex Universal Catalog IAM permissions][iam-permissions] and [Dataplex Universal Catalog IAM roles][iam-roles] for more information on applying IAM permissions and roles to an identity. [iam-overview]: https://cloud.google.com/dataplex/docs/iam-and-access-control [adc]: https://cloud.google.com/docs/authentication#adc [set-adc]: https://cloud.google.com/docs/authentication/provide-credentials-adc [iam-permissions]: https://cloud.google.com/dataplex/docs/iam-permissions [iam-roles]: https://cloud.google.com/dataplex/docs/iam-roles [dataplex-docs]: https://cloud.google.com/dataplex ## Example ```yaml tools: dataplex-search-entries: kind: dataplex-search-entries source: my-dataplex-source description: Use this tool to get all the entries based on the provided query. ``` ## Reference | **field** | **type** | **required** | **description** | |-------------|:--------:|:------------:|----------------------------------------------------| | kind | string | true | Must be "dataplex-search-entries". | | source | string | true | Name of the source the tool should execute on. | | description | string | true | Description of the tool that is passed to the LLM. | ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydblistusers/alloydblistusers_test.go: -------------------------------------------------------------------------------- ```go // 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. package alloydblistusers_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" alloydblistusers "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydblistusers" ) func TestParseFromYaml(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: list-my-users: kind: alloydb-list-users source: my-alloydb-admin-source description: some description `, want: server.ToolConfigs{ "list-my-users": alloydblistusers.Config{ Name: "list-my-users", Kind: "alloydb-list-users", Source: "my-alloydb-admin-source", Description: "some description", AuthRequired: []string{}, }, }, }, { desc: "with auth required", in: ` tools: list-my-users-auth: kind: alloydb-list-users source: my-alloydb-admin-source description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "list-my-users-auth": alloydblistusers.Config{ Name: "list-my-users-auth", Kind: "alloydb-list-users", Source: "my-alloydb-admin-source", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydbgetcluster/alloydbgetcluster_test.go: -------------------------------------------------------------------------------- ```go // 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. package alloydbgetcluster_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" alloydbgetcluster "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbgetcluster" ) func TestParseFromYaml(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: get-my-cluster: kind: alloydb-get-cluster source: my-alloydb-admin-source description: some description `, want: server.ToolConfigs{ "get-my-cluster": alloydbgetcluster.Config{ Name: "get-my-cluster", Kind: "alloydb-get-cluster", Source: "my-alloydb-admin-source", Description: "some description", AuthRequired: []string{}, }, }, }, { desc: "with auth required", in: ` tools: get-my-cluster-auth: kind: alloydb-get-cluster source: my-alloydb-admin-source description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "get-my-cluster-auth": alloydbgetcluster.Config{ Name: "get-my-cluster-auth", Kind: "alloydb-get-cluster", Source: "my-alloydb-admin-source", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /internal/tools/neo4j/neo4jexecutecypher/neo4jexecutecypher_test.go: -------------------------------------------------------------------------------- ```go // 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. package neo4jexecutecypher import ( "testing" "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" ) func TestParseFromYamlNeo4j(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: neo4j-execute-cypher source: my-neo4j-instance description: some tool description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "example_tool": Config{ Name: "example_tool", Kind: "neo4j-execute-cypher", Source: "my-neo4j-instance", Description: "some tool description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, { desc: "readonly example", in: ` tools: example_tool: kind: neo4j-execute-cypher source: my-neo4j-instance description: some tool description readOnly: true authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "example_tool": Config{ Name: "example_tool", Kind: "neo4j-execute-cypher", Source: "my-neo4j-instance", ReadOnly: true, Description: "some tool description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err = yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- ```yaml # Copyright 2024 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. name: lint on: pull_request: pull_request_target: types: [labeled] # Declare default permissions as read only. permissions: read-all jobs: lint: if: "${{ github.event.action != 'labeled' || github.event.label.name == 'tests: run' }}" name: lint runs-on: ubuntu-latest concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: contents: 'read' issues: 'write' pull-requests: 'write' steps: - name: Remove PR Label if: "${{ github.event.action == 'labeled' && github.event.label.name == 'tests: run' }}" uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | try { await github.rest.issues.removeLabel({ name: 'tests: run', owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number }); } catch (e) { console.log('Failed to remove label. Another job may have already removed it!'); } - name: Setup Go uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 with: go-version: "1.25" - name: Checkout code uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: ref: ${{ github.event.pull_request.head.sha }} repository: ${{ github.event.pull_request.head.repo.full_name }} token: ${{ secrets.GITHUB_TOKEN }} - name: > Verify go mod tidy. If you're reading this and the check has failed, run `goimports -w . && go mod tidy && golangci-lint run` run: | go mod tidy && git diff --exit-code - name: golangci-lint uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 with: version: latest args: --timeout 3m ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydbgetinstance/alloydbgetinstance_test.go: -------------------------------------------------------------------------------- ```go // 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. package alloydbgetinstance_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" alloydbgetinstance "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbgetinstance" ) func TestParseFromYaml(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: get-my-instance: kind: alloydb-get-instance source: my-alloydb-admin-source description: some description `, want: server.ToolConfigs{ "get-my-instance": alloydbgetinstance.Config{ Name: "get-my-instance", Kind: "alloydb-get-instance", Source: "my-alloydb-admin-source", Description: "some description", AuthRequired: []string{}, }, }, }, { desc: "with auth required", in: ` tools: get-my-instance-auth: kind: alloydb-get-instance source: my-alloydb-admin-source description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "get-my-instance-auth": alloydbgetinstance.Config{ Name: "get-my-instance-auth", Kind: "alloydb-get-instance", Source: "my-alloydb-admin-source", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /internal/tools/postgres/postgreslistactivequeries/postgreslistactivequeries_test.go: -------------------------------------------------------------------------------- ```go // 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. package postgreslistactivequeries_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgreslistactivequeries" ) func TestParseFromYamlPostgresListTables(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: example_tool: kind: postgres-list-active-queries source: my-postgres-instance description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "example_tool": postgreslistactivequeries.Config{ Name: "example_tool", Kind: "postgres-list-active-queries", Source: "my-postgres-instance", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, { desc: "basic example", in: ` tools: example_tool: kind: postgres-list-active-queries source: my-postgres-instance description: some description `, want: server.ToolConfigs{ "example_tool": postgreslistactivequeries.Config{ Name: "example_tool", Kind: "postgres-list-active-queries", Source: "my-postgres-instance", Description: "some description", AuthRequired: []string{}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/looker/looker-health-analyze.md: -------------------------------------------------------------------------------- ```markdown --- title: "looker-health-analyze" type: docs weight: 1 description: > "looker-health-analyze" provides a set of analytical commands for a Looker instance, allowing users to analyze projects, models, and explores. aliases: - /resources/tools/looker-health-analyze --- ## About The `looker-health-analyze` tool performs various analysis tasks on a Looker instance. The `action` parameter selects the type of analysis to perform: - `projects`: Analyzes all projects or a specified project, reporting on the number of models and view files, as well as Git connection and validation status. - `models`: Analyzes all models or a specified model, providing a count of explores, unused explores, and total query counts. - `explores`: Analyzes all explores or a specified explore, reporting on the number of joins, unused joins, fields, unused fields, and query counts. Being classified as **Unused** is determined by whether a field has been used as a field or filter within the past 90 days in production. ## Parameters | **field** | **type** | **required** | **description** | | :--- | :--- | :--- | :--- | | kind | string | true | Must be "looker-health-analyze" | | source | string | true | Looker source name | | action | string | true | The analysis to perform: `projects`, `models`, or `explores`. | | project | string | false | The name of the Looker project to analyze. | | model | string | false | The name of the Looker model to analyze. Required for `explores` actions. | | explore | string | false | The name of the Looker explore to analyze. Required for the `explores` action. | | timeframe | int | false | The timeframe in days to analyze. Defaults to 90. | | min_queries | int | false | The minimum number of queries for a model or explore to be considered used. Defaults to 1. | ## Example Analyze all models in `thelook` project. ```yaml tools: analyze-tool: kind: looker-health-analyze source: looker-source description: | Analyzes Looker projects, models, and explores. Specify the `action` parameter to select the type of analysis. parameters: action: models project: "thelook" Analyze all the explores in the `ecomm` model of `thelook` project. Specifically look at usage within the past 20 days. Usage minimum should be at least 10 queries. ```yaml tools: analyze-tool: kind: looker-health-analyze source: looker-source description: | Analyzes Looker projects, models, and explores. Specify the `action` parameter to select the type of analysis. parameters: action: explores project: "thelook" model: "ecomm" timeframe: 20 min_queries: 10 ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydblistclusters/alloydblistclusters_test.go: -------------------------------------------------------------------------------- ```go // 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. package alloydblistclusters_test import ( "testing" yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" alloydblistclusters "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydblistclusters" ) func TestParseFromYaml(t *testing.T) { ctx, err := testutils.ContextWithNewLogger() if err != nil { t.Fatalf("unexpected error: %s", err) } tcs := []struct { desc string in string want server.ToolConfigs }{ { desc: "basic example", in: ` tools: list-my-clusters: kind: alloydb-list-clusters source: my-alloydb-admin-source description: some description `, want: server.ToolConfigs{ "list-my-clusters": alloydblistclusters.Config{ Name: "list-my-clusters", Kind: "alloydb-list-clusters", Source: "my-alloydb-admin-source", Description: "some description", AuthRequired: []string{}, }, }, }, { desc: "with auth required", in: ` tools: list-my-clusters-auth: kind: alloydb-list-clusters source: my-alloydb-admin-source description: some description authRequired: - my-google-auth-service - other-auth-service `, want: server.ToolConfigs{ "list-my-clusters-auth": alloydblistclusters.Config{ Name: "list-my-clusters-auth", Kind: "alloydb-list-clusters", Source: "my-alloydb-admin-source", Description: "some description", AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, }, }, }, } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { got := struct { Tools server.ToolConfigs `yaml:"tools"` }{} // Parse contents err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } if diff := cmp.Diff(tc.want, got.Tools); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) } } ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/dataplex/dataplex-search-aspect-types.md: -------------------------------------------------------------------------------- ```markdown --- title: "dataplex-search-aspect-types" type: docs weight: 1 description: > A "dataplex-search-aspect-types" tool allows to to find aspect types relevant to the query. aliases: - /resources/tools/dataplex-search-aspect-types --- ## About A `dataplex-search-aspect-types` tool allows to fetch the metadata template of aspect types based on search query. It's compatible with the following sources: - [dataplex](../../sources/dataplex.md) `dataplex-search-aspect-types` accepts following parameters optionally: - `query` - Narrows down the search of aspect types to value of this parameter. If not provided, it fetches all aspect types available to the user. - `pageSize` - Number of returned aspect types in the search page. Defaults to `5`. - `orderBy` - Specifies the ordering of results. Supported values are: relevance (default), last_modified_timestamp, last_modified_timestamp asc. ## Requirements ### IAM Permissions Dataplex uses [Identity and Access Management (IAM)][iam-overview] to control user and group access to Dataplex resources. Toolbox will use your [Application Default Credentials (ADC)][adc] to authorize and authenticate when interacting with [Dataplex][dataplex-docs]. In addition to [setting the ADC for your server][set-adc], you need to ensure the IAM identity has been given the correct IAM permissions for the tasks you intend to perform. See [Dataplex Universal Catalog IAM permissions][iam-permissions] and [Dataplex Universal Catalog IAM roles][iam-roles] for more information on applying IAM permissions and roles to an identity. [iam-overview]: https://cloud.google.com/dataplex/docs/iam-and-access-control [adc]: https://cloud.google.com/docs/authentication#adc [set-adc]: https://cloud.google.com/docs/authentication/provide-credentials-adc [iam-permissions]: https://cloud.google.com/dataplex/docs/iam-permissions [iam-roles]: https://cloud.google.com/dataplex/docs/iam-roles [dataplex-docs]: https://cloud.google.com/dataplex ## Example ```yaml tools: dataplex-search-aspect-types: kind: dataplex-search-aspect-types source: my-dataplex-source description: Use this tool to find aspect types relevant to the query. ``` ## Reference | **field** | **type** | **required** | **description** | |-------------|:--------:|:------------:|----------------------------------------------------| | kind | string | true | Must be "dataplex-search-aspect-types". | | source | string | true | Name of the source the tool should execute on. | | description | string | true | Description of the tool that is passed to the LLM. | ```